#!/usr/local/bin/perl -w # Code to print ISO 8601:1988 week number for 'any' date. # Uses Unix time functions, so works for 1970 - 2038. # # A.D.S.Benham, June 1998 # # If called with no arguments, prints week number of current date/time # # Can call with one argument, the seconds since the epoch # # Can call with three arguments - day month year # #/ my ($given_time,@inp,$year,$daynumber,$day,$x,$week); use POSIX; use integer; if ($#ARGV == 0) { @inp=localtime($ARGV[0]); } elsif ($#ARGV == 2) { $inp[3] = $ARGV[0]; $inp[4] = $ARGV[1]-1; # Process the year number # If xx < 50, assume 20xx # If 50 <= xx < 100, assume 19xx # If xx >= 100, assume xxxx if ($ARGV[2] < 50) { $inp[5] = $ARGV[2]+100; } elsif ($ARGV[2] < 100) { $inp[5] = $ARGV[2]; } else { $inp[5] = $ARGV[2]-1900; } $inp[2]=12; $inp[1]=0; $inp[0]=0; $inp[6]=0; $inp[7]=0; $inp[8]=-1; } elsif ($#ARGV == -1) { @inp=localtime(time); } else { printf STDERR "Syntax: %s [day month year] | [seconds_since_epoch]\nReturns week number according to ISO8601:1988\nWritten by ADS Benham\n",$ARGV; exit 1; } # POSIX::mktime seems loathe to fill in the weekday, so do a localtime() # to force the weekday to be right. $given_time=POSIX::mktime(@inp); @inp=localtime($given_time); $year=$inp[5]+1900; $daynumber=$inp[7] + 1; # day number in year ( range 1-366) $day=$inp[6]; # weekday, sunday=0 if ($day == 0) { $day=7; # Make Sunday day 7 (day range 1-7) } $x=$daynumber - $day; $week=$x/7+1; # Get 'raw' week number # The raw week number now needs to be worked on. ISO8601:1988 tells # us that week 1 of a year is the one which includes the first Thursday # of the year, or equivalently the one which includes 4 January. # ISO8601:1988 also tells us that the week begins on Monday. if ($x < 0) { $week=0; } if ($x%7 < 0) { $x += 7; # x%7 is the date of the 1st Sunday in the year } if ($x%7 > 3) { $week++; } if ($week==53) { # Week 53 is usually bogus result of calc if ( (&is_leap_year($year) and ($x%7 == 5)) or ($x%7 == 4) ) { # Really is a week 53 under these conditions */ } else { $week = 1; $year++; } } if ($week < 1) { # Need to return the last week of the previous year. This is either 52 or 53. # To get here, x%7 is either 1, 2, or 3 # If it's 1, then the last week of the previous year is guaranteed to be week 52 # If it's 3, then the last week of the previous year is guaranteed to be week 53 # If it's 2, then it depends on: # 1. whether this year is a leap year: if so, then the last week of the # previous year was week 52 # 2. if this year isn't a leap year, was the previous year was a leap year ? # if it was, then the last week of the previous year was week 53 # if it wasn't, then the last week of the previous year was week 52 if ($x%7 == 1) { $week = 52; } elsif ($x%7 == 3) { $week = 53; } elsif ($x%7 == 2) { if (&is_leap_year($year)) { # Current year is a leap year $week = 52; } else { if (&is_leap_year($year-1)) { # Previous year is a leap year $week = 53; } else { $week = 52; } } } else { print STDERR "Logic warning - shouldn't get here\n"; $week=-999; } $year--; } printf "%dW%.2d\n",$year,$week; sub is_leap_year # Return 1 if leap year, 0 if not # Note: year is 4 digit number { if ($_[0] % 400 == 0) { return 1; } if ($_[0] % 100 == 0) { return 0; } if ($_[0] % 4 == 0) { return 1; } return 0; }