Handling Date-Time Data
QUESTION: I have a dataset in which dates and times are given in units of "hours since 0001-01-01". How do I handle these in IDL?
![]()
ANSWER: The conventional way of representing date-time data in numeric form in IDL is the Julian Day Number. Julian Day Numbers are just days counted from a time in the distant past. For the present purpose you don't need to know much more than that, but it's fascinating to read about it nonetheless. Here are a few good links:
- Julian Day Numbers
- Julian and Gregorian Calendars
- Julian Date Converter
- The Roman Calendar and Dates
Now there's an odd thing about the Julian Day Number system: a new day starts at noon, not at midnight. So, let's say it's 11:00 am and someone asks "What is the current Julian Day Number?" The correct answer would be the number of the Julian Day that started 23 hours ago. But if someone asks "What is today's Julian Day Number?", the correct answer would be (I think) the number of the Julian Day that will start in one hour. Confused? I certainly am. I find the easiest way to avoid confusion is to express dates and times as real numbers. These are called Julian Dates (though this term does have other meanings). The Julian Date equals the Julian Day Number at noon each day, but varies continuously.
The IDL function to convert calendar date-times into Julian Dates is JULDAY. It takes arguments month, day and year, plus (optionally) hour, minute and second. To convert our "hours since 0001-01-01" into Julian Dates we need to know the Julian Date for 0001-01-01.
IDL> print, julday(1,1,1,0,0,0)
1721423.5
So, to convert some data in hours since 0001-01-01 (let's call this variable hs) to Julian Dates (jd) the formula is
jd = julday(1,1,1,0,0,0) + (hs/24.D0)
(Note that the constant 24 is in double precision (64 bits). When we are dealing with dates and times relative to an origin in the distant past it is necessary to used 64-bit floating-point numbers for acceptable precision: a modern Julian Date expressed in double-precision has a precision of around 1 millisecond.)
Now, I said above that the hour, minute and second arguments to JULDAY are optional. So why don't we omit them? Let's try:
IDL> print, julday(1,1,1,0,0,0), julday(1,1,1)
1721423.5 1721424
You may find this result surprising (I do). When you set hour, minute and second to zero, you get the Julian Date at midnight; when you omit them you get the number of the Julian Day that starts at 12:00. This is why I was careful to distinguish between Julian Day Number and Julian Date above. My recommendation: always specify the hour minute and second arguments and deal with Julian Dates only.
Personally, I'm not keen on Julian Dates or "days/hours since 0001-01-01" or any system that expresses modern dates relative to an origin in the distant past, when they weren't even using the same calendar as we do. (In case you're wondering, JULDAY interprets 0001-01-01 as a date in the Julian calendar and by a fortunate coincidence this is the meaning intended by the "since 0001-01-01" people. Ancient calendars are really interesting to some people, like me, but why should you have to bother?) It makes more sense to use a more recent origin and there is IDL software around that does so. I am fond of Modified Julian Days and there's also software that uses "seconds since 2000-01-01". But IDL has built-in facilities to handle Julian Dates, including direct support for input and output via the calendar formats, so (in my opinion) it makes sense to use them.
Finally, a piece of calendar trivia: on 0001-01-01 (Julian calendar) did they know that was what the date was? Well they obviously didn't know it was year 1 AD, but would they agree with us that it was the 1st of January? It turns out the Romans were using the Julian calendar then (it was introduced by Julius Caesar around 46 BC) but they didn't get the leap years finalised until 4 AD. So according to one authority "there is still no certainty regarding these matters, so all dates prior to A.D. 4, when the Julian Calendar finally stabilized, are uncertain" . There you go.
![]()
Copyright © 2005 Mark Hadfield, NIWA
Last Updated 12 August 2005
