ciel-lang / CIEL

CIEL Is an Extended Lisp. Scripting with batteries included.
http://ciel-lang.org
350 stars 18 forks source link

Evaluating: the periods library #37

Open vindarel opened 1 year ago

vindarel commented 1 year ago

bo-tato:

The periods library you might want to consider inclusion in CIEL, it has convenient macros like do-times there for looping over a range of dates. I've written a couple standalone ciel scripts with it. Like this for catching up on reading the #commonlisp irc channel.

periods might bring some more high-level functions and macros, complementing local-time.

goal: bring the good in a common package, for instance import & reexport symbols into a new ciel/time package.


do-times

not exported

Signature
((var start duration end &optional (result)) &body body)

A 'do' style version of the functional MAP-TIMES macro.

The disadvantage to DO-TIMES is that there is no way to ask for a reversed
time sequence, or specify an inclusive endpoint.

example:

do-times (day (-> +last-date-file+ str:from-file str:trim parse-timestring)
              (duration :days 1)
              (today))
  …)

also do-time-period (un-exported), do-over-time (exported but doesn't exist?), map-over-time (doesn't exist ?)

subtract-time, add-time

equivalent to local-time:timestamp- ?

(periods:subtract-time (local-time:now) (periods:duration :days 2))

==

(local-time:timestamp- (local-time:now) 2 :day)

not exported: add-[hours, days, years, months, minutes, seconds, microseconds, milliseconds]

(periods::add-hours (periods:duration :days 1) 3)
#S(PERIODS:DURATION
   :YEARS 0
   :MONTHS 0
   :DAYS 1
   :HOURS 3
   :MINUTES 0
   :SECONDS 0
   :MILLISECONDS 0
   :MICROSECONDS 0
   :NANOSECONDS 0)

duration

(periods:duration :days 3)
#S(PERIODS:DURATION
   :YEARS 0
   :MONTHS 0
   :DAYS 3
   :HOURS 0
   :MINUTES 0
   :SECONDS 0
   :MILLISECONDS 0
   :MICROSECONDS 0
   :NANOSECONDS 0)

time-range

(periods:time-range :begin (local-time:now) :end (local-time:now))
#S(PERIODS:TIME-RANGE
   :FIXED-BEGIN NIL
   :BEGIN @2023-11-09T14:21:56.804175+01:00
   :BEGIN-INCLUSIVE-P T
   :FIXED-END NIL
   :END @2023-11-09T14:21:56.804177+01:00
   :END-INCLUSIVE-P NIL
   :DURATION NIL
   :ANCHOR NIL)

fixed-time

Signature
(&rest args)

Return a fixed point in time relative to the time of the call.  ARGS is a
property list giving a specific precision for the return value.

  If the keyword argument :NOW is given, all else is ignored; this is
equivalent to calling LOCAL-TIME:NOW.

  Otherwise, any keyword arguments given override their corresponding elements
in the current time.  Further, any elements smaller in resolution than the
finest specified element are reduced to 0 or 1, according to their position.

  For example, assuming the current time is "@2007-11-17T23:02:00.000",
compare these outputs:

  (fixed-time :month 4) => @2007-04-01T00:00:00.000
  (fixed-time :day 10)  => @2007-11-10T00:00:00.000
  (fixed-time :hour 15) => @2007-11-17T15:00:00.000

This behavior makes it very easy to return a fixed time for "april of this
year", etc.  If you wish to determine the date of the previous April, while
preserving the current day of the month, hour of the day, etc., then see the
function PREVIOUS-TIME.

parse-time-range, parse-time-period

Parse a human-readable string and give a time-range, or parse a date with a time-range of 1 day.

(periods:parse-time-range "2 months")

#S(PERIODS:TIME-RANGE
   :FIXED-BEGIN NIL
   :BEGIN @2023-11-09T00:00:00.000000+01:00
   :BEGIN-INCLUSIVE-P T
   :FIXED-END NIL
   :END NIL
   :END-INCLUSIVE-P NIL
   :DURATION #S(PERIODS:DURATION
                :YEARS 0
                :MONTHS 2
                :DAYS 0
                :HOURS 0
                :MINUTES 0
                :SECONDS 0
                :MILLISECONDS 0
                :MICROSECONDS 0
                :NANOSECONDS 0)
   :ANCHOR NIL)

Possible strings:

(defun time-parser-tests ()
  (dolist
      (expr '("this year"
          "next year"
          "last year"
          "the year before last"
          "jan 8"
          "jan 2008"
          "2008/01/01"
          "2 months"
          "2 months since jan 8"
          "january of last year"
          "three months ago"
          "1 months, 2 days ago"
          "every friday starting tomorrow"
          "every day this week"
          "every day of this week"
          "every ten days"
          "the day after tuesday"
          "monthly"
          "monthly from the beginning of this year"
          "monthly from now until the end of the year"
          "the last week of last year"
          ;; "every weekend this year"
          ))
    (format t "EXPR <  ~A~%     >= ~S~%" expr
        (p/time (make-string-input-stream expr)))))
(periods:parse-time-range "every day this week")
@2023-11-09T00:00:00.000000+01:00
;; no time-range structure?

Convenience functions

current-year

leapp

local-time has it in a flet, my PR to bring it to an accessible function got rejected: https://github.com/dlowe-net/local-time/pull/106 (add weaks-in-year, leap-year-p, tomorrow, yesterday)

falls-on-weekend-p

sleep-until


it doesn't have tests? (I know it's CL, but still)

vindarel commented 1 year ago

Added the current periods doc online, with syntax highlighting: https://lisp-maintainers.github.io/periods/

It should be extended now (and probably by using a real documentation builder).

While working on the doc, ciel -s simplehttpserver was helpful ;)