CodeGym /Blogue Java /Random-PT /Como não se perder no tempo: DateTime e Calendar
John Squirrels
Nível 41
San Francisco

Como não se perder no tempo: DateTime e Calendar

Publicado no grupo Random-PT
Oi! Hoje vamos começar a trabalhar com um novo tipo de dados que não encontramos antes, ou seja, datas. Como não se perder no tempo: DateTime e Calendar - 1Acho que não preciso explicar o que é um encontro. :) Em princípio, poderíamos armazenar a data e hora atuais em uma String Java comum.

public class Main {
   public static void main(String[] args) {

       String date = "June 11, 2018";
       System.out.println(date);
   }
}
Mas essa abordagem tem muitas desvantagens. A Stringclasse foi projetada para trabalhar com texto e seus métodos são apropriados para essa tarefa. Se precisarmos manipular uma data de alguma forma (adicionar 2 horas, por exemplo), Stringnão funciona tão bem. Ou se quisermos exibir a data e hora atuais quando o programa é compilado. Stringtambém não ajuda aqui: quando você escrever o código e executá-lo, a hora terá mudado e o console exibirá as informações erradas. É por isso que os criadores de Java forneceram várias classes para trabalhar com datas e horas. O primeiro deles éjava.util.Date

data classe

Especificamos seu nome completo, porque outro pacote Java possui a java.sql.Dateclasse. Não os misture! A primeira coisa que você precisa saber sobre ele é que ele armazena a data como o número de milissegundos que se passaram desde 1º de janeiro de 1970. Esse sistema de tempo tem até seu próprio nome: " Unix-time " Uma abordagem bastante interessante, não você concorda? :) A segunda coisa que vale a pena lembrar é esta: Se você criar um Dateobjeto usando o construtor padrão, o resultado representará a data e hora atuais no momento em que o objeto foi criado . Lembra que dissemos que uma data representada como uma Stringlutaria com essa tarefa? A Dateclasse lida com isso com facilidade.

public class Main {
   public static void main(String[] args) {

       Date date = new Date();
       System.out.println(date);
   }
}
Execute este código várias vezes e você verá a hora mudar repetidamente. :) Isso é possível porque o tempo é armazenado em milissegundos: são unidades de tempo extremamente pequenas, portanto os resultados são altamente precisos. A Dateclasse outro construtor: você pode passar o número exato de milissegundos desde 00:00 de 1º de janeiro de 1970 até a data necessária e um objeto de data correspondente será criado:

public class Main {
   public static void main(String[] args) {

       Date date = new Date(1212121212121L);
       System.out.println(date);
   }
}
Saída do console: Sex May 30 04:20:12 GMT 2008 Temos 30 de maio de 2008. "Sex" indica o dia da semana (sexta-feira, duh) e GMT é o fuso horário (Greenwich Mean Time). Os milissegundos são passados ​​como longs, porque o número de milissegundos geralmente não cabe em um int. Então, quais operações com datas podemos precisar realizar? Bem, o mais óbvio, claro, é a comparação . Para determinar se uma data vem antes ou depois de outra. Isto pode ser feito de várias maneiras. Por exemplo, você pode chamar o Date.getTime()método, que retorna o número de milissegundos decorridos desde a meia-noite de 1º de janeiro de 1970. Basta chamá-lo em dois objetos Date e comparar os resultados:

public class Main {
   public static void main(String[] args) {

       Date date1 = new Date();

       Date date2 = new Date();

       System.out.println((date1.getTime() > date2.getTime())?
               "date1 is later than date2" : "date1 is earlier than date2");
   }
}
Saída: date1 é anterior a date2 Mas também há uma maneira mais conveniente, ou seja, usando métodos especiais fornecidos pela classe Date: before(), after()e equals(). Todos eles retornam um valor booleano. O before()método verifica se nossa data é anterior à data passada como argumento:

public class Main {
   public static void main(String[] args) throws InterruptedException {

       Date date1 = new Date();

       Thread.sleep(2000);// Suspend the program for 2 seconds
       Date date2 = new Date();

       System.out.println(date1.before(date2));
   }
}
Saída do console: true Da mesma forma, o after()método verifica se nossa data é posterior à data passada como argumento:

public class Main {
   public static void main(String[] args) throws InterruptedException {

       Date date1 = new Date();

       Thread.sleep(2000);// Suspend the program for 2 seconds
       Date date2 = new Date();

       System.out.println(date1.after(date2));
   }
}
Saída do console: false Em nossos exemplos, "colocamos o programa em hibernação" por 2 segundos, para garantir que as duas datas sejam diferentes. Em computadores rápidos, o tempo entre a criação de date1e date2pode ser inferior a um milissegundo, fazendo com que ambos before()e after()retornem falsos. Mas neste caso, o equals()método retornará true! Afinal, ele compara o número de milissegundos desde 00:00 em 1º de janeiro de 1970 para cada data. Os objetos são considerados iguais apenas se corresponderem ao milissegundo :

public static void main(String[] args) {

   Date date1 = new Date();
   Date date2 = new Date();

   System.out.println(date1.getTime());
   System.out.println(date2.getTime());

   System.out.println(date1.equals(date2));
}
Aqui está outra coisa que você precisa prestar atenção. Se você abrir a documentação da Dateclasse no site da Oracle , verá que muitos de seus métodos e construtores foram marcados como obsoletos (ou seja, não recomendados para uso). Aqui está o que os criadores de Java têm a dizer sobre partes de classes que foram descontinuadas:
"Um elemento de programa com a anotação @Deprecated é algo que os programadores não são recomendados para usar, geralmente porque é perigoso ou porque existe uma alternativa melhor."
Isso não significa que esses métodos não possam ser usados. Se você tentar executar o código usando métodos obsoletos em um IDE, provavelmente funcionará. Por exemplo, considere o Date.getHours()método obsoleto, que retorna o número de horas associado a um Dateobjeto.

public static void main(String[] args) {

   Date date1 = new Date();

   System.out.println(date1.getHours());
}
Se você iniciar o código em 14:21 (2:21 PM), ele exibirá o número 14. Como você pode ver, o método obsoleto está riscado, mas ainda funciona. Esses métodos não são removidos para não quebrar o enorme corpo de código existente que os utiliza. Em outras palavras, esses métodos não são "quebrados" nem "removidos". Eles simplesmente não são recomendados para uso porque uma alternativa mais conveniente está disponível. Aliás, a documentação menciona especificamente esta alternativa:
Como não se perder no tempo: DateTime e Calendar - 2
A maioria dos Datemétodos da classe foi movida para a Calendarclasse aprimorada e estendida. Vamos nos familiarizar com essa classe a seguir. :)

Aula de calendário

O JDK 1.1 introduziu uma nova classe: Calendar. Tornou o trabalho com datas em Java um pouco mais fácil do que antes. A única implementação da classe Calendarcom a qual trabalharemos é a GregorianCalendarclasse. Ele implementa o calendário gregoriano, que é observado pela maioria dos países do mundo. Sua principal vantagem é poder trabalhar com datas em um formato mais conveniente. Por exemplo, pode:
  • Adicionar um mês ou dia à data atual
  • Verifique se o ano é bissexto;
  • Retorne componentes individuais da data (por exemplo, extraia o número do mês de uma data inteira)
  • Ele também contém um sistema muito conveniente de constantes (muitas das quais veremos abaixo).
Outro aprimoramento importante da Calendarclasse é sua constante Calendar.ERA : você pode indicar uma data antes da era comum (BC - antes de Cristo) ou na era comum (AD - Anno Domini). Vejamos tudo isso com exemplos. Vamos criar um calendarobjeto com a data de 25 de janeiro de 2017:

public static void main(String[] args) {

  Calendar calendar = new GregorianCalendar(2017, 0 , 25);
}
Na Calendarclasse (assim como na Dateclasse), os meses começam em zero , então passamos o número 0 como o segundo argumento. Ao trabalhar com a Calendarturma, é importante entender que isso é apenas isso, um calendário , não uma data individual. Como não se perder no tempo: DateTime e Calendar - 3 Uma data é apenas alguns números que indicam um intervalo de tempo específico. Um calendário é todo um sistema que permite fazer muitas coisas com datas. :) Isso é bastante aparente se você tentar exibir o Calendarobjeto: Saída: java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/London",offset=0,dstSavings=0,useDaylight= false,transitions=79,lastRule=null],firstDayOfWeek=2,minimalDaysInFirstWeek=1,ERA=?,YEAR=2017,MONTH=0,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_MONTH=25,DAY_OF_YEAR=?,DAY_OF_WEEK=? ,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?] Veja quantas informações você obtém! Um calendário tem um monte de propriedades que uma data normal não tem, e todas elas são exibidas (é assim que otoString()método funciona naCalendarclasse). Se você só precisa obter uma data simples do calendário, ou seja, umDateobjeto, use oCalendar.getTime()método (o nome não é o mais lógico, mas o que você pode fazer?):

public static void main(String[] args) {

   Calendar calendar = new GregorianCalendar(2017, 0 , 25);
   Date date = calendar.getTime();
   System.out.println(date);
}
Saída: Quarta-feira, 25 de janeiro 00:00:00 GMT 2017 Agora pegamos o calendário e o "reduzimos" a uma data comum. Vamos mais longe. Além de designar meses por seu número, você pode usar os valores de campo constantesCalendar da classe . Essas constantes são campos estáticos da classe com um valor predefinido que não pode ser alterado. Na verdade, essa é uma opção ainda melhor, porque usá-los melhora a legibilidade do seu código. Calendar

public static void main(String[] args) {
   GregorianCalendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
}
Calendar.JANUARY é uma das constantes que representam os meses do ano. Usando essas constantes nomeadas, ninguém esquecerá, por exemplo, que o número 3 significa abril, e não o terceiro mês, que gostamos de chamar de março. Basta escrever Calendar.APRIL e pronto. :) Todos os campos do calendário (número, mês, minutos, segundos, etc.) podem ser especificados separadamente usando oset()método. Esse método é muito conveniente, porque aCalendarclasse possui uma constante para cada campo e o código resultante é muito fácil de ler. No último exemplo, criamos uma data, mas não definimos um horário para ela. Vamos marcar a hora 19:42:12

public static void main(String[] args) {
   Calendar calendar = new GregorianCalendar();
   calendar.set(Calendar.YEAR, 2017);
   calendar.set(Calendar.MONTH, 0);
   calendar.set(Calendar.DAY_OF_MONTH, 25);
   calendar.set(Calendar.HOUR_OF_DAY, 19);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   System.out.println(calendar.getTime());
}
Saída: Qua Jan 25 19:42:12 GMT 2017 Chamamos o set()método, passando uma constante (dependendo do campo que queremos alterar) e o novo valor para o campo. Acontece que esse set()método é uma espécie de "superconfigurador" que sabe definir o valor não apenas para um campo, mas para muitos campos. :) A Calendarclasse usa o add()método para somar e subtrair valores. Você passa no campo que deseja alterar, e um número (exatamente quanto deseja somar/subtrair do valor atual). Por exemplo, vamos pegar uma data 2 meses antes da data que criamos:

public static void main(String[] args) {
   Calendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
   calendar.set(Calendar.HOUR, 19);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   calendar.add(Calendar.MONTH, -2); // To subtract, pass a negative number
   System.out.println(calendar.getTime());
}
Saída: Sex 25 de novembro 19:42:12 GMT 2016 Muito bom! Marcamos a data há 2 meses. Isso não fez apenas com que o mês mudasse: o ano também mudou de 2017 para 2016. Claro, ao converter datas, o ano atual é calculado automaticamente, sem a necessidade de você acompanhá-lo manualmente. Mas se, por algum motivo, você precisar desativar esse comportamento, poderá fazê-lo. O roll()método pode adicionar e subtrair valores sem afetar os valores restantes . Por exemplo, assim:

public static void main(String[] args) {
   Calendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
   calendar.set(Calendar.HOUR, 10);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   calendar.roll(Calendar.MONTH, -2);
   System.out.println(calendar.getTime());
}
Fizemos exatamente o mesmo que no exemplo anterior: levamos 2 meses a partir da data atual. Mas agora o código faz algo diferente: o mês mudou de janeiro para novembro, mas o ano permanece inalterado - 2017! Saída: Sáb 25 de novembro 10:42:12 GMT 2017 Seguindo em frente. Como dissemos acima, podemos obter todos os Calendarcampos separadamente. Fazemos isso com o get()método:

public static void main(String[] args) {
   GregorianCalendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
   calendar.set(Calendar.HOUR, 10);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   System.out.println("Year: " + calendar.get(Calendar.YEAR));
   System.out.println("Month: " + calendar.get(Calendar.MONTH));
   System.out.println("Week in the month: " + calendar.get(Calendar.WEEK_OF_MONTH));// Week in this month?

   System.out.println("Day: " + calendar.get(Calendar.DAY_OF_MONTH));

   System.out.println("Hours: " + calendar.get(Calendar.HOUR));
   System.out.println("Minutes: " + calendar.get(Calendar.MINUTE));
   System.out.println("Seconds: " + calendar.get(Calendar.SECOND));
   System.out.println("Milliseconds: " + calendar.get(Calendar.MILLISECOND));

}
Saída: Ano: 2017 Mês: 0 Semana do mês: 5 Dia: 25 Horas: 10 Minutos: 42 Segundos: 12 Milissegundos: 0 Portanto, além do Calendar"super-setter" da classe, também existe um "super-getter" ". :) Claro, outro aspecto interessante desta classe é trabalhar com eras. Para criar uma data "BC", você precisará usar o campo Calendar.ERA Por exemplo, vamos criar uma data para a Batalha de Canas, onde Aníbal derrotou o exército romano. Isso aconteceu em 2 de agosto de 216 aC:

public static void main(String[] args) {
   GregorianCalendar cannae = new GregorianCalendar(216, Calendar.AUGUST, 2);
   cannae.set(Calendar.ERA, GregorianCalendar.BC);

   DateFormat df = new SimpleDateFormat("MMM dd, yyy GG");
   System.out.println(df.format(cannae.getTime()));
}
Aqui usamos a SimpleDateFormatclasse para imprimir a data em um formato mais fácil de entendermos (as letras "GG" indicam que queremos que a era seja exibida). Saída: 02 de agosto de 216 aC. A Calendarclasse tem muito mais métodos e constantes. Você pode ler sobre eles na documentação . Se não gostar deste formato de data, 25 de novembro 10:42:12 GMT 2017 , você pode usá-lo SimpleDateFormatpara torná-lo facilmente o que deseja.

public static void main(String[] args) {

   SimpleDateFormat dateFormat = new SimpleDateFormat("EEEE, MMMM d, yyyy");
   Calendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
   calendar.set(Calendar.HOUR, 10);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   calendar.roll(Calendar.MONTH, -2);
   System.out.println(dateFormat.format(calendar.getTime()));
}
Saída: sábado, 25 de novembro de 2017 Muito melhor, não é? :)
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION