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.

baphomet.

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.


In reply to Playing with time (or, a lament to POSIX::strftime's %Z) by baphomet

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.