Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why dec 31 2010 returns 1 as week of year?

For instance:

Calendar c = Calendar.getInstance();
DateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
c.setTime( sdf.parse("31/12/2010"));
out.println( c.get( Calendar.WEEK_OF_YEAR ) );  

Prints 1

Same happens with Joda time.

:)

like image 984
OscarRyz Avatar asked Jan 05 '11 19:01

OscarRyz


3 Answers

The definition of Week of Year is Locale dependent.

How it is defined in US is discused in the other posts. For example in Germany (DIN 1355-1 / ISO 8601): the first Week* of Year is the first week with 4 or more days in the new year.

*first day of week is Monday and last day of week is Sunday

And Java’s Calendar pays attention to the locale. For example:

public static void main(String[] args) throws ParseException {

    DateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
    Date lastDec2010 = sdf.parse("31/12/2010");

    Calendar calUs = Calendar.getInstance(Locale.US);       
    calUs.setTime(lastDec2010);

    Calendar calDe = Calendar.getInstance(Locale.GERMAN);       
    calDe.setTime(lastDec2010);

    System.out.println( "us: " + calUs.get( Calendar.WEEK_OF_YEAR ) ); 
    System.out.println( "de: " + calDe.get( Calendar.WEEK_OF_YEAR ) );
}

prints:

us: 1
de: 52

ADDED For the US (and I can think of that it is the same for Mexico) the 1. Week of Year is the week where the 1. January belongs to. -- So if 1. Januar is a Saturday, then the Friday before (31. Dec) belongs the same week, and in this case this day belongs to the 1. Week of Year 2011.

like image 111
Ralph Avatar answered Nov 04 '22 23:11

Ralph


Values calculated for the WEEK_OF_YEAR field range from 1 to 53. Week 1 for a year is the earliest seven day period starting on getFirstDayOfWeek() that contains at least getMinimalDaysInFirstWeek() days from that year. It thus depends on the values of getMinimalDaysInFirstWeek(), getFirstDayOfWeek(), and the day of the week of January 1. Weeks between week 1 of one year and week 1 of the following year are numbered sequentially from 2 to 52 or 53 (as needed).

To determine if that week is the last week of 2010 or the first of 2011 Java uses getMinimalDaysInFirstWeek javadoc. If that method returns 7 then the first week in which all the days in the week are of the same year is week one, if it returns 1 then the first week with any days of the next year is the first week of the next year.

In this case the first of January in 2011 is on a Saturday so it is considered the first week of 2011 as long as you would like a week with one day to be considered already the first week of the next year, if you don't then do:

Calendar c = Calendar.getInstance();
c.setMinimalDaysInFirstWeek(7);//anything more than 1 will work in this year
DateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
c.setTime( sdf.parse("31/12/2010"));
System.out.println( c.get( Calendar.WEEK_OF_YEAR ) ); 

returns:

52
like image 11
Adam Avatar answered Nov 04 '22 22:11

Adam


tl;dr

java.time.LocalDate.parse( 
    "31/12/2010" , 
    DateTimeFormatter.ofLocalizedDate( FormatStyle.SHORT ).withLocale( Locale.UK )  
)      
.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR )

52

Or, add a library, and then…

org.threeten.extra.YearWeek.from(     // Convert from a `LocalDate` object to a `YearWeek` object representing the entire week of that date’s week-based year.
    java.time.LocalDate.parse( "31/12/2010" , DateTimeFormatter.ofLocalizedDate( FormatStyle.SHORT ).withLocale( Locale.UK )  
).getWeek()                           // Extract an integer number of that week of week-based-year, either 1-52 or 1-53 depending on the year.

52

java.time

As others noted, the definition of a week varies by Locale in the old java.util.Calendar class.

That troublesome class, and its partner java.util.Date, have been supplanted by the java.time framework built into Java 8 and later.

The IsoFields class defines a week using the ISO 8601 standard: Week always starts on a Monday, and week # 1 holds the first Thursday of the calendar-year.

Get the current moment.

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

Ask about the standard week-based year.

int week = now.get ( IsoFields.WEEK_OF_WEEK_BASED_YEAR );
int weekYear = now.get ( IsoFields.WEEK_BASED_YEAR );

Standard week definition

There are many ways to define “a week” and “first week of the year”.

However, there is one major standard definition: the ISO 8601 standard. That standard defines weeks of the year, including the first week of the year.

the week with the year's first Thursday

A standard weeks begins with Monday and ends with Sunday.

Week # 1 of a week-based year has the first Thursday of the calendar year.

The java.time classes support the ISO 8601 week through the IsoFields class, holding three constants that implement TemporalField:

  • WEEK_OF_WEEK_BASED_YEAR
  • WEEK_BASED_YEAR
  • WEEK_BASED_YEARS

Call LocalDate::get to access the TemporalField.

LocalDate ld = LocalDate.parse( "2010-12-31" ) ;
int weekOfWeekBasedYear = ld.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR ) ;
int yearOfWeekBasedYear = ld.get( IsoFields.WEEK_BASED_YEAR ) ;

ld.toString(): 2010-12-31

weekOfWeekBasedYear: 52

yearOfWeekBasedYear: 2010

ISO 8601 string format

The ISO 8601 standard defines a textual format as well as a meaning for week-based-year values: yyyy-Www. For a specific date, add day-of-week numbered 1-7 for Monday-Sunday: yyyy-Www-d.

Construct such a string.

String outputWeek = String.format( "%04d" , yearOfWeekBasedYear ) + "-W" + String.format( "%02d" , weekOfWeekBasedYear ) ;
String outputDate = outputWeek + "-" + ld.getDayOfWeek().getValue() ;

2010-W52-5

YearWeek

This work is much easier if you add the ThreeTen-Extra library to your project. Then use the YearWeek class.

YearWeek yw = YearWeek.from( ld ) ;  // Determine ISO 8601 week of a `LocalDate`. 

Generate the standard string.

String output = yw.toString() ;

2010-W52

And parse.

YearWeek yearWeek = YearWeek.parse( "2010-W52" ) ;  

yearWeek.toString(): 2010-W52

Determine a date. Pass a java.time.DayOfWeek enum object for day-of-week Monday-Sunday.

LocalDate localDate = yw.atDay( DayOfWeek.MONDAY ) ;

localDate.toString(): 2010-12-27

I strongly recommending adding this library to your project. Then you can pass around smart objects rather than dumb ints. Doing so makes your code more self-documenting, provides type-safety, and ensures valid values.


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.

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

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

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

Where to obtain the java.time classes?

  • Java SE 8, Java SE 9, and later
    • Built-in.
    • 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
    • Much 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, 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.


For much more detail, see my Answer on the similar Question:

  • java get week of year for given a date

…and see my Answer on the similar Question:

  • How to calculate Date from ISO8601 week number in Java
like image 4
Basil Bourque Avatar answered Nov 05 '22 00:11

Basil Bourque