Почему номера недель SQL Server отличаются от номеров недель Java? - PullRequest
3 голосов
/ 01 февраля 2012

Я работаю над системой отчетов, использующей Java 6 и SQL Server 2008. Для некоторых запросов я хочу посмотреть данные по номеру недели. Я использую Java, чтобы заполнить пробелы в данных, чтобы сделать непрерывную временную линию, и я обнаружил, что

java.util.Calendar cal = new java.util.GregorianCalendar();
cal.set(2012, 0, 1);
cal.get(Calendar.WEEK_OF_YEAR);

и

org.joda.time.DateTime date = new org.joda.time.DateTime(2012, 01, 01, 0, 0);
date.getWeekOfWeekyear();

вернуть другой номер недели на

DATEPART(WEEK, '2012-01-01')

Есть ли подход к устранению этой разницы, или мне придется выбрать использование SQL Server или Номера Java-недель?

ТИА

Ответы [ 5 ]

6 голосов
/ 01 февраля 2012

Java более сложна, когда дело доходит до вычисления номеров недель, тогда как SQL-Server DATEPART (WEEK ... более прост. Я обнаружил следующее задокументированное здесь

"При настройкеили получая поля WEEK_OF_MONTH или WEEK_OF_YEAR, Календарь должен определить первую неделю месяца или года в качестве ориентира. Первая неделя месяца или года определяется как самый ранний семидневный период, начинающийся с getFirstDayOfWeek () и содержащий как минимум getMinimalDaysInFirstWeek() "

Я думаю, что по умолчанию это стандарты ISO , которые являются первой неделей года с четвергом (недели с понедельника по воскресенье, где по крайней мере 4 днягод). Рассмотрите возможность использования:

В SQL Server функция DATEPART(WEEK, ..) намного проще, она просто вычисляет количество границ недели (как определено DATEFIRST) между первым января,и дата ввода, поэтому 1 января всегда будет неделей 1. Вы можете рассмотреть возможность использования:

SELECT DATEPART(ISO_WEEK, '01/01/2012')

Получается номер недели, определенный стандартами ISO , который является первой неделей в году с четвергом (недели с понедельника по воскресенье, когда по меньшей мере 4 дня являютсягод).

Поскольку, как указано, SQL Server более прост в вычислениях, его нельзя настроить, а это значит, что вам нужно будет настроить номера недель в Java.Просто убедитесь, что вы настроили свой календарь на Java с правильными значениями для getFirstDayOfWeek() и getMinimalDaysInFirstWeek():

public static Calendar getISOCalendar() {
    Calendar calendar = Calendar.getInstance();
    calendar.setMinimalDaysInFirstWeek(4);
    calendar.setFirstDayOfWeek(Calendar.MONDAY);
    return calendar;
}

Тогда вы сможете гарантировать постоянные номера недель.

public static void main(String args[]) {
    Calendar calendar = getISOCalendar();
    calendar.set(2012,0,1);
    System.out.println(calendar.get(Calendar.WEEK_OF_YEAR));
}

------
52
1 голос
/ 01 февраля 2012

В соответствии с их документами, java.util.calendar , joda и DATEPART все возвращают целое число от 1 до 53, обозначающее неделю. Это значение основано на том, что определено как первый день недели и календарь по умолчанию (например, григорианский, китайский). Я бы проверил ваши значения по умолчанию или увидел, что каждый из них считает первым днем ​​недели.

0 голосов
/ 19 октября 2016

ТЛ; др

int iso8601WeekNumber = 
    ZonedDateTime.now( ZoneId.of ( "America/Montreal" ) )
        .get( IsoFields.WEEK_OF_WEEK_BASED_YEAR )

Множество определений недели

Есть много определений недели.

Для некоторых людей первый день недели - воскресенье, для других - понедельник, а для некоторых - другой день.

Для некоторых людей первая неделя года содержит 1 января, в то время как другие люди считают первую неделю той, которая содержит день начала недели, упомянутый выше, в то время как другие считают первую неделю как определенную дату дня. -неделю.

Так что никогда не следует понимать значение «недели» или «номера недели» без изучения документации.

Избегайте устаревших классов даты и времени

В общем, вам следует избегать старых устаревших классов даты и времени, связанных с ранними версиями Java, поскольку они плохо спроектированы, сбивают с толку и создают проблемы.

Здесь, в частности, класс java.util.Calendar имеет определение недели, которое варьируется в зависимости от локали. Так что не используйте это, если вам нужны надежные постоянные результаты.

ISO 8601

Стандарт ISO 8601 определяет форматы и связанные с ними вопросы для значений даты и времени. специально определяет значение недели и недели года:

  • Неделя начинается с понедельника по воскресенье с номерами 1-7, где понедельник = 1.
  • Неделя № 1 содержит первый четверг года, дающий 52 или 53 недели в год.

Joda-Time

Библиотека Joda-Time использует стандартное определение недели и недели года ISO 8601 .

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

java.time

В классах java.time используется определение недели: ISO 8601 : неделя № 1 имеет первый четверг, а неделя - понедельник-воскресенье.

Класс IsoFields определяет недельный год. Мы можем попросить:

Сначала мы получаем текущую дату и время.

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

Опросить этот объект даты-времени, спрашивая о стандартном недельном году.

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

Дамп на консоль.

System.out.println ( "now: " + now + " is week: " + week + " of weekYear: " + weekYear );

сейчас: 2016-01-17T20: 55: 27.263-05: 00 [Америка / Монреаль] - неделя: 2 неделиГод: 2016

Для получения дополнительной информации см. Аналогичный вопрос: Как вычислить дату из номера недели ISO8601 в Java .

WeekFields

В java.time вы также можете вызвать класс WeekFields, например, WeekFields.ISO.weekBasedYear(). Должен иметь тот же эффект, что и IsoFields в более поздних версиях Java 8 или новее (некоторые ошибки были исправлены в более ранних версиях Java 8).


О java.time

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

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

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

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

  • Java SE 8 и SE 9 и более поздние
    • Встроенный.
    • Часть стандартного Java API со встроенной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и SE 7
    • Большая часть функциональности java.time перенесена на Java 6 и 7 в ThreeTen-Backport .
  • Android

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

0 голосов
/ 07 сентября 2012
   System.out.println("get date range from week number and year in java");
   System.out.println(); // print a blank line

   // get the input from the user
   Scanner sc = new Scanner(System.in);

   System.out.print("Enter the week : ");
   int weekNumber  = sc.nextInt(); 
   System.out.print("Enter the Year: ");
   int year = sc.nextInt() ;



   Calendar cal = Calendar.getInstance();
   //cal.setTime(new Date());

   cal.set(Calendar.YEAR, year);
   cal.set(Calendar.WEEK_OF_YEAR, weekNumber);

   SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");

   cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
   System.out.println(formatter.format(cal.getTime())); // start date

   cal.add(Calendar.DAY_OF_WEEK, 6);
   System.out.println(formatter.format(cal.getTime())); // end date
0 голосов
/ 01 февраля 2012

Я думаю, что это может иметь какое-то отношение к 2011 году, и идея о том, что у него 53 недели, согласно SQLServer. Глядя на проблемы SQL в январе / новогоднем году! , это решение может помочь лучше справляться с SQLServer:

DATEPART(WEEK, DATEADD(WEEK, -1, '2012-01-01'))

...