BZLIB/DATE & BZLIB/DATE-TZ are now available on planet. They provide additional date manipulation capability on top of SRFI/19, including
timezone manipulation.
They are released under LGPL.
Usage and Installation
(require (planet bzlib/date))
(require (planet bzlib/date-tz))
bzlib/date
provides date manipulations.
bzlib/date
provides timezone manipulations. Their usages are separately discussed below.
bzlib/date
To create a date object, you can use
bulid-date
, which provides a more natural year/month/day/hour/minute/second order of the parameters:
(build-date <year> <month> <day> <hour> <minute> <second> #:tz <offset>)
And it would do the right thing if you enter February 31st:
(build-date 2009 2 31) ;; => #(struct:tm:date 0 0 0 0 3 3 2009 0)
By default, the tz offset is 0, which equates to GMT (see below for timezone support). Only
year
,
month
, and
day
are required.
Date Comparisons
The following function compares two dates to determine their orders:
(date>? <d1> <g2>)
(date<? <d1> <g2>)
(date>=? <d1> <g2>)
(date<=? <d1> <g2>)
(day=? <d1> <g2>)
(date!=? <d1> <g2>)
(date===? <d1> <g2>)
day=?
only compares the year/month/day values, and
date===?
means they are the same date with the same tz offset.
Conversions
You can convert between date and seconds with
(date->seconds <date>)
and
(seconds->date <seconds>)
.
You can add to a date with
(date+ <date> <number-of-days>)
. The number of day can be a non-integer.
You can find out the gaps between two dates with
(date- <date1> <date2>)
.
You can create an alarm event with date via
(date->alarm <date>)
or
(date->future-alarm <date>)
. The difference between the two is that
date->future-alarm
will return false if the date is in the past.
Dealing with Weekdays
To find out the weekday of a particular date, you can use
(week-day <date>)
.
To find out the date of the nth-weekday (e.g., first sunday, 3rd wednesday, last Friday) of a particular month, use
nth-week-day
:
(nth-week-day <year> <month> <week-day> <nth> <hour> <minute> <second> #:tz <offset>)
For the
week-day
argument, use 0 for Sunday, and 6 for Saturday. For the
nth
argument, use 1, 2, 3, 4, 5, or
'last
.
hour
,
minute
,
second
, and
offset
are optional (same as build-date, and the other functions below that have them).
To find out the date of a particular weekday relative to another date, use one of the following:
week-day>=mday
week-day<=mday
week-day>mday
week-day<mday
They all share the same arguments, which are
year
,
month, week-day
, month-day
, hour
, minute
, second
, and offset
.
The usage is something like:
;; the sunday after May 15th, 2009
(week-day>mday 2009 5 0 15) ;; 5/17/2009
;; the friday before September 22nd, 2008
(week-day<mday 2009 9 5 22) ;; 9/19/2009
The hour
, minute
, second
, and offset
parameters are there for you to customize the return values:
;; the sunday after May 15th, 2009
(week-day>mday 2009 5 0 15 15 0 0 #:tz -28800) ;; 5/17/2009 15:00:00-28800
;; the friday before September 22nd, 2008
(week-day<mday 2009 9 5 22 8 30 25 #:tz 14400) ;; 9/19/2009 08:00:00+14400
bzlib/date-tz
By default, you need to parameterize the current-tz
parameter, which defaults to America/Los_Angeles
. The timezone names are the available names from the olson database.
To determine the offset of any date for a particular timezone, use tz-offset
:
(parameterize ((current-tz "America/New_York"))
(tz-offset (build-date 2008 3 9))) ;; => -18800
(parameterize ((current-tz "America/New_York"))
(tz-offset (build-date 2008 3 10))) ;; => -14400
If you want to separate between the standard offset and the daylight saving offset, you can use tz-standard-offset
or tz-daylight-saving-offset
:
(let ((d1 (build-date 2008 3 9))
(d2 (build-date 2008 3 10)))
(parameterize ((current-tz "America/New_York"))
(values (tz-standard-offset d1)
(tz-daylight-saving-offset d1)
(tz-daylight-saving-offset d2))))
;; => -18800 (std)
;; => 0 (dst on 3/9/2008)
;; => 3600 (dst on 3/10/2008)
Conversion
To reset a date's tz offset, you can use the helper function date->tz
, which will reset the offset for you:
(let ((date (build-date 2008 3 10 #:tz -18800)))
(parameterize ((current-tz "America/New_York"))
(date->tz date)))
;; => #(struct:tm:date 0 0 0 0 10 3 2008 -14400)
This function is meant for you to fix the offsets for dates that belong to a particular timezone but did not correctly account for the offset - it does not switch the timezone for you.
Couple other functions makes it even easier to work with timezone.
(build-date/tz <year> <month> ...)
(date+/tz <date> <number-of-days>)
They basically creates the date object and calls date->tz
so the offset is properly adjusted based on the timezone.
Besides using current-tz
, you can also pass it explicitly to tz-offset
, tz-standard-offset
, tz-daylight-saving-offset
, date->tz
, build-date/tz
, and date+/tz
. You pass it in in the following forms:
(tz-offset <date> "America/Los_Angeles")
(tz-daylight-saving-offset <date> "Asia/Kolkata")
(tz-standard-offset <date> "Europe/London")
(date->tz <date> "Europe/London")
(build-date/tz <year> <month> <day> #:tz "America/New_York")
(date+/tz <date> <number-of-days> "America/Los_Angeles")
Convert from One Timezone to Another
To covert the timezone of a date so you get the same date in a different timezone, use tz-convert
:
(tz-convert <date> >from-timezone> <to-timezone>)
All parameters are required.
(tz-convert (build-date 2008 3 10 15) "America/New_York" "America/Los_Angeles")
;; => #(struct:tm:date 0 0 0 12 10 3 2008 -25200) ;; 2008/3/10 12:00:00-25200
(tz-convert (build-date 2008 3 10 15) "America/New_York" "GMT")
;; ==> #(struct:tm:date 0 0 0 19 10 3 2008 0) ;; 2008/10/10 19:00:00+00:00
That's it for now - enjoy.