Java: Obter mês inteiro a partir da data

157

Como obtenho o mês como um número inteiro de um objeto Date ( java.util.Date)?

Muhd
fonte
23
realmente getMonth () na Data está obsoleto desde sempre;)
Mateusz Dymczyk
6
@slhck: descontinuado. A partir do JDK versão 1.1, substituído por Calendar.get (Calendar.MONTH).
adarshr
3
@Zenzen Não vejo o problema de usar um método obsoleto em uma classe principalmente obsoleta.
Serabe 24/08
1
@ Muhd, se você estiver trabalhando com datas, sirva-se e use joda ou qualquer outra biblioteca.
Serabe
1
@ Serabe: o problema é que existem soluções melhores (aquelas que pelo menos não são obsoletas). E o getMonth está obsoleto há 14 anos e está obsoleto por um motivo.
Mateusz Dymczyk

Respostas:

57

java.time (Java 8)

Você também pode usar o pacote java.time no Java 8 e converter seu java.util.Dateobjeto em umjava.time.LocalDate objeto e, em seguida, basta usar o getMonthValue()método

Date date = new Date();
LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
int month = localDate.getMonthValue();

Observe que os valores do mês são dados aqui de 1 a 12, ao contrário cal.get(Calendar.MONTH)da resposta de adarshr, que fornece valores de 0 a 11.

Mas, como Basil Bourque disse nos comentários, a maneira preferida é obter um Monthobjeto enum com o LocalDate::getMonthmétodo.

Ortomala Lokni
fonte
1
Boa resposta. Nota para o leitor: Você pode especificar um fuso horário em vez de confiar na chamada para o padrão mostrado na resposta. Um novo dia (e mês) amanhece mais cedo em Paris, por exemplo, do que em Montreal. Se você se preocupa especificamente com Montreal, use ZoneId.of( "America/Montreal" ).
Basil Bourque
1
Eu só quero acrescentar que há um grande artigo sobre a introdução de java.time api oracle.com/technetwork/articles/java/...
A propósito, outra observação para o leitor: Você também pode obter um Monthobjeto enum em vez de um mero número inteiro. Month m = localDate.gotMonth();Veja o LocalDate::getMonthmétodo O uso de objetos como esse torna seu código auto-documentado, garante a segurança do tipo e garante valores válidos. Consulte o tutorial do Enum da Oracle.
Basil Bourque
1
se você usar date.toInstant()e estiver trabalhando com um java.sql.Date(filho de java.util.Date), receberá um UnsupportedOperationException. Tentenew java.sql.Date(src.getTime()).toLocalDate()
Adam
1
@ Adam Muito mais fácil de converter de / para java.sql.Dateusando os novos métodos de conversão adicionados à classe antiga. java.sql.Date.valueOf( myLocalDate )e myJavaSqlDate.toLocalDate() Além disso, os drivers JDBC atualizados para o JDBC 4.2 ou posterior não precisam mais de java.sqltipos e podem endereçar java.timetipos diretamente pelos métodos ResultSet::getObjecte PreparedStatement::setObject.
Basil Bourque 23/03
287
java.util.Date date= new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(date);
int month = cal.get(Calendar.MONTH);
adarshr
fonte
166
Observe que, Calendar.MONTHsem motivos aparentes, é baseado em ZERO, ou seja, janeiro == 0. Agora isso está bem documentado na API, mas ainda é confuso para os usuários iniciantes. Ainda estou para encontrar alguém que possa me dizer por que eles concordaram com isso - talvez seja o momento de fazer uma nova pergunta para o SO (embora eu tenha medo de que não exista uma grande base para isso: /) #
Voo
5
O método @Voo Date.getMonth () foi baseado em zero, provavelmente o principal motivo de Calendar.MONTH.
Muhd
1
@ Muhd ​​Claro, afinal, foi a substituição. Mas isso muda apenas a questão de por que o Date.getMonth () foi baseado em zero? Imo um design horrível, especialmente porque os dias começam em um (eles poderiam pelo menos ser consistentes!). Suponho que foi apenas uma supervisão em uma API não especialmente bem projetada (Data e Calendário) para começar. Mas talvez haja algum precedente - isso me parece estranho e causou problemas a mais de um iniciante na minha experiência.
Voo 24/08
2
Na verdade, já foi perguntado aqui no SO (e não apenas). O resultado final é que é resultado de uma API mal projetada. Quero dizer, como você mencionou, toda a classe Date é uma piada. O fato interessante é que não apenas o Java sofre com esse problema - a data getMonth () do JavaScript do iirc também começa com um 0!
Mateusz Dymczyk
1
@Voo getYear()também é "sem razões aparentes", subtraídos por 1900.
Hele
17

Se você usa o Java 8 date api, pode obtê-lo diretamente em uma linha!

LocalDate today = LocalDate.now();
int month = today.getMonthValue();
Ketan Chitale
fonte
7

Joda-Time

Como alternativa, com a classe Joda-Time DateTime .

//convert date to datetime
DateTime datetime = new DateTime(date);
int month = Integer.parseInt(datetime.toString("MM"))

…ou…

int month = dateTime.getMonthOfYear();
ssoward
fonte
2
Ainda mais simples, basta perguntar ao DateTimeobjeto pelo seu mês. int month = dateTime.getMonthOfYear();
Basil Bourque 28/07
Boa chamada Basil, eu atualizei o código. No entanto, eu gosto do .toString("MM")que mostra, existem mais possibilidades do que apenas "MM".
31814 ssoward
1
Essa resposta ignora a questão crucial do fuso horário. Veja meus comentários na pergunta e na resposta do irmão. Sugiro passando um DateTimeZoneobjeto para que o construtor DateTime: DateTimeZone.forID( "America/Montreal" ).
Basil Bourque
6

tl; dr

myUtilDate.toInstant()                          // Convert from legacy class to modern. `Instant` is a point on the timeline in UTC.
          .atZone(                              // Adjust from UTC to a particular time zone to determine date. Renders a `ZonedDateTime` object. 
              ZoneId.of( "America/Montreal" )   // Better to specify desired/expected zone explicitly than rely implicitly on the JVM’s current default time zone.
          )                                     // Returns a `ZonedDateTime` object.
          .getMonthValue()                      // Extract a month number. Returns a `int` number.

java.time Detalhes

A resposta de Ortomala Lokni para o uso de java.time está correta. E você deve usar o java.time, pois é uma melhoria gigantesca em relação às antigas classes java.util.Date/.Calendar. Veja o Tutorial do Oracle em java.time.

Vou adicionar um código que mostra como usar o java.time sem considerar o java.util.Date, para quando você estiver iniciando com um novo código.

Usando java.time em poucas palavras… An Instanté um momento na linha do tempo no UTC. Aplique um fuso horário ( ZoneId) para obter umZonedDateTime .

A Monthclasse é uma enumeração sofisticada para representar um mês em geral. Essa enumeração tem métodos úteis, como obter um nome localizado. E tenha certeza de que o número do mês em java.time é sensato, 1 a 12, não o absurdo com base em zero (0 a 11) encontrado em java.util.Date/.Calendar.

Para obter a data e hora atuais, o fuso horário é crucial. A qualquer momento, a data não é a mesma em todo o mundo. Portanto, o mês não é o mesmo em todo o mundo se estiver perto do final / início do mês.

ZoneId zoneId = ZoneId.of( "America/Montreal" );  // Or 'ZoneOffset.UTC'.
ZonedDateTime now = ZonedDateTime.now( zoneId );
Month month = now.getMonth(); 
int monthNumber = month.getValue(); // Answer to the Question.
String monthName = month.getDisplayName( TextStyle.FULL , Locale.CANADA_FRENCH );

Sobre java.time

o estrutura java.time é integrada ao Java 8 e posterior. Essas classes suplantar os velhos problemáticos legados aulas de data e hora, comojava.util.Date,Calendar, eSimpleDateFormat .

O projeto Joda-Time , agora em modo de manutenção , aconselha a migração para as classes java.time .

Para saber mais, consulte o Tutorial do Oracle . E procure Stack Overflow para muitos exemplos e explicações. A especificação é JSR 310 .

Você pode trocar objetos java.time diretamente com seu banco de dados. Use um driver JDBC compatível com JDBC 4.2 ou posterior. Não há necessidade de strings, não há necessidade dejava.sql.* classes.

Onde obter as classes java.time?

  • Java SE 8 , Java SE 9 , Java SE 10 e posterior
    • Construídas em.
    • Parte da API Java padrão com uma implementação em pacote configurável.
    • O Java 9 adiciona alguns recursos e correções menores.
  • Java SE 6 e Java SE 7
    • Grande parte da funcionalidade java.time é portada para Java 6 e 7 no ThreeTen-Backport .
  • Android
    • Versões posteriores das implementações de pacote configurável do Android das classes java.time.
    • Para anteriormente Android (<26), o ThreeTenABP projeto adapta ThreeTen-Backport (mencionados acima). Consulte Como usar o ThreeTenABP… .

O projeto ThreeTen-Extra estende java.time com classes adicionais. Este projeto é um campo de prova para possíveis adições futuras ao java.time. Você pode encontrar algumas classes úteis aqui, como Interval, YearWeek, YearQuarter, e mais .

Basil Bourque
fonte
4

Se você não pode usar o tempo Joda e ainda vive no mundo sombrio :) (Java 5 ou inferior), pode aproveitar o seguinte:

Nota: verifique se a data já foi criada pelo formato: dd / MM / AAAA

/**
Make an int Month from a date
*/
public static int getMonthInt(Date date) {

    SimpleDateFormat dateFormat = new SimpleDateFormat("MM");
    return Integer.parseInt(dateFormat.format(date));
}

/**
Make an int Year from a date
*/
public static int getYearInt(Date date) {

    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy");
    return Integer.parseInt(dateFormat.format(date));
}
Badr DRAIFI
fonte
Você é a mãe! / Είσαι η μάνα!
Tzegenos
0
Date mDate = new Date(System.currentTimeMillis());
mDate.getMonth() + 1

O valor retornado começa em 0, então você deve adicionar um ao resultado.

twlkyao
fonte
6
2 problemas com a sua resposta: um é que você pode marcar uma data com a hora atual, new Date()sem fazer isso System.currentTimeMillis. A outra é que getMonth está obsoleto.
Muhd
@ Muhd ​​Então, qual é a melhor solução?
Twlkyao 14/05
@Muhd O System.currentTimeMillis () que eu adicionei aqui foi para indicar que aqui é um tipo longo, e você pode especificar a data.
Twlkyao 15/05
4
Date :: getMonth já foi descontinuado no Java 1.1 ( cs.mun.ca/~michael/java/jdk1.1-beta2-docs/api/… )
Ortomala Lokni