baphomet has asked for the wisdom of the Perl Monks concerning the following question:
Excellent Monks!
Last night, as I was toiling away at one of my current Everything Engine projects, I came upon an older item in my to do list that, while at first glance appearing quite simple, has now consumed (at least the anal-retentive part of) my mind ;)
The task is this: given a date and time in GMT, I want to be able to convert that date to an arbitrary time zone, respecting daylight savings and strange (i.e. not simply +1 or -1) hour offsets, and pretty-print the result for human consumption.
The method I hit upon (that doesn't employ Date::Manip, at any rate) goes something like this:
sub format_date { my ($epoch, $string, $timezone) = @_; local %ENV; $ENV{TZ} = $timezone || 'GMT'; return strftime($string, localtime($epoch)); }
This works, for the most part, and plays nicely with Time::ZoneInfo. However! POSIX::strftime's %Z and %z tokens are sometimes wrong. For instance, given a date during daylight savings and one during winter time, %Z is replaced with the standard time abbreviation (i.e. for America/Chicago %Z renders CST for both dates, which would be correct for America/Regina) and %z with only the standard time offset.
Time::CTime::strftime, meanwhile, simply regurgitates the value of %ENV{TZ}.
Is there a better way to be going about these date calculations? Ideally, I'd like to be able to display EST/EDT, NZST/NZDT, etc. just like date(1) ... one way would be to gut the zoneinfo files manually for their innards, another to build a table of EST -> EDT conversions... however, the first seems not incredibly efficient while the later seems incredibly kludgy.
Any suggestions, or fine rants about time ;), would be appreciated.
Update: Well, it looks like I neglected to notice Class::Date. Using the to_tz() method, you get results similar to what I've used above, except that Class::Date objects keep some better information about the date's time zone. For instance,
sub format_date { my ($isodate, $string, $timezone) = @_; my $gmtdate = Class::Date->new($isodate, 'GMT'); my $tzdate = $gmtdate->to_tz($timezone); return $tzdate->strftime($string); }
will return proper results for strftime's %Z. You can also access $tzdate->tz_offset to grab GMT offset, $tzdate->tz to grab the base timezone and $tzdate->tzdst to grab the "real" timezone accounting for DST as best as zoneinfo can.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Playing with time (or, a lament to POSIX::strftime's %Z)
by seattlejohn (Deacon) on Dec 24, 2002 at 00:53 UTC | |
|
Re: Playing with time (or, a lament to POSIX::strftime's %Z)
by waswas-fng (Curate) on Dec 23, 2002 at 23:17 UTC |