Недельные вычисления SimpleDateFormat - PullRequest
8 голосов
/ 20 июля 2011

Я получаю некоторые удивительные результаты с SimpleDateFormat и надеюсь, что кто-то может пролить свет на эту проблему.Вывод:

Time          = Mon Dec 27 00:00:00 PST 2010
2010-01 <--- THIS IS WHAT I DON'T UNDERSTAND
Start of week = Sun Dec 26 00:00:00 PST 2010
2010-01
End of Week   = Sat Jan 01 23:59:59 PST 2011
2011-01

Должен ли я рассматривать последнюю «неделю» года, которая распространяется на следующий год, как особый случай?Или это правильный способ интерпретировать это?Очевидно, что при попытке организовать неделю последовательно, порядок неверен.При корректировке начальных значений 25 декабря 2005 года считается 53-й неделей.Я еще не смотрел на Joda, чтобы увидеть, дает ли Joda похожие результаты.

Соответствующий код:

private static Date getStartOfWeek( Date d ) {
  Calendar calendar = Calendar.getInstance();
  calendar.clear();
  calendar.setTime( d );

  calendar.set( Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek() );

  return calendar.getTime();  
}

private static Date getEndOfWeek( Date d ) {
  Calendar calendar = Calendar.getInstance();
  calendar.clear();

  calendar.setTime( d );
  calendar.add( Calendar.WEEK_OF_YEAR, 1 );
  calendar.set( Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek() );
  calendar.add( Calendar.MILLISECOND, -1 );

  return calendar.getTime();
}


Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.set( 2010, Calendar.DECEMBER, 27 );
Date d = calendar.getTime();
Date start = getStartOfWeek( d );
Date end = getEndOfWeek( d );
SimpleDateFormat fmt = new SimpleDateFormat( "yyyy-ww" );

System.out.println( "Time          = " + d );
System.out.println( fmt.format( d ) );
System.out.println( "Start of week = " + start );
System.out.println( fmt.format( start ) );
System.out.println( "End of Week   = " + end );
System.out.println( fmt.format( end ) );

Справочная информация: я нашел это при использовании кросс-таблицы (дата сгруппирована по неделям)в JasperReports.

РЕДАКТИРОВАТЬ: Я использую JDK 1.6.0_25

РЕДАКТИРОВАТЬ: Кажется, мне придется использовать Joda, чтобы получить правильный результат.Чтобы получить начало / конец недели, я использовал: LocalDate.withDayOfWeek.Чтобы получить номер года и недели, я использовал DateTime.getWeekyear и DateTime.getWeekOfWeekyear.

Ответы [ 4 ]

15 голосов
/ 20 июля 2011

Ошибка в вашем коде форматирования, а не в Java.

Удивительное поведение связано с эзотерическим правилом в нотации даты.Обратите внимание, что ISO 8601 (довольно запутанно) устанавливает разные правила для границ года при использовании номеров недели.В частности, 2010-12-27 считается частью 2011 года при использовании номеров недели.

В результате вы должны использовать «год недели» YYYY вместо обычного года yyyy.(См. http://download.oracle.com/javase/7/docs/api/java/util/GregorianCalendar.html#week_year и последний пример в http://download.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html.)

Кроме того, стандартная запись для дат использует явный 'W', поэтому вместо него следует использовать new SimpleDateFormat( "YYYY-'W'ww" ).

Редактировать: есть еще одна проблема. Кажется, по умолчанию в Java нестандартный calendar.getMinimalDaysInFirstWeek() == 1, поэтому вам нужно установить

calendar.setMinimalDaysInFirstWeek( 4 );

, чтобы получить правильный год.

Редактировать:При чтении Calendar javadocs вам, возможно, также потребуется установить начальный день на понедельник. Кроме того, спецификатор формата YYYY кажется новым в Java 1.7. В свете этого, если вы не 'Желая перейти на предварительную версию Java, я рекомендую просто использовать Joda Time.

2 голосов
/ 20 июля 2011

С Неделя ИСО

Первая неделя года - это неделя, в которой содержится первый четверг года.поведение не имеет ничего общего с Java или Joda.Вот как «неделя года» реализуется во всем мире (если они соответствуют стандарту ISO)

1 голос
/ 20 июля 2011

классы даты и времени standadr java плохо разработаны и иногда не работают должным образом.используйте вместо этого Joda Time

0 голосов
/ 20 июля 2011

Да, это похоже на ошибку в Java, а не в коде форматирования.Если вы печатаете:

System.out.println("Week = " + calendar.get(Calendar.WEEK_OF_YEAR));

Также отображается 1.

Если вы измените дату на что-то не очень близкое к концу года, например:

calendar.set(2010, Calendar.NOVEMBER, 27);

Тогда вывод выглядит правильно.Кстати, я тестировал с использованием Sun 1.6.0_25 64bit VM.

...