Java Date vs Calendar

Alguém poderia, por favor, avisar a atual “prática recomendada” em torno dos tipos Date e Calendar .

Ao escrever um novo código, é melhor favorecer sempre o Calendar over Date ou existem circunstâncias em que Date é o tipo de dados mais apropriado?

A data é uma class mais simples e está principalmente lá por motivos de compatibilidade com versões anteriores. Se você precisar definir datas específicas ou aritmética de data, use um calendar. Os calendars também lidam com localização. As funções de manipulação de data anteriores de Date foram descontinuadas.

Pessoalmente, costumo usar o tempo em milissegundos como um longo (ou longo, conforme apropriado) ou o calendar quando há uma opção.

Data e Calendário são mutáveis, o que tende a apresentar problemas ao usar uma API.

A melhor maneira para um novo código (se sua política permitir código de terceiros) é usar a biblioteca Joda Time .

Ambos, Date e Calendar , têm tantos problemas de design que nem são boas soluções para novos códigos.

  • Date e Calendar são realmente o mesmo conceito fundamental (ambos representam um instante no tempo e são wrappers em torno de um valor long subjacente).

  • Pode-se argumentar que o Calendar está, na verdade, ainda mais quebrado do que Date , pois parece oferecer fatos concretos sobre coisas como dia da semana e hora do dia, enquanto se você mudar sua propriedade timeZone , o concreto se transformará em manjar branco! Nenhum object é realmente útil como uma loja de ano-mês-dia ou hora do dia por esse motivo.

  • Use o Calendar somente como uma calculadora que, quando dados os objects Date e TimeZone , fará cálculos para você. Evite seu uso para digitação de propriedade em um aplicativo.

  • Use SimpleDateFormat junto com TimeZone e Date para gerar Strings de exibição.

  • Se você está se sentindo aventureiro usar Joda-Time, embora seja IMHO desnecessariamente complicado e em breve será substituído pela API de data JSR-310 em qualquer evento.

  • Eu já respondi que não é difícil criar sua própria class YearMonthDay , que usa o Calendar under the hood para cálculos de datas. Fui rejeitado pela sugestão, mas ainda acredito que seja válido porque o Joda-Time (e o JSR-310 ) são realmente muito complicados para a maioria dos casos de uso.

A data é melhor para armazenar um object de data. É o persistido, o Serializado …

O calendar é melhor para manipular datas.

Nota: às vezes também favorecemos java.lang.Long over Date, porque Date é mutável e, portanto, não é thread-safe. Em um object Date, use setTime () e getTime () para alternar entre os dois. Por exemplo, uma data constante no aplicativo (exemplos: o zero 1970/01/01 ou um aplicativo END_OF_TIME que você definiu como 2099/12/31; esses são muito úteis para replace valores nulos como hora de início e hora de término, especialmente quando você persistir no database, como SQL é tão peculiar com nulos).

Eu geralmente uso Data, se possível. Embora seja mutável, os mutadores são realmente obsoletos. No final, basicamente, envolve um longo período que representaria a data / hora. Por outro lado, eu usaria os calendars se tivesse que manipular os valores.

Você pode pensar desta forma: você só usa StringBuffer apenas quando você precisa ter Strings que você pode manipular facilmente e depois convertê-los em Strings usando o método toString (). Da mesma forma, só uso o Google Agenda se precisar manipular dados temporais.

Para a prática recomendada, costumo usar objects imutáveis ​​o máximo possível fora do modelo de domínio . Isso reduz significativamente as chances de quaisquer efeitos colaterais e é feito para você pelo compilador, em vez de um teste JUnit. Você usa essa técnica criando campos finais privados em sua class.

E voltando à analogia do StringBuffer. Aqui está algum código que mostra como converter entre Calendário e Data

 String s = "someString"; // immutable string StringBuffer buf = new StringBuffer(s); // mutable "string" via StringBuffer buf.append("x"); assertEquals("someStringx", buf.toString()); // convert to immutable String // immutable date with hard coded format. If you are hard // coding the format, best practice is to hard code the locale // of the format string, otherwise people in some parts of Europe // are going to be mad at you. Date date = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).parse("2001-01-02"); // Convert Date to a Calendar Calendar cal = Calendar.getInstance(); cal.setTime(date); // mutate the value cal.add(Calendar.YEAR, 1); // convert back to Date Date newDate = cal.getTime(); // assertEquals(new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).parse("2002-01-02"), newDate); 

Date devem ser usadas como pontos imutáveis ​​no tempo; Calendar s são mutáveis ​​e podem ser passados ​​e modificados se você precisar colaborar com outras classs para chegar a uma data final. Considere-os análogos a String e StringBuilder e você entenderá como eu considero que eles devem ser usados.

(E sim, eu sei que Data não é tecnicamente imutável, mas a intenção é que não seja mutável, e se nada chamar os methods obsoletos, então é assim.)

Com o Java 8, o novo pacote java.time deve ser usado.

Objetos são imutáveis, fusos horários e economia de luz do dia são levados em conta.

Você pode criar um object ZonedDateTime partir de um object java.util.Date antigo como este:

  Date date = new Date(); ZonedDateTime zonedDateTime = date.toInstant().atZone(ZoneId.systemDefault()); 

Eu sempre defendo o Joda-time . Aqui está o porquê.

  1. a API é consistente e intuitiva. Ao contrário das APIs java.util.Date/Calendar
  2. ele não sofre com problemas de encadeamento, diferente de java.text.SimpleDateFormat etc. (Eu já vi vários problemas com clientes relacionados a não perceber que a formatação padrão de data / hora não é segura para encadeamento)
  3. é a base das novas APIs de data / hora Java ( JSR310 , agendadas para Java 8). Assim, você usará APIs que se tornarão APIs Java principais.

tl; dr

aconselhar as “melhores práticas” atuais em torno da Date e do Calendar

é melhor sempre favorecer o Calendar por Date

Evite essas classs legadas completamente. Use as classs java.time .

  • Por um momento no UTC , use Instant
    (o equivalente moderno da Date )
  • Por um momento em um fuso horário específico , use ZonedDateTime
    (o equivalente moderno do GregorianCalendar )
  • Por um momento em um determinado deslocamento de UTC , use OffsetDateTime
    (não equivalente em classs legadas)
  • Para uma data-hora (não um momento) com fuso horário ou deslocamento desconhecido, use LocalDateTime
    (não equivalente em classs legadas)

Detalhes

A resposta de Ortomala Lokni está certa ao sugerir o uso das classs java.time modernas, em vez das antigas classs antigas de legado ( Date , Calendar , etc.). Mas essa resposta sugere a class errada como equivalente (veja meu comentário sobre essa resposta).

Usando java.time

As classs java.time são uma grande melhoria em relação às classs legadas de data e hora, diferença de dia e noite. As classs antigas são mal projetadas, confusas e problemáticas. Você deve evitar as classs antigas sempre que possível. Mas quando você precisa converter para / do antigo / novo, pode fazê-lo chamando novos methods adicionados às classs antigas .

Para obter mais informações sobre conversão, consulte minha resposta e o diagrama nifty para outra pergunta. Converta java.util.Date para o tipo “java.time”? .

A pesquisa do Stack Overflow fornece muitas centenas de perguntas e respostas sobre o uso de java.time. Mas aqui está uma sinopse rápida.

Instant

Veja o momento atual com um Instant . A class Instant representa um momento na linha do tempo no UTC com uma resolução de nanossegundos (até nove (9) dígitos de uma fração decimal).

 Instant instant = Instant.now(); 

ZonedDateTime

Para ver o mesmo momento simultâneo através da lente do tempo de relógio de parede de determinada região, aplique um fuso horário ( ZoneId ) para obter um ZonedDateTime .

Fuso horário

Especifique um nome de fuso horário adequado no formato de continent/region , como America/Montreal , Africa/Casablanca ou Pacific/Auckland . Nunca use a abreviação de 3 a 4 letras, como EST ou IST pois eles não são verdadeiros fusos horários, não são padronizados e nem mesmo exclusivos (!).

 ZoneId z = ZoneId.of( "America/Montreal" ); ZonedDateTime zdt = instant.atZone(); 

Offset

Um fuso horário é um histórico da região de alterações no deslocamento de UTC . Mas às vezes você recebe apenas um deslocamento sem a zona completa. Nesse caso, use a class OffsetDateTime .

 ZoneOffset offset = ZoneOffset.parse( "+05:30" ); OffsetDateTime odt = instant.atOffset( offset ); 

O uso de um fuso horário é preferível ao uso de um mero deslocamento.

LocalDateTime

O “Local” nas classs Local… significa qualquer localidade, não uma localidade específica. Então o nome pode ser contra-intuitivo.

LocalDateTime , LocalDate e LocalTime propositalmente não possuem informações sobre deslocamento ou fuso horário. Então eles não representam momentos reais, eles não são pontos na linha do tempo. Em caso de dúvida ou confusão, use ZonedDateTime vez de LocalDateTime . Pesquise o Stack Overflow para muito mais discussão.

Cordas

Não combine objects de data e hora com strings que representem seu valor. Você pode analisar uma string para obter um object de data e hora e gerar uma string a partir de um object de data e hora. Mas a string nunca é a data-hora em si.

Aprenda sobre os formatos padrão ISO 8601 , usados ​​por padrão nas classs java.time.


Sobre o java.time

O framework java.time está embutido no Java 8 e posterior. Essas classs substituem as antigas classs herdadas de data e hora legadas , como java.util.Date , Calendar e SimpleDateFormat .

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

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

Usando um driver JDBC compatível com o JDBC 4.2 ou posterior, você pode trocar objects java.time diretamente com seu database. Não há necessidade de strings nem de classs java.sql. *.

Onde obter as classs java.time?

  • Java SE 8 , Java SE 9 e posterior
    • Construídas em.
    • Parte da API Java padrão com uma implementação integrada.
    • O Java 9 adiciona alguns resources e correções menores.
  • Java SE 6 e Java SE 7
    • Grande parte da funcionalidade java.time é transferida para o Java 6 e 7 no ThreeTen-Backport .
  • Android
    • Versões posteriores das implementações do pacote Android das classs java.time.
    • Para o Android anterior, o projeto ThreeTenABP adapta o ThreeTen-Backport (mencionado acima). Veja Como usar o ThreeTenABP… .

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

Um pouco atrasado na festa, mas o Java tem uma nova API Date Time no JDK 8. Você pode querer atualizar sua versão do JDK e adotar o padrão. Não há mais data / calendar bagunçado, não há mais potes de terceiros.

A data deve ser desenvolvida novamente. Em vez de ser um longo interger, deve conter ano, mês, data, hora, minuto, segundo, como campos separados. Pode até ser bom armazenar o calendar e o fuso horário com os quais essa data está associada.

Em nossa conversa natural, se você marcar uma reunião em 1 de novembro de 2013, 1pm, horário de Nova York, esse será um DateTime. NÃO é um calendar. Então, poderíamos conversar assim também em Java.

Quando Data é armazenada como um número inteiro longo (de mili segundos desde 1º de janeiro de 1970 ou algo assim), o cálculo da data atual depende do calendar. Calendários diferentes darão datas diferentes. Esta é a perspectiva de dar um tempo absoluto (por exemplo, 1 trilhão de segundos após o Big Bang). Mas muitas vezes também precisamos de uma maneira conveniente de conversar, como um object que encapsula ano, mês etc.

Gostaria de saber se há novos avanços em Java para conciliar esses dois objectives. Talvez meu conhecimento de java seja muito antigo.

Btw “date” é geralmente marcado como “obsoleto / depreciado” (não sei exatamente por que) – algo sobre isso é escrito lá Java: Por que o construtor Date está obsoleto, e o que eu uso em vez disso?

Parece que é um problema do construtor un-way via new Date (int ano, int month, int day) , o recomendado é via Calendar e configura params separadamente .. ( Calendar cal = Calendar.getInstance (); )

Eu uso o Calendar quando preciso de algumas operações específicas sobre as datas, como mover no tempo, mas Data eu acho que é útil quando você precisa formatar a data para adaptar suas necessidades, recentemente descobri que Locale tem um monte de operações e methods úteis. Estou usando Locale agora mesmo!