Как рассчитать дату из номера недели ISO8601 в Java

3 ответов


UPDATE: концепции, представленные здесь, по-прежнему применяются, но код устарел. The Joda Времени, теперь режим обслуживания, советует миграцию в java.время классы. См.Java.код времени в ответ Szulc.

Короткий Ответ:

DateTime dateTimeStart = new DateTime( "2003-W01-1", DateTimeZone.UTC ); // Joda-Time 2.4.
DateTime dateTimeStop = dateTimeStart.plusWeeks( 1 );

Подробнее читайте дальше.

избегайте j.u.Дата

старая java.утиль.Дата и java.утиль.Классы календаря в комплекте с Java, как известно, хлопотно и следует избегать. Sun и ее партнеры поместили много аккуратных вещей в библиотеки Java, но не все из них хороши. Хуже всего, наверное, занятия по датам и времени.

кроме того эти классы имеют слабую поддержку ISO 8601 недели. См.ответ для сведения.

правила недели ISO

вы могли бы написать свой собственный код, используя эти классы, но я не рекомендую это. Правила расчет ISO недель достаточно прост:

  • неделя 1 имеет первый четверг календарного года.
  • понедельник-первый день недели.

Joda Времени

на их месте общей заменой является библиотека под названием Joda Времени. Эта библиотека включает отличную поддержку ISO недель.

просто добавить в свой проект, просто добавьте один .

Другой Пример Код

посмотреть этот другой мой ответ или этот например, код для получения даты-времени из номера недели ISO.

java.время

Java 8 имеет новую структуру даты и времени, вдохновленную Joda-Time, найденную в java.time пакета.

Добавление Библиотеки

Java построен для смешивания библиотек вместе. Это одна из основных целей объектно-ориентированного программирования и поздней привязки. Этот комментарии к вашему вопросу относятся к слишком распространенной ситуации, когда боссы иррационально или невежественно запрещают добавлять библиотеки. Хотя есть веские причины для такого запрета, они редки.

запрещение добавления библиотек и банок на Java похоже на запрещение подключения прицепов к автопарку, оборудованному сцепкой.

старые классы даты-времени действительно достаточно плохи, что многие из нас добавляют Joda-Time к большинству новых проектов в качестве привычка.

Полуоткрытых

в работе с датой и временем общим способом определения промежутка времени является "полуоткрытый" подход. Это означает начало включено в эксклюзивные. Итак, стандартная неделя начинается в первый момент понедельника и заканчивается в первый момент следующего понедельника. Поиск StackOverflow.com для большего обсуждения и примеров.

Diagram of Half-Open approach to defining a week, going from start of Day 1 to start of Day 8

текстовое представление недели ISO

ISO 8601 стандарт определяет способы представляем стандартную неделю и даже день в течение этой недели.

возьмите год, дефис,W разделитель, а номер недели представляет всю неделю:YYYY-Www. Добавьте дефис и номер дня недели, чтобы точно указать день в течение этой недели:YYYY-Www-D.

Joda-Time понимает этот формат, как показано в примере кода ниже.

Пример Кода

вот некоторый код Joda-Time 2.4. Поиск StackOverflow.com для обсуждения и примеров этих концепций. Этот вопрос и этот ответ в значительной степени дублируют многие другие.

int year = 2003;
int week = 1; // Domain: 1 to 53.

// Build a String in ISO 8601 Week format: YYYY-Www-D
// Hard-coding a `1` for Monday, the standard first-day-of-week.
String input = ( String.format( "%04d", year ) + "-W" + String.format( "%02d", week ) + "-1" );

// Specify the time zone by which to define the beginning of a day.
DateTimeZone timeZone = DateTimeZone.UTC; // Or: DateTimeZone.forID( "America/Montreal" );

// Calculate beginning and ending, using Half-Open (inclusive, exclusive) approach.
DateTime dateTimeStart = new DateTime( input, timeZone );
DateTime dateTimeStop = dateTimeStart.plusWeeks( 1 );

// Use Joda-Time's tidy Interval class to represent the entire week. Use getters to access start and stop.
Interval weekInterval = new Interval( dateTimeStart, dateTimeStop );

// Is today in that week? Joda-Time has handy methods: contains, isBefore, isAfter, overlap.
boolean isTodayInThatWeek = weekInterval.contains( DateTime.now() );

дамп в консоли.

System.out.println( "input: " + input );
System.out.println( "dateTimeStart: " + dateTimeStart );
System.out.println( "dateTimeStop: " + dateTimeStop );
System.out.println( "interval: " + interval );
System.out.println( "isTodayInThatWeek: " + isTodayInThatWeek );

при запуске.

input: 2003-W01-1
dateTimeStart: 2002-12-30T00:00:00.000Z
dateTimeStop: 2003-01-06T00:00:00.000Z
interval: 2002-12-30T00:00:00.000Z/2003-01-06T00:00:00.000Z
isTodayInThatWeek: false

Java 8 / java.время пути

в Java 8, вы можете использовать TemporalField в сочетании с LocalDate:: with (TemporalField, long) метод для получения недели недели на основе года и TemporalAdjuster в сочетании с LocalDate:: with (TemporalAdjuster) метод перехода к требуемому дню недели, например:

final int weekNumber = 34;
LocalDate weekByNumber = date.with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, weekNumber);

final TemporalAdjuster adjuster = TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY);
LocalDate mondayOfWeekByNumber = weekByNumber.with(adjuster);

LocalDate date = 
  LocalDate.parse("2015 53", 
     new DateTimeFormatterBuilder().appendPattern("YYYY w")
    .parseDefaulting(WeekFields.ISO.dayOfWeek(), 1)
    .toFormatter()));