Data Java vs Calendário

364

Alguém poderia aconselhar as "melhores práticas" atuais Datee Calendartipos.

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

Marty Pitt
fonte
28
Hora do Joda: joda-time.sourceforge.net
R. Martinho Fernandes
2
FYI, os incômodos aulas em tempo data antigas, tais como java.util.Date, java.util.Calendare java.text.SimpleDateFormatestão agora legado, suplantado pelos java.time classes. Grande parte da funcionalidade java.time é portada para Java 6 e Java 7 no projeto ThreeTen-Backport . Mais adaptado para Android anterior no projeto ThreeTenABP . Consulte Como usar o ThreeTenABP… .
Basil Bourque 23/02
2
Para sua informação, o projeto Joda-Time (mencionado em outro comentário) agora está no modo de manutenção , com a equipe aconselhando a migração para as classes java.time . Consulte o Tutorial da Oracle .
Basil Bourque 23/02

Respostas:

377

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

Pessoalmente, costumo usar o tempo em milissegundos como longo (ou longo, conforme apropriado) ou o calendário quando houver uma opção.

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

cleto
fonte
5
FYI, os terrivelmente problemáticas aulas em tempo data antigas, tais como java.util.Date, java.util.Calendare java.text.SimpleDateFormatestão agora legado , suplantado pelos java.time classes internas em Java 8 e posterior. Consulte o Tutorial da Oracle .
Basil Bourque
67

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

Ambos, Data e Calendário , têm tantos problemas de design que nem são boas soluções para o novo código.

dmeister
fonte
7
Segundo a sugestão de usar o tempo de joda. É mais fácil de usar e entender e oferece muito mais funcionalidade que você pode usar.
Jeroen van Bergen
30
Para obter uma discussão sobre o uso do Joda Time ou o uso de classes JDK padrão, consulte stackoverflow.com/questions/589870/…
#
3
Não sei se merece votos negativos, mas não responde à pergunta. Pode ser melhor como um comentário.
IcedDante
7
Como a pergunta era sobre o uso de Data e calendário, não uma biblioteca de terceiros, que adiciona um risco de dependência de um único fornecedor a um projeto.
Archimedes Trajano
3
Essa foi a "melhor maneira" até que o pacote java.time foi disponibilizado com o Java 8.
DaBlick
58
  • Datee Calendarsão realmente o mesmo conceito fundamental (ambos representam um instante no tempo e envolvem um longvalor subjacente ).

  • Pode-se argumentar que, Calendarna verdade, é ainda mais quebrado do queDate é, pois parece oferecer fatos concretos sobre coisas como dia da semana e hora do dia, enquanto que, se você mudar sua timeZonepropriedade, o concreto se transforma em manjedoura! Nenhum dos objetos é realmente útil como armazenamento de ano-mês-dia ou hora do dia por esse motivo.

  • Use Calendarapenas como uma calculadora que, quando fornecida Datee TimeZoneobjetos, fará cálculos para você. Evite seu uso para digitar propriedades em um aplicativo.

  • Use SimpleDateFormatjunto com TimeZonee Datepara gerar strings de exibição.

  • Se você estiver se sentindo aventureiro, use o Joda-Time, embora o IMHO seja desnecessariamente complicado e seja substituído em breve pela API de data do JSR-310.

  • Eu respondi antes que não é difícil apresentar sua própria YearMonthDayclasse, que é usada Calendarsob o capô para cálculos de datas. Recebi voto negativo para a sugestão, mas ainda acredito que seja válida porque o Joda-Time (e o JSR-310 ) são realmente muito complicados para a maioria dos casos de uso.

oxbow_lakes
fonte
11
Existe um prazo para o JSR310? Seria no Java 7, mas acredito que agora não é o caso.
10139 Brian Agnew
@ Brian - certamente ficou muito quieto nessa lista!
Oxbow_lakes 10/09/09
Apenas a verificação, ele foi embora Inativo, o que significa que não tenha publicado um projecto de marco em 18 meses :-(
Brian Agnew
Mais recente comentário sobre a lista de discussão é a partir de julho e por Stephen, para que o projeto provavelmente ainda está tiquetaqueando
oxbow_lakes
Acordado. Se você souber usar Data com segurança como um objeto imutável e o Calendário para manipular Datas, a maioria das pessoas deve estar segura. Tenha cuidado ao usar SimpleDateFormat no código multithread.
Cwash
25

A data é melhor para armazenar um objeto de data. É o persistente, o serializado ...

O calendário é melhor para manipular datas.

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

KLE
fonte
Acho que você está tomando sobre o imutáveljava.lang.Long
PJP
17

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

Você pode pensar desta maneira: você só usa StringBuffer apenas quando precisa de Strings que você pode manipular facilmente e depois as converte em Strings usando o método toString (). Da mesma forma, eu só uso o Calendário se precisar manipular dados temporais.

Para práticas recomendadas, costumo usar objetos imutáveis ​​o máximo possível fora do modelo de domínio . Reduz significativamente as chances de efeitos colaterais e é feito por você pelo compilador, em vez de um teste JUnit. Você usa essa técnica criando final privado campos em sua classe.

E voltando à analogia do StringBuffer. Aqui está um 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);
Archimedes Trajano
fonte
Sim, objetos imutáveis fazem sentido para o trabalho de data e hora. As classes java.time que substituíram Date/ Calendarusam o padrão de objetos imutáveis.
Basil Bourque
Isso pode ser verdade, mas não em 2010.
Archimedes Trajano
Sim. Mas existem milhares de pessoas lendo esta página agora , mais de 150.000 até agora. Meu comentário é uma nota para eles, não uma crítica a você.
Basil Bourque
Eu sei, é por isso que votei na outra resposta. No entanto, ainda há pessoas que precisam sofrer com os JDKs mais antigos que também precisam da resposta acima.
Archimedes Trajano
11
Na verdade, para Java 6 e 7, temos o projeto ThreeTen-Backport . Isso traz a maior parte da funcionalidade java.time com praticamente a mesma API. Portanto, não há necessidade de usar essas terríveis classes de data e hora herdadas.
Basil Bourque
15

Dates devem ser usados ​​como pontos imutáveis ​​no tempo; Calendars são mutáveis ​​e podem ser passados ​​e modificados se você precisar colaborar com outras classes para chegar a uma data final. Considerá-los análogo ao Stringe StringBuildere você vai entender como eu considero que deve ser usado.

(E sim, eu sei que o Date não é tecnicamente imutável, mas a intenção é que não seja mutável e, se nada chamar os métodos descontinuados, é o caso).

Andrzej Doyle
fonte
Sim, objetos imutáveis fazem sentido para o trabalho de data e hora. As classes java.time que substituíram Date/ Calendarusam o padrão de objetos imutáveis. Especificamente, Instantsubstitui java.util.Datee ZonedDateTimesubstitui Calendar/ GregorianCalendar.
Basil Bourque
15

tl; dr

aconselhar as atuais "melhores práticas" em torno DateeCalendar

É melhor sempre favorece CalendarmaisDate

Evite completamente essas classes herdadas . Use as classes java.time .

Tabela de todos os tipos de data e hora em Java, modernos e herdados

Detalhes

A resposta de Ortomala Lokni está certa ao sugerir o uso das classes modernas java.time em vez das classes antigas problemáticas de data e hora herdadas ( Date,Calendar , etc.). Mas essa resposta sugere a classe errada como equivalente (veja meu comentário sobre essa resposta).

Usando java.time

As classes java.time são uma grande melhoria em relação às classes de data e hora herdadas, diferença de noite e dia. As classes antigas são mal planejadas, confusas e problemáticas. Você deve evitar as aulas antigas sempre que possível. Mas quando você precisa converter de / para o antigo / novo, pode fazer isso chamando novos métodos para adicionar às classes antigas .

Para muito mais informações sobre conversão, consulte minha resposta e diagrama bacana para outra pergunta, converta java.util.Date para que tipo "java.time"? .

Pesquisando o estouro de pilha fornece muitas centenas de exemplos de perguntas e respostas sobre o uso de java.time. Mas aqui está uma rápida sinopse.

Instant

Obtenha o momento atual com um Instant. A Instantclasse 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 pelas lentes do relógio de parede de uma região em particular , aplique um fuso horário ( ZoneId) para obter a ZonedDateTime.

Fuso horário

Especifique um nome próprio fuso horário no formato continent/region, como America/Montreal, Africa/Casablanca, ou Pacific/Auckland. Nunca utilize o 3-4 letras, como ESTou ISTcomo eles são não zonas verdadeiros tempo, não padronizados, e nem mesmo única (!).

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

Deslocamento

Um fuso horário é o histórico de alterações de uma região em seu deslocamento em relação ao UTC . Mas às vezes você recebe apenas um deslocamento sem a zona completa. Nesse caso, use a OffsetDateTimeclasse

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 Local…classes significa qualquer localidade, não uma localidade específica. Portanto, o nome pode ser contra-intuitivo.

LocalDateTime, LocalDateE LocalTimepropositadamente não têm qualquer informação sobre a zona de deslocamento ou tempo. Assim, eles não representam momentos reais, eles são não pontos na linha do tempo. Em caso de dúvida ou confusão, use em ZonedDateTimevez deLocalDateTime . Procure Stack Overflow para muito mais discussão.

Cordas

Não confunda objetos de data e hora com seqüências de caracteres que representam seu valor. Você pode analisar uma sequência para obter um objeto de data e hora e pode gerar uma sequência a partir de um objeto de data e hora. Mas a string nunca é a própria data e hora.

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


Sobre java.time

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

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 .

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

Onde obter as classes java.time?

  • Java SE 8 , Java SE 9 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, o ThreeTenABP projeto adapta ThreeTen-Backport (mencionados acima). Consulte Como usar o ThreeTenABP… .

Tabela de qual biblioteca java.time a ser usada com qual versão do Java ou Android

O projeto ThreeTen-Extra estende o 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
10

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

Os objetos são imutáveis, fusos horários e horário de verão são levados em consideração.

Você pode criar um ZonedDateTimeobjeto a partir de um java.util.Dateobjeto antigo como este:

    Date date = new Date();
    ZonedDateTime zonedDateTime = date.toInstant().atZone(ZoneId.systemDefault());
Ortomala Lokni
fonte
É bom sugerir as classes java.time. Mas é ruim sugerir LocalDateTime. Essa classe propositadamente perde qualquer informação sobre deslocamento do UTC e fuso horário. Portanto, essa classe não é equivalente Dateà do UTC e Calendartem um fuso horário atribuído. Veja minha resposta e diagrama bacana para outra pergunta, converta java.util.Date para que tipo "java.time"? .
Basil Bourque
9

Eu sempre defendo o tempo de Joda . Aqui está o porquê.

  1. a API é consistente e intuitiva. Diferente das APIs java.util.Date/Calendar
  2. ele não sofre de problemas de encadeamento, diferentemente de java.text.SimpleDateFormat etc.
  3. é a base das novas APIs de data / hora do Java ( JSR310 , agendadas para Java 8. Portanto, você usará APIs que se tornarão as principais APIs do Java.

EDIT: As classes de data / hora do Java introduzidas no Java 8 agora são a solução preferida, se você pode migrar para o Java 8

Brian Agnew
fonte
3
A última vez que olhei, JODA e JSR-310 pareciam muito diferentes, mesmo que ambos sejam escritos por Stephen Colebourne. Dito isto, JODA iria apresentar-lhe a complexidade dos problemas de data e hora que JSR-310 também resolve
oxbow_lakes
2
Como a pergunta era sobre o uso de Data e calendário, não uma biblioteca de terceiros, que adiciona um risco de dependência de um único fornecedor a um projeto.
Archimedes Trajano
2
I manter a melhor prática é simplesmente não usar essas classes
Brian Agnew
3
Dados os problemas conhecidos com as classes java.util.Date e Calendar, sugerir Joda-Time (ou JSR 310) parece apropriado e responsável para mim. Não estamos falando de uma questão de gosto ou estilo estético. Se alguém perguntasse se deviam pegar o carro vermelho ou o carro prateado, e eu soubesse que o carro vermelho estava com um pneu furado e o carro prateado com um radiador quebrado, devo escolher um carro ou devo sugerir que chame um táxi? A resposta a essa pergunta deve parecer óbvia hoje em dia, pois até a Sun / Oracle decidiu deixar para trás esses junkers e comprar um carro novo: JSR 310: API de data e hora.
Basil Bourque
11
Para sua informação, o projeto Joda-Time agora está no modo de manutenção , aconselhando a migração para as classes java.time . Consulte o Tutorial da Oracle .
Basil Bourque
8

Um pouco atrasado na festa, mas o Java possui uma nova API de Data e Hora no JDK 8. Você pode atualizar sua versão do JDK e adotar o padrão. Não há mais data / calendário confusos, não há mais frascos de terceiros.

Silviu Burcea
fonte
1

A data deve ser re-desenvolvida. Em vez de ser um interger longo, deve conter ano, mês, data, hora, minuto, segundo, como campos separados. Pode até ser bom armazenar o calendário e o fuso horário aos quais esta data está associada.

Em nossa conversa natural, se você marcar um compromisso no dia 1º de novembro de 2013 às 13h, horário de Nova York, será o DateTime. NÃO é um calendário. Portanto, devemos poder conversar assim também em Java.

Quando a 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 calendário. Calendários diferentes terão datas diferentes. Isso é da 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 objeto que encapsula ano, mês etc.

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

user2835562
fonte
O fato de você poder armazenar o mesmo instante no tempo, mas relatar diferentes horas / minutos / dia / semana / ano / ano com base em diferentes sistemas de calendário, é uma força, não uma fraqueza. Reflete a realidade (complexa).
ThrawnCA
De fato, Datefoi re-desenvolvido; substituído pela java.time.Instantclasse. E Calendar/ GregorianCalendarfoi substituído por java.time.ZonedDateTimeclasse.
Basil Bourque
0

Entre "date" é geralmente marcado como "obsoleto / obsoleto" (não sei exatamente por que) - algo sobre ele está escrito lá Java: Por que o construtor Date está obsoleto e o que eu uso?

Parece que é um problema do construtor apenas via nova Data (int ano, int mês, int dia) , a maneira recomendada é via Calendar e defina parâmetros separadamente. ( Calendar cal = Calendar.getInstance (); )

xxxvodnikxxx
fonte
0

Uso o Calendário quando preciso de algumas operações específicas durante as datas, como mudar o horário, mas o Date acho útil quando você precisa formatar a data para adaptar suas necessidades, recentemente descobri que o Locale possui muitas operações e métodos úteis. Estou usando o Locale agora!

Brian Nelson
fonte
Para sua informação, as classes problemáticas Calendare Dateforam substituídas anos atrás pelas classes java.time . Não há necessidade de usar Dateou Calendar. E Localenão tem nada a ver com os significados dos objetos de data e hora. A Localeé usado apenas para especificar a linguagem humana e as normas culturais a serem usadas na localização ao gerar texto para representar o valor de um objeto de data e hora.
Basil Bourque