Skip to main content
  1. Articles/

Dates and Times

·
Some notes on calendars and timekeeping I made when I was working on Tempo.

Astronomical Year Numbering #

Astronomical year numbering is much like AD / BC, but it includes a year zero and years simply go negative. So 1 BC is year 0 in astronomical year numbering, and 2 BC is -1.

Gregorian and Julian Calendars #

The first day of the Julian calendar was January 1, 45 BC, although the Julian calendar does not specify any particular year numbering (and the Romans used several). Modern anno Domini year numbering came about in the 6th century. (Yes, a centuries old decision is “modern.” Aren’t calendars fun?)

The Gregorian calendar has the same months and days as the Julian calendar. The only difference is in the rules for leap years. Early Julian leap years (as well as leap days) were not uniformly applied until AD 12, after which they occurred every 4 years. With those exceptions aside, an AD year is a Julian leap year if it’s divisible by 4.

Gregorian leap years are more complicated: every year divisible by 4, except those divisible by 100, unless they’re also divisible by 400. So 1700, 1800, and 1900 were not leap years, but 1600 and 2000 were.

The number of days the Gregorian calendar is ahead (or behind if negative) the Julian calendar for a given year, y is

$$ \left\lfloor \frac{y}{100} \right\rfloor - \left\lfloor \frac{y}{400} \right\rfloor . $$

The term proleptic Gregorian calendar refers to using the Gregorian calendar for dates prior to its introduction on October 15, 1582.

ISO 8601 #

ISO 8601 is a standard for date and time representations. It uses a proleptic Gregorian calendar, and astronomical year numbering. Some examples (hyphens are optional in all these examples, but are required in some other cases to avoid ambiguity):

1879-03-14 Happy birthday to Albert Einstein
+10000-12-25 Christmas day, many years from now
-0489-09-10 Battle of Marathon, fought in 490 BC; rip Pheidippides
2023-100 Ordinal date. The 100th day of 2023 or Apr 10
2023-W15-1 Week date. The 1st day of the 15th week of 2023 still also Apr 10
2023-W15 Week date without a day.

Week Number #

Source

I’m using the floor function to denote integer divisions. This is different from a true floor function in the way negatives are handled. E.g. \( \left\lfloor \frac{1}{2} \right\rfloor = 0 \) and \(\left\lfloor -\frac{1}{2} \right\rfloor = -1\), but both equal 0 with truncating division.

For dates in Jan and Feb, calculate:

\( a=\text{year}-1 \)
\( b=\left\lfloor\frac{a}{4}\right\rfloor-\left\lfloor\frac{a}{100}\right\rfloor+\left\lfloor\frac{a}{400}\right\rfloor \)
\( c=\left\lfloor\frac{a-1}{4}\right\rfloor-\left\lfloor\frac{a-1}{100}\right\rfloor+\left\lfloor\frac{a-1}{400}\right\rfloor \)
\( s=b-c \)
\( e=0 \)
\( f=\text{day}+31 (\text{month}-1)-1 \)

For dates in March through Dec calculate:

\( a=\text{year} \)
\( b=\left\lfloor \frac{a}{4}\right\rfloor -\left\lfloor \frac{a}{100}\right\rfloor +\left\lfloor \frac{a}{400}\right\rfloor \)
\( c=\left\lfloor \frac{a-1}{4}\right\rfloor -\left\lfloor \frac{a-1}{100}\right\rfloor +\left\lfloor \frac{a-1}{400}\right\rfloor \)
\( s=b-c \)
\( e=s+1 \)
\( f=\text{day}+\left\lfloor \frac{1}{5} (153 (\text{month}-3)+2)\right\rfloor +s+58 \)

For all months continue:

\( g=(a+b) \bmod 7 \)
\( d=(-e+f+g) \bmod 7 \)
\( n=-d+f+3 \)

Finally, there are three cases:

  • if \(n<0\), the day is in week \(53-\left\lfloor \frac{g-s}{5}\right\rfloor\) of the previous year

  • if \(n>364+s\) the day is in week 1 of the following year

  • otherwise the day is in week \(\left\lfloor \frac{n}{7}\right\rfloor +1\) of the current year

Ordinal Date #

An ordinal date is a date containing a year and the day of the year. It basically says “this date is the nth day of year y.”

The ordinal date is equal to \(f+1\) in the Week Number algorithm above.

Julian Period #

The Julian period is defined to start at 12:00 UT (Universal Time—not UTC!) on Monday, January 1, 4713 BC on the Julian calendar or November 24, 4714 BC on the proleptic Gregorian calendar. In astronomical years, it began on -4712 on the Julian calendar, and -4713 on the Gregorian.

The start of the Julian period was chosen because it predates human records, and it occurs on a confluence of the start of the solar cycle, lunar cycle and 15-year Roman taxation cycle. It’s also a Monday.

Julian Day #

The Julian Day Number (JDN) is the number of days since midday of the start of the Julian period. Calculating it from a Julian date gets a bit hairy, and from a Gregorian date is even worse. However the gist is to count the number of days in the full Julian years (optionally subtracting the Gregorian delta), and then adding in the days for each full month, and finally adding in the specific day of the month.

Dealing with the years is pretty easy. For Julian dates, add 365 days for each, year, and one more day for each leap year:

$$ 365\times\text{year}+\left\lfloor \frac{\text{year}}{4}\right\rfloor $$

For Gregorian dates, you must subtract the non-leap years divisible by 100 and add back the ones divisible by 400:

$$ 365\times\text{year}+\left\lfloor \frac{\text{year}}{4}\right\rfloor -\left\lfloor \frac{\text{year}}{100}\right\rfloor +\left\lfloor \frac{\text{year}}{400}\right\rfloor $$

Once you include months, the formulas start getting hairy.

Here’s a formula from Wikipedia:

$$ 367 \times y − (7 \times (y + 5001 + (m − 9)/7))/4 + (275 \times m)/9 + d + 1729777 $$

Why does this work? I don’t know. It’s full of magic numbers. The formula that uses Gregorian Date is even worse:

$$ (1461 \times (y + 4800 + (m − 14)/12))/4 +(367 \times (m − 2 − 12 \times ((m − 14)/12)))/12 − (3 \times ((y + 4900 + (m - 14)/12)/100))/4 + d − 32075 $$

Further reading: https://www.tondering.dk/claus/cal/julperiod.php

Julian date (JD) is simply a JDN with a fractional part representing the time of day. It’s a little inconvenient since the Julian period starts at noon instead of midnight.

Day of Week #

Since the Julian period starts on a Monday, and the 7-day weekly cycle has not been interrupted since the time of Moses (about 1600 BC), it’s pretty simple to find day of the week using the Julian Day Number. For example, using the ISO numbering from 1=Monday to 7=Sunday:

$$ \text{JDN} \bmod 7 + 1$$

And US weekday numbering, 0=Sunday to 6=Saturday:

$$ (\text{JDN}+1) \bmod 7 $$

Storage Requirements #

Bits required to store Julian dates up to 10000 years from year 1 at various granularities:

Date Days Seconds Milliseconds Microseconds Nanoseconds
January 1, -10000 21 38 48 58 68
January 1, 10000 23 39 49 59 69

Mathematica code to generate the above table:

TableForm[(Module[{jd = JulianDate[#]},
     Prepend[IntegerLength[# // IntegerPart,
         2] & /@ (jd {1, 86400, 86400 10^3, 86400 10^6,
          86400 10^9}), #]] &) /@ {DateObject[{-10000, 1, 1}],
   DateObject[{10000, 1, 1}]},
 TableHeadings -> {None, {"Date", "Days", "Seconds", "Milliseconds",
    "Microseconds", "Nanoseconds"}}]

Absolute Month #

Pretty straightforward. An easy epoch is 0000-01-01. Then the absolute month number is:

$$ 12 \times \text{year} + \text{month} $$

Rata Die #

Rata Die is to local dates and times what Julian date is to absolute ones. It numbers days starting with 1 = midnight of 0001-01-01. (It’s worth repeating: Rata Die starts at midnight, not noon like Julian Day.)

The fundamental difference between Julian date and Rata Die (other than epoch dates) is that Julian date is an absolute time defined by noon at 0º longitude, while Rata Die is relative to whatever local time you want it to be. With that said, the basic conversion is:

$$ \text{RD}=\text{JD}-1721424.5 $$

There’s also a Rata Die Day Number which is just

$$ \text{RDN}=\lfloor \text{JD}-1721424.5\rfloor $$

If you’re dealing with an integer JDN instead of the fractional JD it’s

$$ \text{RDN} = \text{JDN}-1721425 $$

More info: https://en.wikipedia.org/wiki/Rata_Die

Peter Baum, Date Algorithms, 1998, 2017, 2020, https://www.researchgate.net/publication/316558298_Date_Algorithms

https://www.tondering.dk/claus/cal/intro.php