Несоответствие в библиотеке дат Java для недели года - PullRequest
0 голосов
/ 23 октября 2018

Согласно https://en.wikipedia.org/wiki/ISO_8601#Week_dates, Будни начинаются в понедельник.Но из Java, если вы попытаетесь извлечь номер недели двумя разными способами, вы получите два разных результата, если дата воскресенье.

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;

public class TestDate {
    public static void main(String[] args) throws ParseException {
        final SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        final SimpleDateFormat weekFormatter = new SimpleDateFormat("ww");
        String date = "2018-10-21";
        System.out.println(weekFormatter.format(formatter.parse(date)));
        Calendar calendar = Calendar.getInstance();
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        calendar.setTime(formatter.parse(date));
        System.out.println(calendar.get(Calendar.WEEK_OF_YEAR));
    }
}

Вывод:

43
42

Это несоответствие?

Это всего лишь тестовая программа, которую я написал, чтобы воспроизвести проблему. Я заметил проблему в Hive, например:

0: jdbc:hive2://zk0-something> select from_unixtime(t, 'ww'), weekofyear(from_unixtime(t, 'yyyy-MM-dd')) from (select 1540122033 as t) a;
+------+------+--+
| _c0  | _c1  |
+------+------+--+
| 43   | 42   |
+------+------+--+
1 row selected (0.388 seconds)
0: jdbc:hive2://zk0-something>

1 Ответ

0 голосов
/ 23 октября 2018

java.time

    String date = "2018-10-21";
    LocalDate ld = LocalDate.parse(date);
    int weekOfYear = ld.get(WeekFields.ISO.weekOfYear());
    System.out.println(weekOfYear);

Вывод:

42

Так как вас интересует ISO 8601 правила для номеров недели , используйте WeekFields.ISO для получения связанных с неделей данных из LocalDate.Вы также можете использовать форматер , если хотите:

    DateTimeFormatter weekFormatter = DateTimeFormatter.ofPattern("ww", Locale.FRANCE);
    System.out.println(ld.format(weekFormatter));

Вывод такой же:

42

локаль, переданная в DateTimeFormatter.ofPattern, определяет схему недели.Если вместо этого я передам Locale.US, я получу 43.

Я рекомендую вам использовать java.time, современный Java-интерфейс даты и времени, и держаться подальше от старых классов даты и временикак SimpleDateFormat и Calendar.Старые были плохо спроектированы, а с современными гораздо приятнее работать.

Что пошло не так в вашем коде?

И устаревший класс SimpleDateFormat, и современный DateTimeFormatterих схема нумерации по неделям из их региона.Если для форматера не указан языковой стандарт, он использует языковой стандарт по умолчанию для JVM.Так, например, если у JVM есть американская локаль, в первом примере программа форматирования напечатает 43, потому что в США воскресенье 21 октября этого года было на неделе 43. Если локаль французская, будет напечатано 42, потому что этот день был на неделе.42 во Франции.Франция следует стандарту ISO 8601, США - нет.

В вашем примере установка первого дня недели Calendar на понедельник приводит к тому, что номер недели будет 42, как вы ожидали.Однако это не всегда так.Номера недель определяются не только первым днем ​​недели, но и определением недели 1. По вашей ссылке:

Первая неделя ISO в году может иметь до трех дней, которыефактически в григорианском календарном году, который заканчивается;если они понедельник, вторник и среда.Аналогично, последняя неделя ISO в году может иметь до трех дней, которые фактически находятся в григорианском календарном году, который начинается;если они пятница, суббота и воскресенье.Четверг каждой недели ISO всегда совпадает с григорианским календарным годом, обозначаемым годом нумерации недели ISO.

Американское определение недели недели отличается: в США 1 января всегдана неделе 1. Поэтому, если ваш Calendar создан с американским языком, установка его первого дня недели на понедельник не является достаточной, чтобы следовать правилам ISO 8601.По совпадению, для 2018 года номера недель совпадают, хотя.

...