The dateutil module provides powerful extensions to the standard datetime module, available in Python.
- 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.
- https://github.com/dlowe-net/local-time
- https://github.com/enaeher/local-time-duration
- https://github.com/chaitanyagupta/chronicity
- https://gist.github.com/perusio/6687883
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*)(timestamp+ *now* 1 :month)
;; or
(adjust-timestamp *now* (offset :month 1))(adjust-timestamp *now* (offset :month 1) (offset :day 7))(adjust-timestamp *now* (offset :month 1) (offset :day 7) (set :hour 10))(adjust-timestamp *now* (set :year 1) (set :month 1))(ltd:timestamp-difference (encode-timestamp 0 0 0 0 1 1 2018) *now*)(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))(adjust-timestamp *today* (offset :day-of-week :friday))(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)(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))(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)(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))(adjust-timestamp (timestamp-minimize-part *now* :day) (offset :day 260))(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))))(parse-timestring "Thu Sep 25 10:36:28 2003")