Simple but powerful and flexible date and time routines, with timezone and daylight savings handling, which the following example illustrates:
include builtins\timedate.e

timedate td

    set_timedate_formats({"Mmmm dth yyyy h:mmam tz",
                          "Mmmm dth yyyy h:mmam"})
    --td = parse_date_string("August 3rd 2015 10:05am BST")
    td = parse_date_string("August 3rd 2015 10:05am")
    td = set_timezone(td,"BST")
    td = adjust_timedate(td,timedelta(days:=5))
    td = change_timezone(td,"EDT")                              ?format_timedate(td)
                                                                &format_timedate(td," (tzz)")
    td = change_timezone(td,"BST")                              ?format_timedate(td)
    td = adjust_timedate(td,timedelta(days:=4*31-2))            ?format_timedate(td)
    td = adjust_timedate(td,timedelta(days:=8*31-4))            ?format_timedate(td)
    -- output is:
    --  "August 8th 2015 5:05am EDT (Eastern Daylight Time)"
    --  "August 8th 2015 10:05am BST"
    --  "December 8th 2015 9:05am GMT"
    --  "August 8th 2016 10:05am BST"
First we specify a couple of format strings for parsing/printing, which can also be specified on a line-by-line basis if you prefer. Using two formats allows it to handle strings with or without an explicit timezone, as the second (commented out) and third statements suggest.

Next, we set the timezone to BST on any timedates that do not have one, using the set_timezone() routine. In the case of "25/12/2015 10am", set_timezone(td,"BST") would (appear at first to) leave it as 10am GMT, because that daylight savings time is not active in December, however it would be left marked as a timedate that needs daylight savings handling on subsequent adjustment.

The set_timezone() routine only has any effect on un-timezoned timedates, never alters the time value, and as shown returns a timedate that when adjusted by 4 then 8 months (the -2 and -4 being ad-hoc tweaks to keep it the 8th) toggles properly in and out of daylight savings time. If we had used "GMT" instead of "BST" then it would, fairly obviously, stay GMT all year round.

Timezone and daylight savings handling is complete for Europe, North America, and Australia, however, now for the bad news, unfortunately there is no international standard that includes GMT/BST/etc, with globally-unique abbreviations1. The worst case is "IST", which can mean Irish/India/Iran/Israel. The override_timezone() routine can be used to change the meaning of "IST" dynamically, depending on where the string came from. Also, the source code (builtins\timedate.e) contains most timezone abbreviations and current rules for daylight savings worldwide, but currently commented out and awaiting someone with a smidgen of local knowledge to ratify them, using a snippet of code similar to the above.

Values from date() can also be passed to the timedate library, and the same DT_XXX constants can be used to examine the contents of a timedate value, if needed.

See Also: the timedate type, set_timedate_formats, format strings, parse_date_string, set_timezone, adjust_timedate, change_timezone, format_timedate, date, elapsed