Perché il 31 dicembre 2010 restituisce 1 come settimana dell’anno?

Per esempio:

Calendar c = Calendar.getInstance(); DateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); c.setTime( sdf.parse("31/12/2010")); out.println( c.get( Calendar.WEEK_OF_YEAR ) ); 

Stampa 1

Lo stesso succede con il tempo di Joda.

🙂

La definizione di Settimana dell’anno dipende dalle Locale .

Come è definito negli Stati Uniti è discusso negli altri post. Per esempio in Germania ( DIN 1355-1 / ISO 8601 ): la prima settimana * dell’anno è la prima settimana con 4 o più giorni nel nuovo anno.

* Il primo giorno della settimana è lunedì e l’ultimo giorno della settimana è domenica

E il Calendar di Java presta attenzione alle impostazioni locali. Per esempio:

 public static void main(String[] args) throws ParseException { DateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); Date lastDec2010 = sdf.parse("31/12/2010"); Calendar calUs = Calendar.getInstance(Locale.US); calUs.setTime(lastDec2010); Calendar calDe = Calendar.getInstance(Locale.GERMAN); calDe.setTime(lastDec2010); System.out.println( "us: " + calUs.get( Calendar.WEEK_OF_YEAR ) ); System.out.println( "de: " + calDe.get( Calendar.WEEK_OF_YEAR ) ); } 

stampe:

 us: 1 de: 52 

AGGIUNTO Per gli Stati Uniti (e posso pensare che sia lo stesso per il Messico) la 1. Settimana dell’anno è la settimana in cui appartiene l’1 gennaio. – Quindi se 1. Januar è ​​un sabato, il venerdì precedente (31 dicembre) appartiene alla stessa settimana, e in questo caso questo giorno appartiene alla 1. Settimana dell’anno 2011.

I valori calcolati per il campo WEEK_OF_YEAR vanno da 1 a 53. La settimana 1 per un anno è il primo periodo di sette giorni che inizia su getFirstDayOfWeek () che contiene almeno getMinimalDaysInFirstWeek () giorni da quell’anno. Dipende quindi dai valori di getMinimalDaysInFirstWeek (), getFirstDayOfWeek () e il giorno della settimana del 1 ° gennaio. Le settimane tra la settimana 1 di un anno e la settimana 1 dell’anno successivo sono numerate sequenzialmente da 2 a 52 o 53 (come necessario).

Per determinare se quella settimana è l’ultima settimana del 2010 o il primo del 2011 utilizza Java getMinimalDaysInFirstWeek javadoc . Se quel metodo restituisce 7, la prima settimana in cui tutti i giorni della settimana sono dello stesso anno è la settimana uno, se restituisce 1, quindi la prima settimana con qualsiasi giorno dell’anno successivo è la prima settimana dell’anno successivo.

In questo caso il primo di gennaio del 2011 è di sabato, quindi è considerato la prima settimana del 2011 a condizione che desideri una settimana con un giorno da considerare già la prima settimana del prossimo anno, se non lo fai Quindi fa:

 Calendar c = Calendar.getInstance(); c.setMinimalDaysInFirstWeek(7);//anything more than 1 will work in this year DateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); c.setTime( sdf.parse("31/12/2010")); System.out.println( c.get( Calendar.WEEK_OF_YEAR ) ); 

ritorna:

 52 

IIRC, la prima settimana con una data di 1 gennaio è la settimana 1.
Ecco perché la settimana 1 viene restituita il 31/12/2010.
Provalo per il 31/12/2011 e riceverai 52.

Modifica: la settimana è specifica per la località, a volte definita come domenica-sabato, a volte definita come lunedì-domenica

Questo perché l’inizio della settimana dipende dal locale.

Negli Stati Uniti la settimana 1 inizia la domenica prima di gennaio 1. Nel 2010 questo è il 26 dicembre. Ecco perché il 31 dicembre è ancora la settimana 1.

In Europa la settimana 1 inizia il lunedì prima del 1 gennaio. Nel 2010 questo è il 27 dicembre. Ecco perché anche in Europa il 31 dicembre è ancora la settimana 1.

tl; dr

 java.time.LocalDate.parse( "31/12/2010" , DateTimeFormatter.ofLocalizedDate( FormatStyle.SHORT ).withLocale( Locale.UK ) ) .get( IsoFields.WEEK_OF_WEEK_BASED_YEAR ) 

52

Oppure aggiungi una libreria e poi …

 org.threeten.extra.YearWeek.from( // Convert from a `LocalDate` object to a `YearWeek` object representing the entire week of that date's week-based year. java.time.LocalDate.parse( "31/12/2010" , DateTimeFormatter.ofLocalizedDate( FormatStyle.SHORT ).withLocale( Locale.UK ) ).getWeek() // Extract an integer number of that week of week-based-year, either 1-52 or 1-53 depending on the year. 

52

java.time

Come altri hanno notato, la definizione di una settimana varia in base alla lingua nella vecchia class java.util.Calendar .

Quella class fastidiosa e il suo partner java.util.Date sono stati soppiantati dal framework java.time incorporato in Java 8 e versioni successive.

La class IsoFields definisce una settimana utilizzando lo standard ISO 8601 : la settimana inizia sempre il lunedì e la settimana 1 tiene il primo giovedì dell’anno solare.

Prendi il momento attuale.

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

Chiedi circa l’anno standard settimanale.

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

Definizione della settimana standard

Esistono molti modi per definire “una settimana” e “prima settimana dell’anno”.

Tuttavia, esiste una definizione standard importante : lo standard ISO 8601 . Questo standard definisce le settimane dell’anno, compresa la prima settimana dell’anno.

la settimana con il primo giovedì dell’anno

Una settimana standard inizia con il lunedì e termina con la domenica.

La settimana n. 1 di un anno basato sulla settimana ha il primo giovedì dell’anno solare.

Le classi java.time supportano la settimana ISO 8601 attraverso la class IsoFields , con tre costanti che implementano TemporalField :

  • WEEK_OF_WEEK_BASED_YEAR
  • WEEK_BASED_YEAR
  • WEEK_BASED_YEARS

Chiama LocalDate::get accedi al TemporalField .

 LocalDate ld = LocalDate.parse( "2010-12-31" ) ; int weekOfWeekBasedYear = ld.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR ) ; int yearOfWeekBasedYear = ld.get( IsoFields.WEEK_BASED_YEAR ) ; 

ld.toString (): 2010-12-31

weekOfWeekBasedYear: 52

yearOfWeekBasedYear: 2010

Formato stringa ISO 8601

Lo standard ISO 8601 definisce un formato testuale oltre che un significato per i valori relativi alla settimana dell’anno: yyyy-Www . Per una data specifica, aggiungi il giorno della settimana numerato 1-7 per lunedì-domenica: yyyy-Www-d settimana yyyy-Www-d .

Costruisci una tale stringa.

 String outputWeek = String.format( "%04d" , yearOfWeekBasedYear ) + "-W" + String.format( "%02d" , weekOfWeekBasedYear ) ; String outputDate = outputWeek + "-" + ld.getDayOfWeek().getValue() ; 

2010-W52-5

YearWeek

Questo lavoro è molto più semplice se aggiungi la libreria ThreeTen-Extra al tuo progetto. Quindi utilizzare la class YearWeek .

 YearWeek yw = YearWeek.from( ld ) ; // Determine ISO 8601 week of a `LocalDate`. 

Genera la stringa standard.

 String output = yw.toString() ; 

2010-W52

E analizzare.

 YearWeek yearWeek = YearWeek.parse( "2010-W52" ) ; 

yearWeek.toString (): 2010-W52

Determina una data. Passa un object enum java.time.DayOfWeek per il giorno della settimana dal lunedì alla domenica.

 LocalDate localDate = yw.atDay( DayOfWeek.MONDAY ) ; 

localDate.toString (): 2010-12-27

Raccomando vivamente di aggiungere questa libreria al tuo progetto. Quindi puoi passare oggetti intelligenti anziché intimi. In questo modo il tuo codice è più auto-documentante, garantisce la sicurezza del tipo e garantisce valori validi.


A proposito di java.time

Il framework java.time è integrato in Java 8 e versioni successive. Queste classi soppiantano le fastidiose vecchie lezioni di data e ora come java.util.Date , Calendar e SimpleDateFormat .

Il progetto Joda-Time , ora in modalità di manutenzione , consiglia la migrazione alle classi java.time .

Per saperne di più, consultare l’ esercitazione Oracle . E cerca Stack Overflow per molti esempi e spiegazioni. La specifica è JSR 310 .

Utilizzando un driver JDBC compatibile con JDBC 4.2 o successivo, è ansible scambiare oggetti java.time direttamente con il proprio database. Nessuna necessità di stringhe o classi java.sql. *.

Dove ottenere le classi java.time?

  • Java SE 8 , Java SE 9 e versioni successive
    • Built-in.
    • 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
    • Gran parte della funzionalità java.time è back-porting su Java 6 e 7 in ThreeTen-Backport .
  • android
    • Versioni successive di implementazioni di bundle Android delle classi java.time.
    • Per Android precedente, il progetto ThreeTenABP adatta ThreeTen-Backport (menzionato sopra). Vedi Come usare ThreeTenABP ….

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


Per ulteriori dettagli, vedere la mia risposta alla domanda simile:

  • java ottenere settimana dell’anno per data data

… e vedi la mia risposta sulla domanda simile:

  • Come calcolare la data dal numero di settimana ISO8601 in Java

Sento che questo è un approccio migliore.

 Calendar c = Calendar.getInstance(); DateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); c.setTime( sdf.parse("31/12/2010")); int thisWeek = c.get(Calendar.WEEK_OF_YEAR); if (c.get(Calendar.MONTH) == Calendar.DECEMBER && thisWeek == 1) thisWeek = 53; System.out.println(thisWeek); 

L’ipotesi principale qui è che, per il mese di dicembre, la settimana non può essere 1, quindi restituendo 53.

Si prega di suggerire, se ho sbagliato da qualche parte, e perché questo non è implementato nel calendario di Java.