The Many Dates and Times of Perl
by Dave RolskyMarch 13, 2003
Some Basic Concepts
In order to understand what you might want to do with dates and times, it's good to have a handle on some basic concepts. Here are some terms that I'll be using in this article:
Related Reading ![]() Embedding Perl in HTML with Mason |
- datetime
This is not a word, but I will use it as a convenient shorthand to
refer to a date and time together, because they are basically the same
thing. Adding time to a date simply increases its granularity.
- UTC (also GMT and Zulu)
UTC stands for "Coordinated Universal Time". It is an international standard which is kept using atomic clocks, and is kept to within 0.9 seconds of the rotation of the earth on its axis in order to work well with traditional standards of time-keeping. UTC time is measured at the prime meridian (O degrees longitude).Time zones around the world are specified as an offset from UTC. The widely used term GMT (Greenwich Mean Time) refers to a time zone that is equivalent to UTC. In other words, it has no offset.
The US military has a set of terms used for time zones around the world based on the alphabet (A-Z). In this system UTC is Z, sometimes called "Zulu".
UTC is a good standard for the internal representation of dates and times, as it makes comparing datetimes or doing datetime math much easier.
- Time zones and Daylight Saving Time
Time zones, as mentioned above, are defined as an offset from UTC. Most, but not all, time zones are in offsets of whole hours. Adelaide, Australia has an offset of nine and a half hours ahead of UTC, and Nepal has an offset five hours and forty-five minutes ahead of UTC.
Time zones are complicated by the use of Daylight Saving Time, which changes the actual offset of a given location to vary over the course of the year. The eastern US has an offset of -0500 from UTC, five hours behind UTC. This means that 12:00 (noon) UTC becomes 07:00 (AM). However, when Daylight Saving Time is in effect, the offset becomes -0400, four hours behind UTC. Because time zones are determined by governments, use of Daylight Saving Time, and the base offsets, have changed over time, and may change again in the future.
This greatly complicates math when dealing with non-UTC datetimes. If I have a local datetime for the Eastern US of 2002-10-25 14:15:00 and I add six months to that datetime, then I will have crossed a DST change.
The upshot of all this is that any code that represents time zones as fixed offset will probably start producing errors once date math gets involved.
The definitive source of time zone offsets and rules is the Olson time zone database. It defines zones according to names like "America/New_York", as opposed to "EST". The latter shorthand is commonly used, but it should probably be avoided because these short names are not unique or definitive. For example, there is an "EST" at -0500 and +1000.
- Local time
The local time is UTC plus the local time zone offset. While UTC is great for internal use, most people want to see datetimes in terms of their location. In a sense, local time is the display format, while UTC is the storage format.
- The epoch
Epoch is a generic term referring to the "start" of any particular system. For example, the Gregorian calendar's epoch is January 1, 1 CE.
The epoch system, as used most operating systems, represents a datetime as the number of seconds after a specific date and time. For Unix systems, the epoch began on January 1, 1970 at midnight GMT (UTC). Other systems have different epochs. Because of this, you cannot assume that an epoch time of 2,003,131 means the same thing from system to system, because different systems have a different "second 0". Storing a datetime as its epoch is not portable.
Even worse, on most current systems, epochs are represented by a 32 bit signed integer, which only lets you represent datetimes with a range of about 136 years. On most UNIX systems currently in use, this means that the latest date you can represent right now is sometime in the year 2038, and the earliest is around 1902. This doesn't work very well if you're trying to represent the birth date of your great-great-grandmother.
The upshot of all this is I would strongly recommend not using epochs except when you have no other choice. Of course, you'll often have no choice, so it's important to know how this system works.
- The Gregorian Calendar
There have been many different calendar systems in use throughout history. The Gregorian calendar is the current generally agreed upon international standard for representing dates, and is what you are using when you say "August 8, 1999". Other calendars that are still in use include the Hebrew calendar, the Islamic calendar, and the Chinese calendar.
Even though the Gregorian calendar wasn't created until 1582, and it wasn't adopted world wide until this century, we can still extrapolate backwards in time using the Gregorian calendar.
What Needs Doing with Dates and Times?
There are a lot of things you can do with dates and times, and different modules/distributions provide different types of functionality. Broadly speaking, we can consider the following areas of functionality:
- Parsing/Formatting
There are more datetime formats in use in the computing world than you can shake a stick at. You'll often have to parse a datetime in one format in order to turn it into something you can work with internally, like a bunch of integers or an epoch time.
On the flip side, you'll often have to take some standard representation, like an epoch, and convert it to some other format.
- Basic representation
A nice datetime object can be quite handy. These range from lightweight wrappers around Perl's
localtime()
to objects that try to provide methods for all possible datetime operations. - Math and calculations
You'll often want to answer questions like "what day is seven days after today" or "how much time is there between now and midnight?" This is closely related to the task of figuring out the date Easter falls on in a given year, or what day of the week Martin Luther King's birthday falls on.
There are plenty of other things we can do with datetimes, but these are largely elaborations of the above areas of functionality.
Perl's Built-in Date/Time Functionality
Perl has some built-in functionality for handling dates and times. This functionality includes:
time()
A function that returns the current epoch time.
localtime()
andgmtime()
These functions convert an epoch time into a set of components representing the local time. They both return arrays containing things like the hour, minute, month, etc., though some of the values returned are awkward to use. For example, the year is the actual year minus 1900.
The
localtime()
function returns the datetime of your current location, based on your system's time zone setting, while the gmtime function returns the current UTC datetime.The
Time::localtime
andTime::gmtime
modules provide a thin object layer aroundgmtime()
andlocaltime()
respectively, so you can do things likeprint gmtime()->year
. Of course, that still prints the year minus 1900.- Time::Local
This core module provide functions that translate from the array of components returned by
localtime()
orgmtime()
back to an epoch time. - POSIX.pm
The
POSIX
module included with Perl provides interfaces to several common C library functions for datetimes, such asstrftime()
. I consider this the last refuge for the desperate, because thePOSIX.pm
module is a memory hog, and the C library interface is rather un-Perlish.
