2016-01-11 25 views
9

Le ISO-8601 norma stabilisce cheCalendario Java WEEK_OF_YEAR non conforme a ISO-8601?

"La prima settimana di un anno è la settimana che contiene il primo Giovedi dell'anno (e, quindi, contiene sempre 4 gennaio)."

Il significato della prima settimana dell'anno non è quello che contiene il 1 gennaio ma il primo che contiene almeno quattro giorni nel nuovo anno.

In base a questo lunedì, l'11 gennaio 2016 è la settimana 2. Here is a list of week numbers for 2016.

Ubuntu riflette che nel suo widget tempo:

enter image description here

E il comando cal fa anche:

enter image description here

Oracle supporta con il parametro "IW" di TO_CHAR:

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

Ma Java dice Mon, 11 gennaio 2016 è Settimana # 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 pensa che la prima settimana dell'anno è quello che contiene 1 gennaio.

- Esiste un modo per Java di utilizzare la numerazione settimanale della copia ISO-8601?

+1

È locale specifico. Impostando l'impostazione predefinita 'Locale' su' Locale.UK', ad esempio, viene indicata la settimana corretta, 2. – haraldK

+0

Ma ciò potrebbe modificare altre cose accanto al numero della settimana! –

+0

Sì, vedere la mia risposta sotto per un approccio migliore. :-) – haraldK

risposta

6

Come ho notato nel mio commento, il comportamento predefinito è locale specifico. Alcuni locali ne daranno 3, alcuni daranno 2.

Fortunatamente, è possibile specificare il numero di giorni che devono essere presenti nella prima settimana dell'anno, per un dato Calendar. Come si scrive in precedenza, per l'ISO 8601, questo numero è 4, quindi il seguente codice dovrebbe funzionare:

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

questo dovrebbe rendere l'uscita corretta indipendentemente dal locale.

uscita

prova:

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

tl; dr

myZonedDateTime.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR) 

... e ...

myZonedDateTime.get(IsoFields.WEEK_BASED_YEAR) 

Evita legacy classi data-ora

Come il correct Answer by haraldK spiega il Calendar La definizione della settimana della classe varia in base alla locale. Sebbene sia ben intenzionato, questo è fonte di confusione.

Si dovrebbe evitare Calendar e classi correlate come Date. Ora sono soppiantati dalle classi java.time.

ISO 8601 settimana

Per quanto riguarda ISO 8601 week, essere chiaro che significa:

  • Il primo giorno è Lunedi, che attraversa Domenica.
  • La settimana numero uno di un anno basato sulla settimana contiene il primo giovedì dell'anno solare.
  • Un anno basato sulla settimana ha 52 o 53 settimane.
  • I primi/ultimi giorni di un anno solare possono essere visualizzati nell'anno precedente/successivo della settimana.

java.time

I java.time classi includono un supporto limitato per ISO 8601 standard weeks. Chiamare il metodo get su varie classi, ad esempio LocalDate e ZonedDateTime. Passare le implementazioni TemporalField rilevate come costanti nella classe IsoFields.

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

ThreeTen-Extra

Ancora meglio, aggiungere la libreria ThreeTen-Extra al progetto di utilizzare YearWeek classe.

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

Beware of impostazioni del software di calendario

Mai assumere la definizione di un numero settimana. Assicurati che la fonte di tale numero abbia la stessa definizione di settimana che hai, come la definizione ISO 8601.

Ad esempio, lo standard Calendar app supplied by Apple con macOS ha come valore predefinito una settimana di calendario "gregoriano". Per quanto riguarda ciò che significa, non so come non ho potuto trovare alcuna documentazione sul loro intento/definizione. Per ISO 8601 settimane, è necessario change a setting away from default.


Chi java.time

Il quadro java.time è costruito in Java 8 e versioni successive. Queste classi soppiantano le fastidiose classi di data legacy come java.util.Date, Calendar, & SimpleDateFormat.

Il progetto Joda-Time, ora in maintenance mode, consiglia la migrazione alle classi java.time.

Per ulteriori informazioni, vedere Oracle Tutorial. E cerca Stack Overflow per molti esempi e spiegazioni. La specifica è JSR 310.

Utilizzando un JDBC driver compatibile con JDBC 4.2 o poi, si può scambiare java.time oggetti direttamente con il database. Nessuna necessità di stringhe o classi java.sql. *.

Dove ottenere le classi java.time?

  • Java SE 8, Java SE 9, e più tardi
    • incorporato.
    • Parte dell'API Java standard con un'implementazione in bundle.
    • Java 9 aggiunge alcune funzionalità e correzioni minori.
  • Java SE 6 e Java SE 7
    • Molte delle funzionalità java.time è di back-porting per Java 6 .
  • Android
    • versioni successive di implementazioni fascio Android delle classi java.time.
    • Per Android precedente, il progetto ThreeTenABP si adatta a ThreeTen-Backport (menzionato sopra). Vedi How to use ThreeTenABP….

Il progetto ThreeTen-Extra java.time prolunga con classi aggiuntive. Questo progetto è un terreno di prova per possibili aggiunte future a java.time. È possibile trovare alcune classi utili come Interval, YearWeek, YearQuarter e more.