Dates, Times, and Timezones (in perl)

From Devpit
Jump to: navigation, search

Notes on terminology

  • A timezone is a specific offset from UTC. So CST and CDT are timezones. CST6CDT is not.
  • A tzspec is a specification for the timezone used in a particular part of the world, for example, CST6CDT or CST6.
  • Epoch_seconds is a timestamp expressed in seconds since the Unix epoch.
  • I use CST6CDT, CST, and CDT here as placeholders for any arbitrary timezone.

Printing a Non-Local Time

use Date::Format ();
use Time::Zone ();

my $epoch_seconds = time();
my $tzspec = "CST6CDT";

print Date::Format::time2str("%a %Y-%m-%d %H:%M:%S %Z", $epoch_seconds, Time::Zone::tz2zone($tzspec, $epoch_seconds)), "\n";

Time::Zone::tz2zone() calculates whether $epoch_seconds is during the time of year the timezone is CST or CDT.

Date::Format::time2str() formats $epoch_seconds with a specific timezone (not a tzspec).

Interpreting a Time Entered By A User

This is much harder than it sounds. You (not the user) are responsible for figuring out whether the time entered by the user should be interpreted as CST or CDT. This has nothing to do with the current time. If the user enters July 1 11pm, that should always be interpreted as CDT (unless the user specifically enters a timezone). Similarly, January 1 11pm should always be interpreted as CST. To complicate things, Date::Parse isn't very smart; you can't pass it a tzspec {grumble}. Obviously there is an hour a year where time timezone the user wants is only a guess, but Date::Parse::str2time() always lets the user override it to any timezone.

use Date::Parse ();
use Time::Zone ();

my $user_input = "June 23, 2005 4:43pm";
my $tzspec = "CST6CDT";

# Figure out the timezone.  First, interpret what the user entered with a
# guessed timezone so str2time() has something to work with that is at most
# an hour off (not half-way around the world).  Then use tz2zone() to figure
# out what timezone that time of year should use.  Finally, re-execute
# str2time() to get the output in the correct timezone for that time of year.
my $timezone = Time::Zone::tz2zone($tzspec, 1);  # Guess at $timezone
my $epoch_seconds = Date::Parse::str2time($user_input, $timezone);  # May be an hour off
$timezone = Time::Zone::tz2zone($tzspec, $epoch_seconds);  # Now correct
$epoch_seconds = Date::Parse::str2time($user_input, $timezone);  # Now correct

print $epoch_seconds, "\n";

As far as I know, this code should always "do the right thing". If the user types "EDT" after their input, it will always be interpreted as EDT, even if you set $tzspec to CST6CDT and even if it's winter. (See Date::Parse's docs.)

See Also