2016-01-11 66 views
9

ISO-8601 standardowe stwierdza, że ​​Kalendarz Java WEEK_OF_YEAR nie jest zgodny z ISO-8601?

„Pierwszym tygodniem roku jest tydzień zawierający pierwszy czwartek roku (i, co za tym idzie, zawsze zawiera 4 stycznia).”

Znaczenie pierwszego tygodnia w roku to nie ten, który zawiera 1 stycznia, ale pierwszy, który zawiera po 4 dniach nowego roku.

Zgodnie z tym pon, 11 stycznia 2016 r. Jest w tygodniu # 2. Here is a list of week numbers for 2016.

Ubuntu odzwierciedla fakt, że w jego widgecie czasu:

enter image description here

a komenda cal robi także:

enter image description here

Oracle wspiera go z "IW" parametr TO_CHAR:

> select to_char(to_date('11/01/2016','dd/mm/yyyy'),'iw') weekno from dual; 
> WEEKNO 
    02 

Ale Java mówi Pon 11 stycznia 2016 tydzień # 3

Calendar c = Calendar.getInstance(); 
System.out.println(c.getTime()); 
System.out.println(c.get(Calendar.WEEK_OF_YEAR)); 

Output: 
Mon Jan 11 09:02:35 VET 2016 
3 

Java uważa, że ​​pierwszy tydzień roku to taka, która zawiera stycznia 1st.

- Czy istnieje sposób, aby Java mogła korzystać z numeracji tygodniowej zgodnej z normą ISO-8601?

+1

Jest specyficzny dla ustawień regionalnych. Ustawienie na przykład domyślnego 'Locale' na' Locale.UK', daje prawidłowy tydzień, 2. – haraldK

+0

Ale to zmieniłoby inne rzeczy oprócz numeru tygodnia! –

+0

Tak, zobacz poniżej moją odpowiedź na lepsze podejście. :-) – haraldK

Odpowiedz

6

Jak zauważyłem w swoim komentarzu, domyślne zachowanie jest specyficzne dla ustawień regionalnych. Niektóre lokalizacje dadzą 3, niektóre dadzą 2.

Na szczęście możesz określić liczbę dni, które muszą być obecne w pierwszym tygodniu roku, dla danego Calendar. Jak piszesz powyżej, ISO 8601, liczba ta jest 4, więc następujący kod powinien działać:

Calendar c = Calendar.getInstance(); 
c.setMinimalDaysInFirstWeek(4); // For ISO 8601 
System.out.println(c.getTime()); 
System.out.println(c.get(Calendar.WEEK_OF_YEAR)); 

To powinno sprawić, że wyjście prawidłowe, niezależnie od lokalizacji.

wyjściowe

Test:

Mon Jan 11 14:54:22 CET 2016 
2 
0

tl; dr

myZonedDateTime.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR) 

... i ...

myZonedDateTime.get(IsoFields.WEEK_BASED_YEAR) 

Unikaj klas date-time legacy

Jako correct Answer by haraldK wyjaśnia Calendar Definicja klasy tygodnia różni się w zależności od ustawień narodowych. Chociaż ma dobre intencje, jest to mylące.

Powinieneś unikać Calendar i powiązanych klas, takich jak Date. Są teraz wypierane przez klasy java.time.

ISO 8601 tydzień

chodzi o ISO 8601 week, być jasne, że oznacza:

  • Pierwszy dzień to poniedziałek, przebiegającej przez niedzielę.
  • Tydzień numer jeden w tygodniu zawiera pierwszy czwartek roku kalendarzowego.
  • Tygodniowy rok ma 52 lub 53 tygodnie.
  • Pierwsze/ostatnie kilka dni w roku kalendarzowym może pojawić się w roku poprzedzającym/przyszłym.

java.time

W java.time klas obejmują między innymi wsparcie dla ISO 8601 standard weeks. Wywołaj metodę get na różnych klasach, takich jak LocalDate i ZonedDateTime. Przekaż implementacje TemporalField znalezione jako stałe w klasie IsoFields.

int week = myZonedDateTime.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR) ; 
int weekBasedYear = myZonedDateTime.get(IsoFields.WEEK_BASED_YEAR) ; 

ThreeTen-Extra

Jeszcze lepiej, dodać bibliotekę ThreeTen-Extra do projektu użyć YearWeek klasę.

org.threeten.extra.YearWeek yw = YearWeek.from(myZonedDateTime) ; 

Strzeż ustawień oprogramowania kalendarzowych

Nigdy nie zakładaj definicję numerem tygodnia. Upewnij się, że źródło takiej liczby ma taką samą definicję tygodnia jak Ty, takie jak definicja ISO 8601.

Na przykład: Calendar app supplied by Apple z macOS domyślnie przyjmuje definicję kalendarza "gregoriańskiego" z tygodnia. Co do tego, co to oznacza, nie wiem, ponieważ nie mogłem znaleźć żadnej dokumentacji na temat ich intencji/definicji. Dla ISO 8601 tygodni, musisz change a setting away from default.


O java.time

Ramy java.time jest wbudowana w Java 8 i późniejszych. Te klasy zastępują kłopotliwe stare klasy dat-czasu, takie jak java.util.Date, Calendar, & SimpleDateFormat.

Projekt Joda-Time, teraz w maintenance mode, zaleca migrację do klas java.time. Aby uzyskać więcej informacji, zobacz

. I wyszukaj Stack Overflow dla wielu przykładów i objaśnień. Specyfikacja to JSR 310.

Używanie JDBC driver zgodny z JDBC 4.2 lub później, można wymieniać java.time obiekty bezpośrednio z bazy danych. Nie ma potrzeby ciągi ani klas java.sql. *.

Gdzie można uzyskać lekcje java.time?

  • Java SE 8, Java SE 9, a później
    • wbudowanej.
    • Część standardowego interfejsu API języka Java z pakietem implementacji.
    • Java 9 dodaje kilka drobnych funkcji i poprawek.
  • Java SE 6 i Java SE 7
    • Znaczna część funkcjonalności java.time jest back-przeniesiony do Java 6 & 7 w ThreeTen-Backport.
  • Android
    • Późniejsze wersje Androida wdrożeń wiązce klas java.time.
    • Dla wcześniejszego systemu Android projekt ThreeTenABP dostosowuje ThreeTen-Backport (wymieniony powyżej). Zobacz How to use ThreeTenABP….

Projekt ThreeTen-Extra rozciąga java.time z dodatkowych zajęć. Ten projekt jest poligonem wskazującym na możliwe przyszłe dodatki do java.time. Możesz znaleźć tutaj kilka użytecznych klas, takich jak Interval, YearWeek, YearQuarter i more.