Functions for Dates and Times

Table of Contents

  1. Introduction
  2. Dates and Julian Day Numbers (JDNs)
  3. Date/Times and Modified Julian Dates (MJDs)

Introduction

The calendar we use is the Gregorian Calendar introduced by Pope Gregory XIII in 1582. Years divisible by 400 (e.g. 1600, 2000) are leap years but other years divisible by 100 (e.g. 1800, 1900) are not. The Gregorian Calendar replaced the Julian Calendar introduced by Julius Caesar in 46 BC.

A date is defined by a year (AD for these functions), a month-of-year and a day-of-month. The following are examples of date problems:
How many days are there between two specified dates?
What is the date n days after a specified date?
What day of the week corresponds to a specified date?
Such problems can be solved by converting both ways between dates and the (integer) number of days since some fixed date.

Let us call a combination of date and time of day a date/time. The following are examples of date/time problems:
How many seconds are there between two specified date/times?
What is the date/time t seconds after a specified date/time?
Such problems can be solved by converting both ways between date/time and the time (as a real number of say days or seconds) since some fixed date/time.

The XXIIIrd International Astronomical Union General Assembly (1997) Resolution B1 recommends and defines (using different wording) the following terms:

Julian Day Number (JDN)
integer assigned to a solar day, counting from 0 assigned to the day starting at noon UTC on 1st January 4713 BC (Julian Calendar).
Julian Date (JD)
JDN plus the fraction of the day since the preceding noon UTC.
Modified Julian Date (MJD)
time (in days) since 0000 hours UTC on 17th November 1858.
MJD = JD − 2400000.5.

This astronomical definition of JDN can be relaxed for civil date calculations. Here one simply requires a way to associate a date with an integer. So the JDN can be used for civil dates commencing at local midnight. Alternatively, one can use the MJD corresponding to the preceding midnight. There is a difference of 2400001 between these integer JDN and MJD values used to identify entire days (see example below). Modern dates correspond to a 7-digit JDN, as shown in the examples below.

The file date.tcl defines the four functions date2jdn, jdn2date, dateTime2mjd and mjd2dateTime. These are valid for all Gregorian dates from 1st January, 1 AD. The file date.tcl also defines the two formatting procedures format_jdn and format_mjd.

Function date2jdn converts Gregorian dates to JDNs.
Function jdn2date converts JDNs to Gregorian dates.

Function dateTime2mjd converts Gregorian date/times to MJDs.
Function mjd2dateTime converts MJDs to Gregorian date/times.
Double-precision (64-bit) floating point gives accuracy of about a microsecond for years around 2000 AD.

These functions do not the handle the leap seconds that occur in UTC. These functions simply assume that each day contains exactly 86400 seconds (as in UT1). This can cause errors of several seconds in UTC time differences. This problem can be solved using a table of leap seconds such as that at the end of Resolution B1.

Dates and Julian Day Numbers (JDNs)

date2jdn(ymd)

This returns the JDNs of the specified Gregorian dates. The unit is set to JDN.

The argument ymd is an array whose final dimension has the size 3.
Column 0 contains the year AD (positive integer).
Column 1 contains the month of year (1 for Jan, 2 for Feb, ...).
Column 2 contains the day of month (0 to 31). Final example below illustrates 0.

Examples:

% [nap "date2jdn{1997 3 21}"] all; # 21st March, 1997. Note unit
::NAP::112-112  i32  MissingValue: -2147483648  References: 0  Unit: JDN
Value:
2450529
% [nap "date2jdn{1 1 1}"]; # 1st January, 1 AD
1721426
% [nap "date2jdn{1858 11 16}"]; # 16th November, 1858 AD
2400000
% [nap "date2jdn{{1997 2 28}{1997 3 1}}"]; # 28th February & 1st March, 1997
2450508 2450509
% [nap "date2jdn{{2004 8 31}{2004 9 0}}"]; # Both 31st August 2004
2453249 2453249

The following example calculates the day of the week for the first ten days of September 2004:

% [nap "ymd = transpose(2004 // (9 /// 1 .. 10))"]; # 1st to 10th Sept 2004
2004    9    1
2004    9    2
2004    9    3
2004    9    4
2004    9    5
2004    9    6
2004    9    7
2004    9    8
2004    9    9
2004    9   10
% [nap "date2jdn(ymd) % 7"] value; # 0 = Mon, 1 = Tue, 2 = Wed, ..., 6 = Sun
2 3 4 5 6 0 1 2 3 4
% [nap "1 + date2jdn(ymd) % 7"] value; # 1 = Mon, 2 = Tue, ..., 7 = Sun
3 4 5 6 7 1 2 3 4 5
% [nap "1 + (1 + date2jdn(ymd)) % 7"] value; # 1 = Sun, 2 = Mon, ..., 7 = Sat
4 5 6 7 1 2 3 4 5 6

jdn2date(jdn)

This is the inverse of function date2jdn above. It converts JDNs to Gregorian dates. The argument jdn is an array of JDNs. The shape of the result is
shape(jdn) // 3
where the final dimension (3) corresponds to year, month, day. The result is {_ _ _} for any date prior to 1st January, 1 AD (JDN = 1721426).

The following examples are the inverses of the first four examples above for date2jdn:

% [nap "jdn2date(1721426)"]
1 1 1
% [nap "jdn2date(2400000)"]
1858 11 16
% [nap "jdn2date(2450529)"]
1997 3 21
% [nap "jdn2date{2450508 2450509}"]
1997    2   28
1997    3    1

Date/Times and Modified Julian Dates (MJDs)

dateTime2mjd(ymdhms)

This returns the MJDs corresponding to the specified Gregorian date/times. The unit is set to MJD.

The argument ymdhms is an array whose final dimension has a size from 1 to 6.
Column 0 contains the year AD (positive integer)
Column 1 contains the month of year (1 for Jan, 2 for Feb, ...) (Default: 1)
Column 2 contains the day of month (0 to 31) (0: day before 1st) (Default: 1)
Column 3 contains the hour of day (0 to 23) (default: 0)
Column 4 contains the minute of hour (0 to 59) (default: 0)
Column 5 contains the (possibly fractional) second of minute (0 to 60) (default: 0)

Examples:

% [nap "dateTime2mjd{2004 8 16 14 39 59.5}"] all -f %.7f
::NAP::525-525  f64  MissingValue: NaN  References: 0  Unit: MJD
Value:
53233.6111053
% [nap "dateTime2mjd{
{1858 11 16}
{1858 11 17}
{1858 11 18}
}"]
-1 0 1
% [nap "dateTime2mjd{1 1 1}"];# 1st Jan 0001 AD
-678575
% [nap "dateTime2mjd{2000 1 0 12}"]; # 1200 hours, 31st December 1999
51543.5
# The following gives the difference between the JDN & MJD for a date
% [nap "date2jdn{2004 8 16} - dateTime2mjd{2004 8 16}"] -f %d
2400001

mjd2dateTime(mjd[,delta])

This is the inverse of function dateTime2mjd above. It converts MJDs to Gregorian date/times.

The argument mjd is an array of MJDs.

The optional argument delta controls rounding. The result is rounded to the nearest multiple of delta seconds. The default value is 1, which rounds to the nearest second. A value of 60 would round to the nearest minute. A value of 1e-3 would round to the nearest millisecond.

The shape of the result is
shape(mjd) // 6
where the final dimension (6) corresponds to year, month, day, hour, minute, second.

The following examples are the inverses of the first three examples for dateTime2mjd:

% [nap "mjd2dateTime(53233.6111053, 0.1)"]; # round to multiple of 0.1 seconds
2004 8 16 14 39 59.5
% [nap "mjd2dateTime(-1 .. 1)"]
1858   11   16    0    0    0
1858   11   17    0    0    0
1858   11   18    0    0    0
% [nap "mjd2dateTime(-678575)"];# 1st Jan 0001 AD
1 1 1 0 0 0

Author: Harvey Davies       © 2002, CSIRO Australia.       Legal Notice and Disclaimer
CVS Version Details: $Id: date_function.html,v 1.2 2004/10/26 00:32:56 dav480 Exp $