Everything You Wanted to Know About Dates

Nick Lariviere, Wolfram Research

(RowDefault[, (Spacer1), , (Spacer1), ])  #WolframTechConf

ABSTRACT

This talk offers an overview of the different aspects involved in understanding and working with dates and time; conceptually and within the the Wolfram Language.

Topics include recent updates and enhancements to the date/time framework, the interactions between various calendars and date operations, and upcoming date and calendar features.

Introduction to Time

Dynamic[Refresh[Row[{ClockGauge[AbsoluteTime[],PlotLabel->Style["Chicago",Large,Bold]],ClockGauge[AbsoluteTime[TimeZone->0],PlotLabel->Style["GMT",Large,Bold]],
ClockGauge[AbsoluteTime[TimeZone->"Asia/Tokyo"],PlotLabel->Style["Tokyo",Large,Bold]],ClockGauge[AbsoluteTime[TimeZone->"Asia/Kolkata"],PlotLabel->Style["Kolkata",Large,Bold]]}],(UpdateInterval->1)]]

What time is it?

UnixTime[]

What is time?

Time is the continued sequence of existence and events that occurs in an apparently irreversible succession from the past, through the present, into the future.

The current definition in the International System of Units for a second:

The second is defined by taking the fixed numerical value of the caesium frequency, ΔνCs, the unperturbed ground-state hyperfine transition frequency of the caesium 133 atom, to be 9192631770 when expressed in the unit Hz, which is equal to s−1.

Dynamic[Refresh[UnixTime[],UpdateInterval->1]]

Dynamic[Refresh[SiderealTime[],UpdateInterval->1]]

Introduction to Dates

TimelinePlot[RandomDate[10]]

What is today’s date?

Today

DateObject[Today,CalendarType->"ISOWeek"]

DateObject[Today,CalendarType->"Japanese"]

Manipulate[DateString@DateObject[CalendarType->i],{{i,"Gregorian"},CalendarData["DateCalendar"]}]

What are dates?

• A date is a reference to a particular instance of time (typically a day) represented within a calendar system, which allows the specific instance to be uniquely identified.

Introduction to Calendars

Labeled[Grid[Partition[Labeled[#2,DateValue[#,"Day"]]&@@@MoonPhase[DateRange[DateObject[{2024,10,1}],DateObject[{2024,10,31}],1],"Icon"]["Path"],7,7,2,""],Frame->All],"October 2024",Top]

What are calendars?

• A calendar is a system for organizing dates and times using periods of time, often consisting of various elements like days, months, and/or years.

What types of calendars are there?

CalendarData["DateCalendar"]

• Observational calendars

• Regnal calendars

DateObject[CalendarType->"Japanese"]

• Arithmetic calendars

CalendarData["ArithmeticCalendar"]

• Astronomical calendars

CalendarData["AstronomicalCalendar"]

Solar calendars

Solar calendars (including Egyptian, Armenian, Persian, Gregorian, Julian, Coptic, Ethiopic, ISO, French Revolutionary and Bahá’í) are based on the yearly solar cycle. Most solar calendars are divided into months, but these months are divorced from the lunar events.

Lunar calendars

Lunar calendars (such as Islamic and Jewish) take the monthly lunar cycle as their basic building block.

Lunisolar calendars

Lunisolar calendars combine the yearly solar cycle with monthly lunar cycles. Because these two cycles do not align, they typically include periodic leap months and/or days for realignment.

CalendarConvert@DateObject[{72,25,4,20},"Day",CalendarType->"Chinese"]

CalendarConvert@DateObject[{72,25,LeapVariant[4],20},"Day",CalendarType->"Chinese"]

DateValue[(DateObject["Adhika 14 Adhika Āśvina 2039""GMT"-5.` ("ModernHinduLunisolar""calendar"), DateObject[{2039,LeapVariant[7],LeapVariant[14]},"Instant","ModernHinduLunisolar",-5.`]]),{"Year","Month","Day"}]

Calendar Granularity

What are calendar granularities?

Calendar granularities are the units that compose the timekeeping steps of a given calendar, such as a year, month or day.

What is a Year?

• The calendar granularity associated to the motion of the Earth around the Sun. There are two main definitions: the tropical year and the sidereal year, with the first one being more important, because it is tied to the seasons, something fundamental for agriculture. Then there are many other concepts of year.

Grid[{#,UnitConvert[Quantity[1.,#],"Days"]}&/@{"Years","LeapYears","GregorianYears","JulianYears","SiderealYears","TropicalYears","LunarYears"},Alignment->Left]

What is a Month?

• A month is approximately the time that the moon takes to move once around the earth. This is a vague definition. The motion of the moon has several irregularities, so the definition needs to be an average anyway.

• The lunar cycle formed the basis for the palaeolithic marking of time. Some calendars start a month with the new moon (Hebrew or Islamic) or with the full moon (in northern India, for example). For calendars in which the month begins with the observed new moon, beginning the day at sunset is natural.

Grid[{#,UnitConvert[Quantity[1.,#],"Days"]}&/@{"Months","GregorianMonths","SynodicMonths","SiderealMonths","TropicalMonths","LunarMonths"},Alignment->Left]

What is a Day?

• A day is the time period of a full rotation of the Earth with respect to the Sun (on average, this is 24 hours, 1440 minutes, or 86,400 seconds, but as with other granularities the actual length of a day varies depending on the point of reference).

Grid[{#,UnitConvert[Quantity[1.,#],"Seconds"]}&/@{"Days","SiderealDays","LunarDays"},Alignment->Left]

• The difference between a sidereal day and a solar day is associated with the tropical year:

1/(1/Quantity["SiderealDays"]-1/Quantity["Days"])

%==Quantity[1,"TropicalYears"]

• The day starts at different times in different calendars: sunset, midnight, sunrise, noon. From CC, definition of day i (JD means Julian Day):

CalendarData["Gregorian"]

CalendarData["ModernHinduSolar"]

CalendarData["JulianDate"]

Time Zones

GeoListPlot[List/@EntityList[EntityClass["TimeZone","GMTOffsets"]],PlotLegends->None,GeoProjection->"AzimuthalEquidistant",GeoCenter->GeoPosition[{90,-90}],GeoBackground->{"Coastlines","Land"->Gray,"Ocean"->Transparent}]

What are time zones?

A time zone is an area which observes a uniform standard time. Time zones typically to follow the boundaries between countries and their subdivisions instead of strictly following longitude, because it is convenient for areas in frequent communication to keep the same time.

Length[zones=(Entity["United States", Entity["Country","UnitedStates"], "Entity[\"Country\", \"UnitedStates\"]", "country"])["TimeZones"]]

GeoGraphics[Table[{ColorData[109,k],Polygon@zones[[k]]},{k,1,Length[zones]}]]

Show[%,GeoRange->(Entity["Indiana, United States", Entity["AdministrativeDivision",{"Indiana","UnitedStates"}], "Entity[\"AdministrativeDivision\", {\"Indiana\", \"UnitedStates\"}]", "administrative division"])]

What kinds of time zones are there?

numeric time zones

These time zones are a fixed offset from Greenwich Mean Time (GMT), and typically given as a number of hours difference in locale time.

$SystemTimeZone

internet time zones

The Internet Assignment Number Authority (IANA) maintains a database of geographic time zones in a database that collects the various rules for time zone offsets both historically and currently, and is updated regularly.

$TimeZoneEntity

TimeZoneOffset[(Entity["America/Chicago", Entity["TimeZone","America/Chicago"], "Entity[\"TimeZone\", \"America/Chicago\"]", "time zone"])]

TimeZoneOffset[(Entity["America/Chicago", Entity["TimeZone","America/Chicago"], "Entity[\"TimeZone\", \"America/Chicago\"]", "time zone"]),0,(DateObject["Tue 12 Nov 2024", DateObject[{2024,11,12},"Day"]])]

TimeZoneOffset[(Entity["America/Chicago", Entity["TimeZone","America/Chicago"], "Entity[\"TimeZone\", \"America/Chicago\"]", "time zone"]),0,(DateObject["Tue 1 Jan 1850", DateObject[{1850,1,1},"Day"]])]

LocalTimeZone[]

TimeZoneConvert[Now,GeoPosition[{-34,151}]]

Time Systems

What are time systems?

A time system is a specification for measuring time (the rate at which time passes, how points in time are measured, or both).

What kinds of time systems are there?

now=Now;
Grid[{#,TimeSystemConvert[now,#]}&/@{"UT","UTC","UT1","TT","TAI","ET","TCB","TCG"},Alignment->Left]

Between 1960 and 1972, "UTC" frequently added fractional seconds and was more closely aligned to "UT1":

DateListPlot[{#,DateDifference[DateObject[#,TimeSystem->"UT1"],DateObject[#,TimeZone->0,TimeSystem->"UTC"],"Second"]}&/@DateRange[{1960,1,2},{1973,1,1},"Month"],PlotRange->{-.7,1}]

Starting in 1972, "UTC" adds only whole leap seconds, as needed, to remain within 1 second of "UT1":

DateListPlot[{#,DateDifference[DateObject[#,TimeSystem->"UT1"],DateObject[#,TimeZone->0,TimeSystem->"UTC"],"Second"]}&/@DateRange[{1970,1,1},{2020,1,1},"Month"]]

The difference between "TAI" and "UTC" shows the number of leap seconds added since "UTC" began:

DateListPlot[{#,DateDifference[DateObject[#,TimeSystem->"TAI"],DateObject[#,TimeZone->0,TimeSystem->"UTC"],"Second"]}&/@DateRange[{1960,1,2,0,0,0},{2021,1,1},"Month"]]

observation of the duration of each day from 1990 to 2000

DateListPlot[GeoOrientationData[DateInterval[{{1990},{2000}}],"DayDurationExcess"],TargetUnits->"Seconds"]

because these were all longer than 24 hours, we need leap seconds.

get the difference between TAI and UT1 from 1990 to 2000

dates=DateRange[DateObject[{1990,1,1}],DateObject[{2000,1,1}]];
dt=GeoOrientationData[dates,"TAIMinusUT1"]

get the difference between TAI and UTC for the same period

leap=GeoOrientationData[dates,"TAIMinusUTC"]

Show[DateListPlot[{Transpose[{dates,dt-Quantity[0.9,"Seconds"]}],Transpose[{dates,dt+Quantity[0.9,"Seconds"]}]},PlotStyle->Orange],DateListPlot[Transpose[{dates,leap}]],ImageSize->Medium]

Here is an example comparing a leap second being added, as seen through both TAI and UTC:

DateObject[#,TimeZone->0,TimeSystem->"TAI"]&/@DateRange[{2017,1,1,0,0,33},{2017,1,1,0,0,40},Quantity[1,"Seconds"]]

TimeSystemConvert[#,"UTC"]&/@%

Date Formats

What are date formats?

A date format is a specification of what elements of a date are given, and in what order. Date formats may come from international, national, or local standards.

What kind of date formats are there?

see the documentation for DateString for an exhaustive list

DateString[]

DateString["ISODateTime"]

DateString["ISOWeekDate"]

DateString["ISOOrdinalDate"]

DateString[{"DateShort","[","Time","]"}]

What kind of locales are available?

A locale is a set of parameters that defines ones language, region and any special variants in localizing dates. Usually a locale identifier consists of at least a language code and a country/region code.

EntityValue["LanguageLocale","SampleEntities"]

DateString[Now,(Entity["American English", Entity["LanguageLocale","en-US"], "Entity[\"LanguageLocale\", \"en-US\"]", "language locale"])]

DateString[Now,]

DateString[Now,"ja"]

DateString[Now,<|"Language"->"Japanese","Elements"->"LocaleDateTimeLong"|>]

FromDateString["2023年3月7日 16:15:01","ja"]

Application: Granularity in Arithmetic

What is the date one month after January 30th?

DatePlus[(DateObject["Mon 30 Jan 2023", DateObject[{2023,1,30},"Day"]]),(Quantity[1, "mo", month, "Months"])]

What are date arithmetic methods?

There are two main methods of doing arithmetic with dates:

Continuous - uses a fixed definition of unit steps (e.g. 1 month is always 2628000 seconds), and thus does not need to account for variation in unit length

DatePlus[(DateObject["Wed 8 Mar 2023 00:00:00", DateObject[{2023,3,8,0,0,0},"Instant","Gregorian",None]]),Quantity[1,"Month"],Method->"Continuous"]

(DateObject["Wed 8 Mar 2023 00:00:00", DateObject[{2023,3,8,0,0,0},"Instant","Gregorian",None]])+Echo[UnitConvert[(Quantity[1, "mo", month, "Months"]),"Seconds"]]

Discrete - uses calendar steps of potentially dynamic length (depending on the calendar being used), which needs to account for gaps/intercalation/daylight saving/leap seconds.

DateObject[{2023,2,30}]

For discrete arithmetic, there is also variation in the method by which variable calendar step lengths handle “rolling” when a gap is encountered during arithmetic (most commonly “Month” on the Gregorian calendar). The three main methods for doing this are:

Roll Forward - skip over to the next valid date

Roll Backward - stay on the last valid date

Roll Over - continue to the next valid date and keep adding from there

DatePlus[(DateObject["Fri 31 Jan 2020", DateObject[{2020,1,31},"Day"]]),Quantity[1,"Months"],Method->#]&/@{"Continuous","RollBackward","RollForward","RollOver"}

Application: Midpoint Detection

When was the middle of Shakespeare’s career?

Length[Echo[EntityClass["Book",{(EntityProperty["author", EntityProperty["Book","Author"], "EntityProperty[\"Book\", \"Author\"]"])->(Entity["William Shakespeare", Entity["Person","WilliamShakespeare::s9r82"], "Entity[\"Person\", \"WilliamShakespeare::s9r82\"]", "person"])}]//EntityList]]

shakespeare=DeleteMissing[EntityValue[EntityClass["Book",{(EntityProperty["author", EntityProperty["Book","Author"], "EntityProperty[\"Book\", \"Author\"]"])->(Entity["William Shakespeare", Entity["Person","WilliamShakespeare::s9r82"], "Entity[\"Person\", \"WilliamShakespeare::s9r82\"]", "person"])}],"FirstPublished","Association"]]

DateHistogram[shakespeare]

DateBounds[Values[shakespeare]]

With[{first=First[%]},first+(DateDifference@@%)/2]

MidDate[shakespeare,"Year"]

TimelinePlot[{shakespeare,{%}}]

What are date midpoint methods?

There are various methods available to determine the midpoint between two or more dates, including different weighting and arithmetic methods.

GranularMean/Median - Mean or median, weighting each date according to it’s calendar granularity

WeightedMean - Mean based on the full duration of each date

UnionedMean - “Flat” mean, with all overlapping intervals unioned into a single distribution

MidpointMean/Median - Mean or median using the midpoint of each date (w/out regard to granularity)

BoundsMean - Mean of the date bounds for the data (i.e. the minimum and maximum dates)

The differences in these methods can be seen applying the methods to the Shakespeare example:

With[{data=shakespeare},TimelinePlot[{Values@data,AssociationMap[MidDate[data,Method->#]&,{"MidpointMean","MidpointMedian","BoundsMean"}]}]
]

With[{data=king},TimelinePlot[{Values@data,AssociationMap[MidDate[data,Method->#]&,{"GranularMedian","WeightedMean","MidpointMean","MidpointMedian","BoundsMean"}]}]
]

Dates in Tabular

Temporal types

Tabular has both “Date” and “Time” column types:

ToTabular[<|"date"->RandomDate[10],"time"->RandomTime[10]|>,"Columns"]

The column types contain information about the different parameters for the stored data:

%["ColumnTypes"]

Tabular has automatic parameter detection based on the input data (with a conforming operation when necessary for non-homogenous dates):

dates=RandomDate[(DateObject["Millennium: ""2000-3000", DateObject[{2000},"Millennium","Gregorian",-5.`]]),10,DateGranularity->"Day",CalendarType->"Julian"]

ToTabular[<|"date"->dates|>,"Columns"]

%["ColumnTypes"]

There are also convenience features like elision of common date elements (which can be moved to the column heading):

ToTabular[<|"date"->RandomDate[Today,8]|>,"Columns"]

Optimizations

There are also optimized accessors, parsing, and typesetting tools built in to Tabular:

t=ToTabular[<|"d"->RandomDate[10000]|>,"Columns"];

RepeatedTiming[t2 = TransformColumns[t, {"s"->(DateString[#d]&)}]]

RepeatedTiming[TransformColumns[t2,{"p"->(DateObject[#s]&)}]]

Additional Resources

Calendrical Calculations by Edward M. Reingold, Nachum Dershowitz

ISO-8601 date and time standard

IANA time zone database

IANA language sub-tag registry