Разница в расчетах недели года между Java и Python - PullRequest
3 голосов
/ 19 апреля 2011

У меня есть две части моей реализации, одна на Python и одна на Java. Теперь проблема в том, что я понял, что их расчеты номера недели в году не совпадают. Например:

Java-код:

private static int getWeekOfYear(int y, int m, int d) {
    Calendar cal = Calendar.getInstance();
    cal.setMinimalDaysInFirstWeek(4);
    cal.set(y, m, d);
    return cal.get(Calendar.WEEK_OF_YEAR);
}

System.out.println(getWeekOfYear(2010, 7, 1));

Результат Java: 31

Код Python:

print datetime(2010, 7, 1, 0, 0).isocalendar()[1]

Результат Python: 26

Теперь, как мне заставить их быть такими же? Я бы хотел, чтобы Java точно следовала вычислениям Python.

Ответы [ 5 ]

4 голосов
/ 19 апреля 2011

Месяцы в Java основаны на 0, вам необходимо:

cal.set(y, m - 1, d); 

РЕДАКТИРОВАТЬ:

Как отмечает jarnbjo, Calendar должен быть настроен напроизвести номера недели ISO 8601 следующим образом :

cal.setMinimalDaysInFirstWeek(4);    
cal.setFirstDayOfWeek(Calendar.MONDAY);
2 голосов
/ 19 апреля 2011

Проблема с нумерацией нечетных месяцев в Java не является полным решением. Java использует локализованные правила для расчета номера недели (в разных странах действуют разные правила относительно того, какой день недели является первым, а какая - первым в году). Функция Python isocalendar использует правила нумерации недель в соответствии с ISO 8601, который для этих целей определяет, что неделя начинается в понедельник, а 4 января всегда в неделю номер 1.

0 голосов
/ 08 июля 2018

ТЛ; др

LocalDate.of( 2010 , Month.JULY , 1 )
.get ( 
    IsoFields.WEEK_OF_WEEK_BASED_YEAR 
)

26

Подробнее

Как уже отмечалось, ваш аргумент за месяц был неверным из-за сумасшедшего подсчета с нуля, сделанного в этом Calendar классе.

Также отмечалось, что Calendar определение класса "week" варьируется на Locale вместо использования стандартного определения недели ISO 8601 , используемого в вашем коде Python.

java.time

Еще одна проблема: вы используете ужасно хлопотные старые классы даты и времени, связанные с самой ранней версией Java. Теперь они унаследованы, заменены классами java.time .

Для значения только для даты, без времени суток и без часового пояса, используйте LocalDate. Используйте удобное перечисление Month для удобства чтения.

LocalDate ld = LocalDate.of( 2010 , Month.JULY , 1 ) ;

Или используйте номер месяца, с нормальной цифрой 1-12 для января-декабря.

LocalDate ld = LocalDate.of( 2010 , 7 , 1 ) ;

Рассчитать стандарт ISO 8601 номер недели . Используйте метод LocalDate::get для доступа к соответствующему значению. Передайте элемент enum IsoFields.WEEK_OF_WEEK_BASED_YEAR, чтобы указать желаемое значение.

int w = ld.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR ) ;

YearWeek

Совет: Если вы много работаете с этой неделей года, вам может пригодиться класс YearWeek, который можно найти в ThreeTen-Extra проект.

YearWeek yw = YearWeek.from( ld ) ;

О java.time

Фреймворк java.time встроен в Java 8 и более поздние версии. Эти классы заменяют проблемные старые устаревшие классы даты и времени, такие как java.util.Date, Calendar, & SimpleDateFormat.

Проект Joda-Time , теперь в режиме обслуживания , рекомендует выполнить переход на классы java.time .

Чтобы узнать больше, см. Oracle Tutorial . И поиск переполнения стека для многих примеров и объяснений. Спецификация JSR 310 .

Вы можете обмениваться java.time объектами напрямую с вашей базой данных. Используйте драйвер JDBC , совместимый с JDBC 4.2 или более поздней версии. Нет необходимости в строках, нет необходимости в java.sql.* классах.

Где получить классы java.time?

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Здесь вы можете найти некоторые полезные классы, такие как Interval, YearWeek, YearQuarter и more .

0 голосов
/ 19 апреля 2011

В Java 7 - это не июль, а август.

0 голосов
/ 19 апреля 2011

Проверьте Javadoc для метода set.Вы увидите следующее:

Параметры:

year - значение, используемое для установки поля календаря YEAR.

month - значение, используемое для установкиМЕСЯЦ календарное поле.Значение месяца основано на 0.например, 0 для января.

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

Таким образом, ваш код должен стать следующим:

private static int getWeekOfYear(int y, int m, int d) {     
    Calendar cal = Calendar.getInstance();     
    cal.setMinimalDaysInFirstWeek(4);     
    cal.set(y, m - 1, d);     // Note the change here
    return cal.get(Calendar.WEEK_OF_YEAR); 
} 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...