Il calendario restituisce il mese sbagliato

Calendar rightNow = Calendar.getInstance(); String month = String.valueOf(rightNow.get(Calendar.MONTH)); 

Dopo l’esecuzione dello snippet sopra riportato, il mese ottiene un valore di 10 anziché 11. Come mai?

I mesi sono indicizzati da 0 e non da 1, quindi 10 sono novembre e 11 dicembre.

Iniziano da 0 – controlla i documenti

Come è chiaro dalle molte risposte: il mese inizia con 0.

Ecco un suggerimento: dovresti usare SimpleDateFormat per ottenere la rappresentazione delle stringhe del mese:

 Calendar rightNow = Calendar.getInstance(); java.text.SimpleDateFormat df1 = new java.text.SimpleDateFormat("MM"); java.text.SimpleDateFormat df2 = new java.text.SimpleDateFormat("MMM"); java.text.SimpleDateFormat df3 = new java.text.SimpleDateFormat("MMMM"); System.out.println(df1.format(rightNow.getTime())); System.out.println(df2.format(rightNow.getTime())); System.out.println(df3.format(rightNow.getTime())); 

Produzione:

 11 Nov November 

Nota: l’output può variare, è specifico per Locale.

Come diverse persone hanno sottolineato, i mesi restituiti dalle classi Calendar e Date in Java sono indicizzati da 0 anziché da 1. Quindi 0 è gennaio e il mese corrente, novembre, è 10.

Potresti chiederti perché questo è il caso. Le origini sono le funzioni standard POSIX ctime , gmtime e localtime , che accettano o restituiscono una struttura time_t con i seguenti campi (da man 3 ctime ):

 int tm_mday; /* day of month (1 - 31) */ int tm_mon; /* month of year (0 - 11) */ int tm_year; /* year - 1900 */ 

Questa API è stata copiata esattamente nella class Java Date in Java 1.0, e da lì per lo più intatta nella class Calendar in Java 1.1. Sun ha risolto il problema più clamoroso quando hanno introdotto Calendar: il fatto che l’anno 2001 nel calendario gregoriano fosse rappresentato dal valore 101 nella class Date. Ma non sono sicuro del motivo per cui non hanno modificato i valori del giorno e del mese almeno per renderli coerenti nella loro indicizzazione, sia da zero che da uno. Questa incoerenza e la relativa confusione esistono ancora in Java (e in C) fino ad oggi.

I mesi partono da zero, come gli indici per le liste.

Quindi Jan = 0, Feb = 1, ecc.

Dall’API:

Il primo mese dell’anno è GENNAIO che è 0; l’ultimo dipende dal numero di mesi in un anno.

http://java.sun.com/j2se/1.5.0/docs/api/java/util/Calendar.html

tl; dr

 LocalDate.now() // Returns a date-only `LocalDate` object for the current month of the JVM's current default time zone. .getMonthValue() // Returns 1-12 for January-December. 

Dettagli

Altre risposte sono corrette ma obsolete.

Le fastidiose lezioni di data e ora avevano molte scelte e difetti di progettazione. Uno era il conteggio a zero dei numeri dei mesi 0-11 piuttosto che l’ovvio 1-12.

java.time

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

Ora in modalità di manutenzione , il progetto Joda-Time consiglia anche la migrazione a java.time.

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

Gran parte della funzionalità java.time è backportata su Java 6 e 7 in ThreeTen-Backport e ulteriormente adattata ad Android in ThreeTenABP .

Il progetto ThreeTen-Extra estende java.time con classi aggiuntive. Questo progetto è un terreno di prova per possibili aggiunte future a java.time.

Mesi 1-12

In java.time il numero del mese è effettivamente previsto 1-12 per gennaio-dicembre.

La class LocalDate rappresenta un valore di sola data senza ora del giorno e senza fuso orario.

Fuso orario

Un fuso orario è fondamentale per determinare una data. Per un dato momento, la data varia in tutto il mondo per zona. Ad esempio, pochi minuti dopo la mezzanotte a Parigi, la Francia è un nuovo giorno mentre è ancora “ieri” a Montréal Québec .

Specificare un nome di fuso orario appropriato nel formato di continent/region , ad esempio America/Montreal , Africa/Casablanca o Pacific/Auckland . Non utilizzare mai l’abbreviazione di 3-4 lettere come EST o IST quanto non sono veri fusi orari, non standardizzati e nemmeno unici (!).

 LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) ); int month = today.getMonthValue(); // Returns 1-12 as values. 

Se si desidera una data per un fuso orario, utilizzare ZonedDateTime object ZonedDateTime allo stesso modo.

 ZonedDateTime now = ZonedDateTime.now( ZoneId.of( "America/Montreal" ) ); int month = now.getMonthValue(); // Returns 1-12 as values. 

Convertire le classi precedenti

Se hai un object GregorianCalendar in mano, converti in ZonedDateTime usando il nuovo metodo toZonedDateTime aggiunto alla vecchia class. Per ulteriori informazioni sulla conversione, vedi Convertire java.util.Date su che tipo “java.time”?

 ZonedDateTime zdt = myGregorianCalendar.toZonedDateTime(); int month = zdt.getMonthValue(); // Returns 1-12 as values. 

Enum Month

A proposito, le classi java.time includono il pratico enum del Month . Utilizza le istanze di questa class nel tuo codice anziché semplici interi per rendere il tuo codice più auto-documentante, fornire sicurezza del tipo e assicurare valori validi.

 Month month = today.getMonth(); // Returns an instant of `Month` rather than integer. 

Il Month enum offre metodi utili come la generazione di una stringa con il nome localizzato del mese .


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 .

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
    • Il progetto ThreeTenABP adatta ThreeTen-Backport (menzionato sopra) per Android in particolare.
    • 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 .

 cal.get(Calendar.MONTH) + 1; 

L’affermazione sopra riporta il numero esatto del mese. Come get(Calendar.Month) restituisce il mese a partire da 0, aggiungendo 1 al risultato darebbe l’output corretto. E ricorda di sottrarre 1 quando si imposta il mese.

 cal.set(Calendar.MONTH, (8 - 1)); 

O utilizzare le variabili costanti fornite.

 cal.set(Calendar.MONTH, Calendar.AUGUST); 

Sarebbe meglio da usare

 Calendar.JANUARY 

che è zero …