Many businesses operate along according to week numbers and ignore months completely, so perl-y business apps may need to calculate them. ("We synergise our assets in week 42, and leverage our ducks into line in week 45", etc)

It's possible to use the Date::Manip or POSIX modules, but they both have some caveats.

Seeing as I only found how to use the above after I'd rolled my own, I thought I'd share both the information and my own solution, so that (crossed fingers) Google might help anyone else needing the same...

Using POSIX:
$weekNum = POSIX::strftime("%V", gmtime time);
(However, this only works on systems where the POSIX implementation meets the "Single Unix" specification. Hence my system (WinXP) just returns "%V", which is less than useful...)

Using Date::Manip:

$weekNum = UnixDate(ParseDate("today"), "%W");
Using none of the above:
# Returns the week number of NOW sub currentWeekNumber { # Get current year, day of year (0..364/5) day of week (0..6) my ($year, $dayOfWeek, $dayOfYear) = (gmtime time)[5,6,7]; # Adjust DayOfWeek from American 0==Sunday, to ISO 0==Monday # and year from "since 1900" to the real year return weekNumber(($dayOfWeek + 6) % 7, $dayOfYear, $year + 1900); } # Returns the week number of the specified time # Year is the real year # Day of week is 0..6 where 0==Monday # Day of year is 0..364 (or 365) where 0==Jan1 sub weekNumber { # Get parameters my ($dayOfWeek, $dayOfYear, $year) = @_; die if ($dayOfWeek < 0); die if ($dayOfWeek > 6); die if ($dayOfYear < 0); die if ($dayOfYear >= 366); die if ($year < 0); # Locate the nearest Thursday # (Done by locating the Monday at or before and going forwards 3 day +s) my $dayOfNearestThurs = $dayOfYear - $dayOfWeek + 3; # Is nearest thursday in last year or next year? if ($dayOfNearestThurs < 0) { # Nearest Thurs is last year # We are at the start of the year # Adjust by the number of days in LAST year $dayOfNearestThurs += daysInYear($year-1); } my $daysInThisYear = daysInYear($year); if ($dayOfNearestThurs > $daysInThisYear) { # Nearest Thurs is next year # We are at the end of the year # Adjust by the number of days in THIS year $dayOfNearestThurs -= $daysInThisYear; } # Which week does the Thurs fall into? my $weekNum = int ($dayOfNearestThurs / 7); # Week numbering starts with 1 $weekNum += 1; # Pad with 0s to force 2 digit representation return substr "0"x2 . $weekNum, -2; } # Returns the number of... sub daysInYear { return 366 unless $_[0] % 400; return 365 unless $_[0] % 100; return 366 unless $_[0] % 4; return 365; }

Replies are listed 'Best First'.
Re: ISO 8601 week number
by jasonk (Parson) on Sep 20, 2008 at 02:13 UTC

    Or the really easy way...

    use DateTime; print DateTime->now->week_number,"\n";

    www.jasonkohles.com
    We're not surrounded, we're in a target-rich environment!
      And nowadays the same thing with a core module

      perl -MTime::Piece -e "print localtime->week"

         larryk                                          
      perl -le "s,,reverse killer,e,y,rifle,lycra,,print"
      
      I'll vote for that.

      Sigh. I don't know how long I looked for a simple solution before I gave up and wrote one, but somehow I never saw the DateTime option. Still, I think it's worth publishing the algorithm, even if it's only a benefit for people who need to implement it in something other than perl...

      I might simplify some code next week.

      PS - I wonder why I can see the module on CPAN, but not via PPM in any of Active's repositories

Re: ISO 8601 week number
by blahblah (Friar) on Mar 31, 2009 at 03:02 UTC
    I found this extremely useful. The code I'm working on has user-set weekstart days (not always Monday) and this code was very nicely explained and easy to modify.
    Robert Browning on being asked what some line in one of his poems meant said
    'When I wrote it only God and Robert Browning knew. Now only God knows.'