Dates, Times, and Timezones (in perl)

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"; 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";
 * 1) Figure out the timezone.  First, interpret what the user entered with a
 * 2) guessed timezone so str2time has something to work with that is at most
 * 3) an hour off (not half-way around the world).  Then use tz2zone to figure
 * 4) out what timezone that time of year should use.  Finally, re-execute
 * 5) str2time to get the output in the correct timezone for that time of year.

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.)