Date and Calendar Functionality

Nick Lariviere, Wolfram Research Inc.

Join the Conversation #WolframTechConf

Overview

Dates and Calendars Overview

Wolfram Language Date Framework

Date String Elements and Formats

Time Zones

Holiday Calendars

Calendar Types

Application Example: Custom Calendar

Future Features

Additional Resources

Dates and Calendars: General Concepts

Absolute Dates - Fixed points in Time

In most applications, dates represent a fixed, or absolute, point in time. There are some exceptions(recurring dates and time spans, which will be covered at the end of the presentation in more detail), but by-and-large when referring to a date we are talking about a single moment in time(ex: “2:30 on October 22nd, 2015”).

Time Units

Time units(as used in Quantity and other units frameworks) have fixed and fundamental unit values. This means that the length of a “Month” unit is constant, and has a fixed relationship with all other time units. Generally Time units are used as measures of duration, while calendar units are used as measures of both duration and absolute time.

Calendar Units

Calendar units on the other hand can have relative definitions, such as the variable length of months in most calendar systems. This means that the result of calendar arithmetic is often dependent on the specific dates being operated on.

Calendar Epochs and Year 0

There is no definitive “absolute 0” value for time(though one can argue that time began with the big bang, roughly 15 billion years ago), and all calendar systems are based on some specific “first date” or epoch. Because of this, most calendars have to have a system for handling both negative year values, and also year 0. There is no universal rule for whether a year 0 is included or excluded for all calendars.

Time Zones

Time zones represent a(most often geographic) region of uniform standard time.  Time zones are typically regulated and defined by nations, and can include observations of daylight saving time. The dates on which DST is observed typically change over time.

Time Systems

Also known as time standards, these are specifications that dictate both fixed points in time and the rate at which time flows.  These are the systems which handle leap seconds, and common conventions are International Atomic Time(TIA), Universal Time(UT, UT0, UT1), and mean solar time.

Wolfram Language Date Framework

Overview of the Wolfram Language Date Framework

Calendar Type: (proleptic) Gregorian

Calendar Epoch: January 1st, 1 ACE 00:00:00

Time System: 24 hour clock, leap-second free.

Year 0: No

The Wolfram Language date framework follows the general conventions of the ISO-8601 calendar, with the main exception being the lack of year 0(in the Wolfram Language {-1, 12, 31, 23, 59, 59} immediately precedes {1, 1, 1, 0, 0, 0}). Both are proleptic Gregorian calendars, meaning that they extend backward beyond the official adoption of the Gregorian calendar over the Julian in 1582(though the date on which different countries adopted the Gregorian calendar are often later than this date, the official Gregorian calendar is considered only valid from 1582 onward).

Date Representations

DateObject - A container that represents a given date including it’s calendar and time zone

DateObject[]

DateObject[{2015, 10, 18}, TimeObject[{15, 3, 43.0424}, TimeZone -> -4.], TimeZone -> -4.]

DateList - a 6-element list specifying year, month, day, hour, minute, and second

DateList[]

AbsoluteTime - a numeric value giving the number of seconds since midnight, January 1, 1900 in your local time zone

AbsoluteTime[]

DateString - a string containing different date string elements

DateString[]

JulianDate - a numeric value giving the number of days since noon GMT on November 24, 4714 BCE

JulianDate[]

UnixTime - a numeric value giving the number of seconds since midnight GMT on January 1, 1970

UnixTime[]

SiderealTime* - a mixed-radix quantity giving the right ascension of the local meridian for a given date and location

SiderealTime[]

Now, Today, Yesterday, Tomorrow - are all convenience symbols that return a DateObject corresponding to their name.

{Now,Today,Yesterday,Tomorrow}

Basic Date Operations

DatePlus - adds calendar units to a date

DatePlus[Today,{3,"Day"}]

DateDifference - gives the difference(in calendar units) between two dates

DateDifference[Yesterday,Tomorrow]

DateRange - generates a list of dates given a start and end date

DateRange[Yesterday,Tomorrow]

DateValue - extracts various properties from a date expression

DateValue[Now,"Hour"]

TimeZoneConvert - changes a date from one time zone to another

time=Now

TimeZoneConvert[time, "America/Denver"]

CalendarConvert - changes a date from one calendar to another

CalendarConvert[Today,"Julian"]

Date String Elements and Formats

DateString

DateString is the most frequently used method for formatting dates as strings in different formats, and includes a long list of available date string elements:

DateString also included a number of predefined date string formats, such as “Date”, “Time”, and “DateTimeShort”:

DateString["Date"]

DateString["Time"]

DateString["DateTimeShort"]

ISO-8601 provides guidelines for date formatting to avoid the ambiguity introduced by regional differences in date notation, which are also available as preset date string formats:

DateString["ISODate"]

DateString["ISODateTime"]

DateString also provides alternative date notation using week-date and ordinal date notation, following ISO-8601 standards:

DateString["ISOWeekDate"]

DateString["ISOOrdinalDate"]

DateValue

DateValue returns many of the same elements as DateString, but also allows you to specify the output type of the elements as well:

DateValue[Now,"Hour"]//InputForm

DateValue[Today,"Year",Quantity]

This can be useful when setting up utility functions to check various elements of a date, without having to call ToExpression or parse date string elements:

businessHoursQ[date_] := TrueQ[8≤DateValue[date,"Hour"]≤17]

businessHoursQ[Now]

businessHoursQ[{2015,1,1,0}]

DateFormat

DateFormat is an option for DateObject which dictates the manner in which the expression will typeset, and also the default form in which DateString will operate on it:

DateObject[]

DateObject[{2015,8,1},DateFormat->"ISOWeekDate"]

DateString[%]

The default format can still be overwritten by explicitly specifying a date string format:

DateString[%%, "DateTimeShort"]

Time Zones

TimeZone Basics

When the Wolfram System is initialized, one of the system variables that is set is $TimeZone, which gives the current offset, in hours, from GMT for your system:

$TimeZone

The option TimeZone can be used to specify an output time zone, instead of defaulting to $TimeZone:

Now

DateList[%,TimeZone->0]

The value for $TimeZone is used by all date functions in the Wolfram Language as the reference point against which time values are measured, and is almost always assumed to be the input timezone, which we can see by modifying the value:

date=DateList[{2015,1,1,1,1,1}]

DateList[date,TimeZone->-5]

Block[{$TimeZone=0},DateList[date,TimeZone->-5]]

Block[{$TimeZone=8},DateList[date,TimeZone->-5]]

DateObject and TimeObject are exceptions, where the TimeZone option value is assumed to be both the input, and output time zone:

DateObject[date,TimeZone->0]

Some functions, like UnixTime and JulianDate, do not have a TimeZone option, because their output values are, by definition, in GMT:

Options/@{UnixTime,JulianDate}

TimeZone Types

Up through version 10.2, time zones in the Wolfram Language have been exclusively numeric offsets from GMT.  As of version 10.3 however, time zones have been extended to include named time zones, as well as entity expressions.

DateObject[TimeZone->0]

DateObject[TimeZone->"America/Chicago"]

DateObject[TimeZone->LinguisticAssistant]

Time zone specifications can also be a location Entity, in which case the Wolfram System will look up the corresponding time zone entity and return the appropriate time:

DateObject[TimeZone->(Entity["Bangkok", Entity["City",{"Bangkok","Bangkok","Thailand"}], "Entity[\"City\", {\"Bangkok\", \"Bangkok\", \"Thailand\"}]", "city"])]

Time zone entities automatically adjust for daylight saving time where appropriate:

DateObject[{2015, 3, 8,1},TimeZone->"America/Chicago"]

DateObject[{2015, 3, 8,3},TimeZone->"America/Chicago"]

Time zone entities can be discovered using natural language input, and also LocalTimeZone:

LinguisticAssistant

LocalTimeZone[(Entity["Tokyo", Entity["City",{"Tokyo","Tokyo","Japan"}], "Entity[\"City\", {\"Tokyo\", \"Tokyo\", \"Japan\"}]", "city"])]

Your local time zone entity can also be found by evaluating the $TimeZoneEntity variable:

$TimeZoneEntity

Holiday Calendars

Basic Overview

Holiday calendars in the Wolfram Language are primarily utilized in the calendar day framework, which is a subset of the general calendar date framework. In the calendar day framework HolidayCalendar can be used to specify which country and exchange is used in determining “Holiday” day types:

DayRange[(DateObject["Thu 1 Jan 2015", DateObject[{2015,1,1}]]),(DateObject["Thu 31 Dec 2015", DateObject[{2015,12,31}]]), "Holiday"]

DayRange[(DateObject["Thu 1 Jan 2015", DateObject[{2015,1,1}]]),(DateObject["Thu 31 Dec 2015", DateObject[{2015,12,31}]]), "Holiday", HolidayCalendar->(Entity["China", Entity["Country","China"], "Entity[\"Country\", \"China\"]", "country"])]

DayRange[(DateObject["Thu 1 Jan 2015", DateObject[{2015,1,1}]]),(DateObject["Thu 31 Dec 2015", DateObject[{2015,12,31}]]), "Holiday", HolidayCalendar->{"UnitedStates","NYSE"}]

One can also specify a custom holiday calendar using pure functions:

DayRange[(DateObject["Thu 6 Jan 2000", DateObject[{2000,1,6}]]),(DateObject["Fri 6 Jul 2018", DateObject[{2018,7,6}]]),"Holiday", HolidayCalendar->{"Gregorian"->{{True&,#==5&,#==9&}}}]

Recent Updates

In version 10, we’ve expanded the number of exchange holiday calendars available, and extended support for HolidayCalendar to the Date* counterparts for the existing Day* functions:

CalendarData[]

CalendarData["Japan"]

Table[DatePlus[Now,{250, "BusinessDay"},HolidayCalendar->i], {i, {"China", "UnitedStates"}}]

Calendar Types

Calendar Overview

The Wolfram Language date framework uses a proleptic Gregorian calendar for it’s standard date notation, but it also includes support for additional calendar types within DateObject and other functions. The standard supported calendars are Gregorian, Julian, Jewish, and Islamic. Specifying an explicit CalendarType in DateObject will return a date in the appropriate calendar:

Column[DateObject[CalendarType->#]&/@{"Gregorian", "Jewish", "Islamic"}]

These calendar dates are also represented using date lists internally within DateObject, and format with their appropriate day and month names:

DateObject[Today,CalendarType->"Jewish"]

InputForm[%]

Note that there are at least 4 different standards for the Islamic calendar, the Umm al-Qura, the lunar Hijri, this Turkish Hijri, and the Solar Hejri, which are all currently in use in different countries, as well as some Tabular variants.  The Wolfram Language’s Islamic calendar is based on the lunar Hijri, which is the most commonly used variant word-wide.

Calendar Operations

CalendarConvert can be used to convert a DateObject expression from one calendar to another:

Column[CalendarConvert[(DateObject["Sun 4 Aug 1985", DateObject[{1985,8,4}]]),#]&/@{"Jewish","Islamic"}]

Other functions, such as DateRange, include support for CalendarType, which can be used with non-DateObject inputs as well:

DateRange[{2011}, {2012}, "Week", CalendarType->"Islamic"]

Application Example: Mayan Calendars

History

The Mayans used 3 different, but related, calendars to handle dates, which are commonly referred to as the long count, haab, and tzolkin calendars.  The exact relationship between these calendars and western calendar systems is still somewhat disputed, but most scholars use the Goodman-Martinez-Thompson correlation. We can use these calendars to illustrate the relationship between different calendar cycles and epochs for different calendar systems.

Calendar units

The Mayan “long count” calendar is composed of 5 different calendar units, the kin, uinal, tun, katun and baktun with the baktun being the highest-ordered unit amounting to 144,000 days. Their relationship is as follows:

$mayanCalendarUnits={
"kin"->"day",
"uinal"->20"kin",
"tun"->18"uinal",
"katun"->20"tun",
"baktun"->20"katun"
}

Note: the Mayans also had larger units for longer time periods, but they are generally not considered part of the standard calendar system.

Epoch

The epoch date used by the Goodman-Martinez-Thompson correlation is August 11th -3114 for the Gregorian calendar(September 6th, 3114 BCE Julian), which we can represent as a number using JulianDate.  Here I will use “Modified” JulianDate to simplify the conversion process by factoring out the offset for “Full” JulianDate values which are based on time relative to noon.

epoch=JulianDate["Modified",DateObject[{-3114,8,11},TimeZone->0]]

Conversion from long count to Julian date

Since the calendar units have a fixed relationship with one another, converting from a list of long count calendar units to a Julian date is simply a mater of arithmetic:

JulianFromMayanLongCount[{baktun_,katun_,tun_,uinal_,kin_}] := epoch+144000*baktun+7200*katun+360*tun+20*uinal+kin

example=JulianFromMayanLongCount[{7,17,18,19,2}]

Conversion to Gregorian calendar date

Since we already have a conversion to a Julian date, it’s trivial to get a Gregorian calendar date using FromJulianDate:

FromJulianDate["Modified",example,TimeZone->0]

Since for these sorts of calendar conversions we typically aren’t interested in the handling of units smaller than hours, we can extract just the Date part using DateValue:

GregorianFromMayanLongCount[date_]:=DateValue[
FromJulianDate["Modified",
JulianFromMayanLongCount[date],
TimeZone->0],
"Day",
DateObject]

GregorianFromMayanLongCount[{7,17,18,19,2}]

Conversion from JulianDate

Conversion from Mayan long count date lists can be done using basic arithmetic operations as well by first subtracting the epoch date, and then taking the quotient and remainder based on the number of days in each calendar unit:

JulianToMayanLongCount[date_]:=Module[{baktun,katun,tun,uinal,kin,longCount,dayOfBaktun,dayOfKatun,dayOfTun},
longCount=date-epoch;
{baktun,dayOfBaktun}=QuotientRemainder[longCount,144000];
{katun , dayOfKatun}=QuotientRemainder[dayOfBaktun,7200];
{tun,dayOfTun}=QuotientRemainder[dayOfKatun,360];
{uinal, kin}=QuotientRemainder[dayOfTun,20];
kin=Floor[kin];
{baktun,katun,tun,uinal,kin}
]

JulianToMayanLongCount[epoch]

date=JulianDate["Modified", DateObject[{2015,4,1},TimeZone->0]]

JulianToMayanLongCount[date]

Conversion from any date format

Having set up our utility function to convert from a Julian date to the Mayan long count date, we can add a wrapper function to handle conversion from any date format to Mayan long count:

DateToMayanLongCount[date_] := Block[{$TimeZone = 0}, 
JulianToMayanLongCount[JulianDate["Modified", date]]
]

This function will now accept any input date and will return the corresponding Mayan long count calendar date list:

DateToMayanLongCount["May 4th, 2015"]

DateToMayanLongCount[AbsoluteTime[]]

DateToMayanLongCount[Today]

And we can sanity-check this and the previous function to make sure that dates successfully round-trip:

DateToMayanLongCount[{1900,1,1}]

GregorianFromMayanLongCount[%]

Future Features

Time Systems

One of the main components for dates that is currently unavailable in the Wolfram Language date framework is time systems, and most notably the lack of leap-second handling.  We are currently exploring different options for accommodating different time systems, and are interested in any feedback we can get in terms of what features would be most useful to our customers(if there are any specific time systems you are interested in, please let me know).

Generic/Recurring Dates

Right now there is no native representation for generic, or recurring, dates in the Wolfram Language, beyond the HolidayCalendar framework(which uses a list of pure functions). We are also exploring different representation options for this in the language, with the ability to specify both basic forms like “January 4th” or any year, and also more complex examples like “the 3rd Tuesday in February” or “the 3rd day of the month that’s also a Wednesday”. Feedback on what sorts of applications you would like to use these expressions in will be helpful in determining the best representation for these.

Time Spans

The Wolfram Language currently uses a few different forms to represent spans of time, such as list-notation with {startdate, enddate}, an explicit list of dates such as those generated by DateRange, and in some places Interval[{startdate, enddate}]. We are working on generalizing all of these cases into a single framework that will allow us to appropriately handle all the various application areas for these time periods, and also would appreciate any customer feedback we can get on application areas of interest.

Additional Resources

The following are good resources for additional information regarding the topics discussed in this presentation.

Upcoming Conference Talks

TimeSeries Processing -   Gosia Konwerska, 2:00 PM - 2:30 PM, October 22 2015 (immediately following this talk in Spartan/Golden Gopher)

Time and Date Visualization -  MinHsuan Peng, 4:30 PM - 5:00 PM, October 22 2015 (in Fighting Illini)

Dates

ISO 8601 - International Organization of Standards standard regarding the representation of calendar dates.

Time Zones

Internet Assigned Number Authority Time Zone Database - curated database of time zone information world wide, including regular updates regarding changing daylight saving time changes.

Calendars

Dershowitz, Nachum and Reingold, Edward M. Calendrical Calculations. 3rd ed. New York. Cambridge, 2008. - detailed overview of different calendar systems, including reference LISP implementations.

Wolfram Language Date Framework

nickl@wolfram.com - Please feel free to contact me if you have any questions, comments or concerns about the date framework as discussed here today, or have any suggestions for future features.