Oberon has asked for the wisdom of the Perl Monks concerning the following question:

O learned masters,

I'm attempting to convert some code over from the somewhat bloated Date::Manip to a slimmer combination of Date::Calc, Date::Parse, and Date::Format. (Aside: Yes, I have considered using DateTime. While there are many advantages thereto, the two facts that have stopped me thus far are 1) there is no general parsing mechanism a la Date::Parse, and 2) it would still be roughly 3x the size of D::C + D::P + D::F.)

Where I'm currently stuck is in dealing with the ISO week number format: yyyy-Www(-dow)?. For Date::Manip, the relevant format for UnixDate() is "%L-W%W". However, Date::Format seems to be lacking ... it has the %W, but nothing corresponding to the %L.

Can anyone suggest how I should be handling this? Is there some standard way that Date::Format is used for these types of date formats? Or is there another module that replaces Date::Format (that maintains a similar footprint)? Or ... something else?

I await enlightenment with appropriate humility.

  • Comment on Date::Format handling of ISO week number format

Replies are listed 'Best First'.
Re: Date::Format handling of ISO week number format
by grinder (Bishop) on Jan 15, 2008 at 11:42 UTC

    I'm not sure whether you want to parse these date formats, or produce them. Since you mention Date::Format, I assume you want to format them. In which case, what's wrong with the following?

    use strict; use Date::Format 'time2str'; print time2str("%Y-W%W", time);

    If you want to zero-fill the week numbers, you have to use the slightly more cumbersome:

    my $t = time; print time2str("%Y-W", $t) . sprintf("%02d",time2str("%W", $t));

    • another intruder with the mooring in the heart of the Perl

      > what's wrong with the following?
      > :
      > print time2str("%Y-W%W", time);

      Because when the date falls in the first week of the year or the last week of the year, that'll be wrong about half the time. For instance,

      use strict; use warnings; use Date::Manip qw<UnixDate>; use Date::Parse qw<str2time>; use Date::Format qw<time2str>; print UnixDate("12/31/2007", "%L-W%W"), "\n"; # prints "200 +8-W01" print time2str("%Y-W%W", str2time("12/31/2007")), "\n"; # prints "200 +7-W52" (!!)
      Actually, I thought it would print "2007-W01" ... I guess D::F's %W is broken to go along with its lack of UnixDate-equivalent-%L. At least it works better than I thought, I suppose ... but of course, according to ISO 8601, 2007-W52 is still wrong.

        Ah, well that sucks. I would file a bug report. Since that doesn't work, I shall return to my first idea, which is to use Date::Calc. I didn't even know about Date::Format until you pointed it out.

        #! /usr/local/bin/perl -w use strict; use Date::Calc 'Week_of_Year'; my ($y, $m, $d) = split m{/}, shift || '2007/12/31'; my ($week,$year) = Week_of_Year($y, $m, $d); printf "%04d-W%02d\n", $year, $week;

        You might want to wrap that up in a little routine and be done with it. It will certainly be far faster than using Date::Manip

        • another intruder with the mooring in the heart of the Perl