Skip to content

Latest commit

 

History

History
289 lines (221 loc) · 7.75 KB

File metadata and controls

289 lines (221 loc) · 7.75 KB

Dateutil

Dateutil

https://dateutil.readthedocs.io/en/stable/

The dateutil module provides powerful extensions to the standard datetime module, available in Python.

Features

  • Computing of relative deltas (next month, next year, next monday, last week of month, etc);
  • Computing of relative deltas between two given date and/or datetime objects;
  • Computing of dates based on very flexible recurrence rules, using a superset of the iCalendar specification. Parsing of RFC strings is supported as well.
  • Generic parsing of dates in almost any string format;
  • Timezone (tzinfo) implementations for tzfile(5) format files (/etc/localtime, /usr/share/zoneinfo, etc), TZ environment string (in all known formats), iCalendar format files, given ranges (with help from relative deltas), local machine timezone, fixed offset timezone, UTC timezone, and Windows registry-based time zones.
  • Internal up-to-date world timezone information based on Olson?s database.
  • Computing of Easter Sunday dates for any given year, using Western, Orthodox or Julian algorithms.

CL alternatives

Python to CL examples

https://dateutil.readthedocs.io/en/stable/examples.html

Similary to Python let’s start with importing required libraries:

Store some values:

;; use this moment for demo
(defparameter *now* (now))
(defparameter *today* (today))
;; fix chronicity now for demo
(setf chronicity:*now* *now*)

(list *now* *today*)

Date and time manipulation

Next month

(timestamp+ *now* 1 :month)
;; or
(adjust-timestamp *now* (offset :month 1))

Next month, plus one week

(adjust-timestamp *now* (offset :month 1) (offset :day 7))

Next month, plus one week, at 10am.

(adjust-timestamp *now* (offset :month 1) (offset :day 7) (set :hour 10))

Setting specific time fields similar to absolute relativedelta:

(adjust-timestamp *now* (set :year 1) (set :month 1))

Get the relative delta

(ltd:timestamp-difference (encode-timestamp 0 0 0 0 1 1 2018) *now*)

One month before one year and other offsets.

(adjust-timestamp *now* (offset :year 1) (offset :month -1))

How does it handle months with different numbers of days? Notice that adding one month will never cross the month boundary.

(adjust-timestamp (encode-timestamp 0 0 0 0 27 1 2003) (offset :month 1))
(adjust-timestamp (encode-timestamp 0 0 0 0 31 1 2003) (offset :month 1))
(adjust-timestamp (encode-timestamp 0 0 0 0 31 1 2003) (offset :month 2))

The logic for years is the same, even on leap years.

(adjust-timestamp (encode-timestamp 0 0 0 0 28 2 2000) (offset :year 1))
(adjust-timestamp (encode-timestamp 0 0 0 0 29 2 2000) (offset :year 1))
(adjust-timestamp (encode-timestamp 0 0 0 0 28 2 1999) (offset :year 1))
(adjust-timestamp (encode-timestamp 0 0 0 0 1 3 1999) (offset :year 1))
(adjust-timestamp (encode-timestamp 0 0 0 0 28 2 2001) (offset :year -1))
(adjust-timestamp (encode-timestamp 0 0 0 0 1 3 2001) (offset :year -1))

Next Friday

(adjust-timestamp *today* (offset :day-of-week :friday))

Last Friday of the month

(defun set-day-of-week (time day-of-week)
  "Adjust the timestamp to be the specifed day of the week, selects corresponding preceeding date if timestamp's day of the week do not match the requirement."
  (let ((adjusted (adjust-timestamp time (offset :day-of-week day-of-week))))
    (if (timestamp>= time adjusted)
        adjusted
        (adjust-timestamp adjusted (offset :day -7)))))

(set-day-of-week (timestamp-maximize-part *today* :day) :friday)

Next Wednesday (it’s today!)

(defun next-day-of-week (time day-of-week)
  "Adjust the timestamp to be the next specifed day of the week, selects corresponding future date if timestamp's day of the week do not match the requirement."
  (let ((adjusted (adjust-timestamp time (offset :day-of-week day-of-week))))
    (if (timestamp>= adjusted time)
        adjusted
        (adjust-timestamp adjusted (offset :day 7)))))

(let ((*today* (encode-timestamp 0 0 0 0 3 1 2018)))
  (next-day-of-week *today* :wednesday))

Next wednesday, but not today.

(let ((*today* (encode-timestamp 0 0 0 0 3 1 2018)))
  (next-day-of-week (adjust-timestamp *today* (offset :day 1)) :wednesday))

Following ISO year week number notation find the first day of the 15th week of 1997.

(set-day-of-week
 (adjust-timestamp
     (next-day-of-week
      (encode-timestamp 0 0 0 0 1 1 1997)
      :thursday)
   (offset :day (* 7 14)))
 :monday)

How long ago has the millennium changed?

(ltd:timestamp-difference *now* (encode-timestamp 0 0 0 0 1 1 2001))

It works with dates too.

(ltd:timestamp-difference *today* (encode-timestamp 0 0 0 0 1 1 2001))

Obtain a date using the yearday:

(adjust-timestamp (timestamp-minimize-part *now* :day) (offset :day 260))

Leap year vs non-leap year:

(let ((leap (encode-timestamp 0 0 0 0 1 1 2000))
      (non-leap (encode-timestamp 0 0 0 0 1 1 2002)))

  (list (adjust-timestamp (timestamp-minimize-part leap :day) (offset :day 260))
        (adjust-timestamp (timestamp-minimize-part non-leap :day) (offset :day 260))))

Date parsing

Simple examples

(parse-timestring "Thu Sep 25 10:36:28 2003")