Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a good, simple way to compute ISO 8601 week number?

Tags:

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.

like image 848
user9511 Avatar asked Sep 29 '08 01:09

user9511


People also ask

How is ISO week number calculated?

For an ISO week, if the last day of the year ends on a Wednesday as it did in 1992, the week is considered to include the first few days of the next year to complete the full seven day week. Thereby it continues to count the week numbering from the current year until the week is complete.

What is ISO 8601 week based?

All weeks in the ISO-8601 Week-Based calendar have exactly 7 days, start on a Monday, and each week belongs to single year. Unlike the Gregorian calendar, there are no weeks that extend across years. Each ISO-8601 year is either a Long or a Short year, with 52 or 53 weeks depending on when the ISO-8601 year begins.

How are week numbers defined?

The weeks of the year in a Gregorian calendar are numbered from week 1 to week 52 or 53, depending on several varying factors. Most years have 52 weeks, but if the year starts on a Thursday or is a leap year that starts on a Wednesday, that particular year will have 53 numbered weeks.

What is week based calendar year?

In a week-based-year, each week belongs to only a single year. Week 1 of a year is the first week that starts on the first day-of-week and has at least the minimum number of days. The first and last weeks of a year may contain days from the previous calendar year or next calendar year respectively.


2 Answers

tl;dr

LocalDate.of( 2015 , 12 , 30 )
         .get ( 
             IsoFields.WEEK_OF_WEEK_BASED_YEAR 
         )

53

…or…

org.threeten.extra.YearWeek.from (
    LocalDate.of( 2015 , 12 , 30 )
)

2015-W53

java.time

Support for the ISO 8601 week is now built into Java 8 and later, in the java.time framework. Avoid the old and notoriously troublesome java.util.Date/.Calendar classes as they have been supplanted by java.time.

These new java.time classes include LocalDate for date-only value without time-of-day or time zone. Note that you must specify a time zone to determine ‘today’ as the date is not simultaneously the same around the world.

ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime now = ZonedDateTime.now ( zoneId );

Or specify the year, month, and day-of-month as suggested in the Question.

LocalDate localDate = LocalDate.of( year , month , dayOfMonth );

The IsoFields class provides info according to the ISO 8601 standard including the week-of-year for a week-based year.

int calendarYear = now.getYear();
int weekNumber = now.get ( IsoFields.WEEK_OF_WEEK_BASED_YEAR );
int weekYear = now.get ( IsoFields.WEEK_BASED_YEAR ); 

Near the beginning/ending of a year, the week-based-year may be ±1 different than the calendar-year. For example, notice the difference between the Gregorian and ISO 8601 calendars for the end of 2015: Weeks 52 & 1 become 52 & 53.

enter image description here

enter image description here

ThreeTen-Extra — YearWeek

The YearWeek class represents both the ISO 8601 week-based year number and the week number together as a single object. This class is found in the ThreeTen-Extra project. The project adds functionality to the java.time classes built into Java.

ZoneId zoneId = ZoneId.of ( "America/Montreal" );
YearWeek yw = YearWeek.now( zoneId ) ;

Generate a YearWeek from a date.

YearWeek yw = YearWeek.from (
    LocalDate.of( 2015 , 12 , 30 )
)

This class can generate and parse strings in standard ISO 8601 format.

String output = yw.toString() ;

2015-W53

YearWeek yw = YearWeek.parse( "2015-W53" ) ;

You can extract the week number or the week-based-year number.

int weekNumber = yw.getWeek() ;
int weekBasedYearNumber = yw.getYear() ;

You can generate a particular date (LocalDate) by specifying a desired day-of-week to be found within that week. To specify the day-of-week, use the DayOfWeek enum built into Java 8 and later.

LocalDate ld = yw.atDay( DayOfWeek.WEDNESDAY ) ;

About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

  • Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
    • Java 9 adds some minor features and fixes.
  • Java SE 6 and Java SE 7
    • Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android
    • Later versions of Android bundle implementations of the java.time classes.
    • For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

like image 68
Basil Bourque Avatar answered Oct 16 '22 21:10

Basil Bourque


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).

like image 26
technophile Avatar answered Oct 16 '22 22:10

technophile