tags:

views:

1267

answers:

5

Suppose I have a date, i.e. year, month and day, as integers. What's a good (correct), concise and fairly readable algorithm for computing the ISO 8601 week number of the week the given date falls into? I have come across some truly horrendous code that makes me think surely there must be a better way.

I'm looking to do this in Java but psuedocode for any kind of object-oriented language is fine.

+5  A: 

I believe you can use the Calendar object (just set FirstDayOfWeek to Monday and MinimalDaysInFirstWeek to 4 to get it to comply with ISO 8601) and call get(Calendar.WEEK_OF_YEAR).

technophile
+4  A: 

The joda-time library has an ISO8601 calendar, and provides this functionality:

http://joda-time.sourceforge.net/cal_iso.html

yyyy-Www-dTHH:MM:SS.SSS This format of ISO8601 has the following fields:

* four digit weekyear, see rules below
* two digit week of year, from 01 to 53
* one digit day of week, from 1 to 7 where 1 is Monday and 7 is Sunday
* two digit hour, from 00 to 23
* two digit minute, from 00 to 59
* two digit second, from 00 to 59
* three decimal places for milliseconds if required

Weeks are always complete, and the first week of a year is the one that includes the first Thursday of the year. This definition can mean that the first week of a year starts in the previous year, and the last week finishes in the next year. The weekyear field is defined to refer to the year that owns the week, which may differ from the actual year.

The upshot of all that is, that you create a DateTime object, and call the rather confusingly (but logically) named getWeekOfWeekyear(), where a weekyear is the particular week-based definition of a year used by ISO8601.

In general, joda-time is a fantastically useful API, I've stopped using java.util.Calendar and java.util.Date entirely, except for when I need to interface with an API that uses them.

skaffman
A: 

If you want to be on the bleeding edge, you can take the latest drop of the JSR-310 codebase (Date Time API) which is led by Steven Colebourne (of Joda Fame). Its a fluent interface and is effectively a bottom up re-design of Joda.

Andrew Harmel-Law
A: 

this is the reverse: gives you the date of the monday of the week (in perl)

use POSIX qw(mktime);
use Time::localtime;

sub monday_of_week {
    my $year=shift;
    my $week=shift;
    my $p_date=shift;

    my $seconds_1_jan=mktime(0,0,0,1,0,$year-1900,0,0,0);
    my $t1=localtime($seconds_1_jan);
    my $seconds_for_week;
    if (@$t1[6] < 5) {
#first of january is a thursday (or below)
        $seconds_for_week=$seconds_1_jan+3600*24*(7*($week-1)-@$t1[6]+1);
    } else {
        $seconds_for_week=$seconds_1_jan+3600*24*(7*($week-1)-@$t1[6]+8);
    }
    my $wt=localtime($seconds_for_week);
    $$p_date=sprintf("%02d/%02d/%04d",@$wt[3],@$wt[4]+1,@$wt[5]+1900);
}


A: 

week number in perl (sorry, not object oriented, will certainly disgust some)

use POSIX qw(mktime);
use Time::localtime;
use strict;

my $week;
my $year;
&num_of_week(\$week,\$year);
printf "this week: %d of year %s\n",$week,$year;


sub num_of_week {
my $p_week=shift;

my $lt=localtime();
my $tz=0;
my $tNowSeconds=mktime(@$lt[0],@$lt[1],@$lt[2],@$lt[3],@$lt[4],@$lt[5],0,0,$tz);
my $week_day=@$lt[6];
my $thursday_offset=4-$week_day; #week num is the week num of the thursday
my $tThursdaySeconds = $tNowSeconds+$thursday_offset*3600*24; #
$lt=localtime($tThursdaySeconds); # recompute using thursday
my $seconds_1_jan=mktime(0,0,0,1,0,@$lt[5],0,0,0); # use year of thursday
my $week_num=1+($tThursdaySeconds-$seconds_1_jan)/(24*3600*7);

$$p_year=@$lt[5]+1900;
$$p_week=$week_num;
}