JavaRush /Blogue Java /Random-PT /Como não se perder no tempo – DateTime e Calendar

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

Publicado no grupo Random-PT
Olá! Hoje começaremos a trabalhar com um novo tipo de dados que não encontramos antes, nomeadamente datas. Como não se perder no tempo - DateTime e Calendar - 1Acho que não há necessidade de explicar o que é uma data :) Em princípio, é bem possível escrever a data e a hora atuais em Java em uma string normal.
public class Main {
   public static void main(String[] args) {

       String date = "June 11, 2018";
       System.out.println(date);
   }
}
Mas esta abordagem tem muitas desvantagens. A classe Stringfoi criada para trabalhar com texto e possui métodos apropriados. Se precisarmos gerenciar a data de alguma forma (adicionar 2 horas, por exemplo), Stringnão funcionará aqui. Ou, por exemplo, exiba a data e hora atuais no momento em que o programa foi compilado no console. Aqui Stringtambém não vai adiantar: enquanto você escreve o código e o executa, o tempo mudará e o irrelevante será exibido no console. Portanto, em Java, seus criadores disponibilizaram diversas classes para trabalhar com datas e horas. O primeiro é a aulajava.util.Date

Classe de data Java

Demos a ele o nome completo porque também existe uma classe em outro pacote em Java java.sql.Date. Não se confunda! A primeira coisa que você precisa saber é que ele armazena em milissegundos a data que se passou desde 1º de janeiro de 1970. Existe até um nome separado para esta data - “Hora Unix”. Uma forma bastante interessante, não concorda? :) A segunda coisa a lembrar: se você criar um objeto Datecom um construtor vazio, o resultado será a data e hora atuais no momento em que o objeto foi criado . StringVocê se lembra de como escrevemos que tal tarefa seria problemática para um formato de data ? A turma Dateresolve isso facilmente.
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á como o tempo vai mudar a cada vez :) Isso é possível justamente porque ele é armazenado em milissegundos: são a menor unidade de tempo, por isso os resultados são tão precisos. Existe outro construtor para Date: você pode especificar o número exato de milissegundos que se passaram desde 00:00 de 1º de janeiro de 1970 até a data necessária, e ele será criado:
public class Main {
   public static void main(String[] args) {

       Date date = new Date(1212121212121L);
       System.out.println(date);
   }
}
Saída do console:

Fri May 30 08:20:12 MSD 2008
Recebemos em 30 de maio de 2008. “Sex” significa o dia da semana - “sexta-feira” (sexta-feira) e MSD - “horário de verão de Moscou” (horário de verão de Moscou). Milissegundos são transmitidos no formato long, já que seu número geralmente não cabe int. Então, que tipo de operações de data podemos precisar em nosso trabalho? Bem, a coisa mais óbvia, claro, é a comparação . Determine se uma data foi posterior ou anterior a outra. Isso pode ser feito de diferentes maneiras. Por exemplo, você pode chamar o método . Date.getTime(), que retornará o número de milissegundos que se passaram desde a meia-noite de 1º de janeiro de 1970. Vamos apenas chamá-lo em dois objetos Date e compará-los entre si:
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");
   }
}
Conclusão:

date1 раньше date2
Mas existe uma maneira mais conveniente, a saber, usar métodos especiais da classe Date: before()e . Todos eles retornam o resultado em . O método verifica se nossa data é anterior àquela que passamos como argumento: after()equals()booleanbefore()
public class Main {
   public static void main(String[] args) throws InterruptedException {

       Date date1 = new Date();

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

       System.out.println(date1.before(date2));
   }
}
Saída do console:

true
O método funciona de maneira semelhante after(); ele verifica se nossa data foi posterior àquela que passamos como argumento:
public class Main {
   public static void main(String[] args) throws InterruptedException {

       Date date1 = new Date();

       Thread.sleep(2000);//pause 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 que as duas datas sejam garantidamente diferentes. Em computadores rápidos, o tempo entre a criação date1de e date2pode ser inferior a um milissegundo; nesse caso, e before()e after()retornarão false. Mas o método equals()em tal situação retornará true! Afinal, ele compara exatamente o número de milissegundos que se passaram desde 00h00 de 1º de janeiro de 1970 para cada data. Os objetos só serão considerados iguais se corresponderem até o 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 classe Dateno site da Oracle, verá que muitos de seus métodos e construtores foram designados como Deprecated(“obsoletos”). Aqui, veja: Data da Classe Aqui está o que os próprios criadores de Java dizem sobre as partes das classes que se tornaram obsoletas: “Um elemento de programa anotado com @Deprecated é algo que os programadores são desencorajados de usar, geralmente porque é perigoso, ou porque isso existe uma alternativa melhor.” Isso não significa que esses métodos não possam ser usados. Além disso, se você mesmo tentar executar o código usando-os no IDEA, provavelmente funcionará. Tomemos por exemplo o método obsoleto Date.getHours(), que retorna o número de horas do objeto Date.
public static void main(String[] args) {

   Date date1 = new Date();

   System.out.println(date1.getHours());

}
Se no momento em que você executa o código, por exemplo, o horário for 14:21, ele exibirá o número 14. Como você pode ver, o método obsoleto está riscado, mas funciona muito bem. Esses métodos não foram removidos completamente, para não quebrar um monte de código já escrito com eles. Ou seja, esses métodos não estão “quebrados” ou “removidos”, simplesmente não são recomendados para uso devido à disponibilidade de uma alternativa mais conveniente. A propósito, está escrito sobre isso na documentação: Como não se perder no tempo - DateTime e Calendar - 2A maioria dos métodos da classe Date foram movidos para sua versão aprimorada e estendida - a classe Calendar. Iremos conhecê-lo melhor :)

Calendário Java

Java 1.1 introduziu uma nova classe - Calendar. Ele tornou o trabalho com datas em Java um pouco mais fácil do que parecia antes. A única implementação da classe Calendarcom a qual trabalharemos é a classe GregorianCalendar(ela implementa o calendário gregoriano, segundo o qual vive a maioria dos países do mundo). Sua principal comodidade é poder trabalhar com datas em um formato mais conveniente. Por exemplo, ele pode:
  • Adicione um mês ou dia à data atual
  • Verifique se o ano é bissexto;
  • Obtenha componentes de data individuais (por exemplo, obtenha o número do mês de uma data inteira)
  • E também dentro dele foi desenvolvido um sistema de constantes muito conveniente (veremos muitos deles a seguir).
Outra diferença importante da classe Calendaré que ela implementa uma constante Calendar.Era: você pode definir a data para a era AC (“Antes de Cristo” - antes do nascimento de Cristo, ou seja, “antes de nossa era”) ou AC (“Depois de Cristo” - “ nossa época"). Vejamos tudo isso com exemplos. Vamos criar um calendário com a data 25 de janeiro de 2017:
public static void main(String[] args) {

  Calendar calendar = new GregorianCalendar(2017, 0 , 25);
}
Os meses da turma Calendar(como em Date, aliás) começam do zero, então passamos o número 0 como segundo argumento. O principal ao trabalhar com uma turma Calendaré entender que se trata de um calendário e não de uma data separada. Como não se perder no tempo - DateTime e Calendar - 3Uma data é simplesmente uma série de números que representam um período específico de tempo. E um calendário é um dispositivo completo com o qual você pode fazer muitas coisas com datas :) Isso pode ser visto claramente se você tentar enviar o objeto Calendário para o console: Saída:

java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/Moscow",offset=10800000,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 quanta informação existe! O calendário possui várias propriedades que uma data normal não possui, e todas elas são enviadas para o console (é assim que funciona o método toString()na classe Calendar). Se, ao trabalhar, você só precisa obter uma data simples do calendário, ou seja, objeto Date- isso é feito usando um método Calendar.getTime()(o nome não é o mais lógico, mas nada pode ser feito):
public static void main(String[] args) {

   Calendar calendar = new GregorianCalendar(2017, 0 , 25);
   Date date = calendar.getTime();
   System.out.println(date);
}
Conclusão:

Wed Jan 25 00:00:00 MSK 2017
Agora “simplificamos” o calendário para uma data normal. Vamos continuar. Além dos símbolos numéricos para meses, Calendarconstantes podem ser usadas em sala de aula. Constantes são campos estáticos de uma classe Calendarcom um valor já definido que não pode ser alterado. Esta opção é realmente melhor, pois melhora a legibilidade do código.
public static void main(String[] args) {
   GregorianCalendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
}
Calendar.JANUARY— uma das constantes para indicar o mês. Com esta opção de nomenclatura, ninguém esquecerá, por exemplo, que o número “3” significa abril, e não o terceiro mês a que estamos habituados - março. Basta escrever Calendar.APRIL- e pronto :) Todos os campos do calendário (dia, mês, minutos, segundos, etc.) podem ser definidos individualmente usando o método set(). É muito conveniente, pois Calendarcada campo possui sua própria constante na classe e o código final parecerá o mais simples possível. Por exemplo, no exemplo anterior, criamos uma data, mas não definimos a hora atual para ela. Vamos definir o horário para 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());
}
Conclusão:

Wed Jan 25 19:42:12 MSK 2017
Chamamos o método set(), passamos uma constante para ele (dependendo do campo que queremos alterar) e um novo valor para este campo. Acontece que o método set()é uma espécie de “supersetter” que pode definir um valor não para um campo, mas para vários campos :) A adição e subtração de valores em uma classe Calendaré realizada usando o método add(). Você precisa passar nele o campo que deseja alterar e o número - exatamente quanto deseja adicionar/subtrair do valor atual. Por exemplo, vamos definir a data que criamos para 2 meses atrás:
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 a value - a negative number must be passed to the method
   System.out.println(calendar.getTime());
}
Conclusão:

Fri Nov 25 19:42:12 MSK 2016
Ótimo! Redefinimos a data para 2 meses atrás. Com isso, não só o mês, mas também o ano mudou, de 2017 para 2016. O cálculo do ano corrente na mudança de datas, claro, é feito de forma automática e não precisa ser controlado manualmente. Mas se por algum motivo você precisar desabilitar esse comportamento, você pode fazer isso. Um método especial roll()pode adicionar e subtrair valores sem afetar outros valores. 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 - subtraímos 2 meses da data atual. Mas agora o código funcionou de forma diferente: o mês mudou de janeiro para novembro, mas o ano permaneceu igual a 2017! Conclusão:

Sat Nov 25 10:42:12 MSK 2017
Avançar. Como dissemos acima, todos os campos de um objeto Calendarpodem ser obtidos separadamente. O método é responsável por isso get():
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("Number of the week in the month: " + calendar.get(Calendar.WEEK_OF_MONTH));// serial number of the week in the month

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

   System.out.println("Watch: " + 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));

}
Conclusão:

Год: 2017 
Месяц: 0 
Порядковый номер недели в месяце: 4 
Число: 25 
Часы: 10 
Минуты: 42 
Секунды: 12 
Миллисекунды: 0
Ou seja, além do “super-setter” da turma Calendartambém existe um “super-getter” :) Outro ponto interessante é, claro, trabalhar com eras. Para criar uma data “BC” é necessário utilizar o campo Calendar.Era Por exemplo, vamos criar uma data indicando a Batalha de Canas, na qual Aníbal derrotou o exército de Roma. Isso aconteceu em 2 de agosto de 216 AC. ex.:
public static void main(String[] args) {
   GregorianCalendar cannes = new GregorianCalendar(216, Calendar.AUGUST, 2);
   cannes.set(Calendar.ERA, GregorianCalendar.BC);

   DateFormat df = new SimpleDateFormat("dd MMM yyy GG");
   System.out.println(df.format(cannes.getTime()));
}
Aqui utilizamos a classe SimpleDateFormatpara exibir a data em um formato que nos seja mais compreensível (as letras “GG” são responsáveis ​​por exibir a época). Conclusão:

02 авг 216 до н.э.
CalendarExistem muitos mais métodos e constantes na classe , leia sobre eles na documentação:

Convertendo string em data

Para converter String em Data, você pode usar a classe auxiliar Java - SimpleDateFormat . Esta é a classe que você precisa para converter uma data em um formato que você definir. Como não se perder no tempo – DateTime e Calendar – 5Por sua vez, é muito semelhante ao DateFormat . A única diferença notável entre os dois é que SimpleDateFormat pode ser usado para formatação (conversão de uma data em uma string) e análise da string em uma data com reconhecimento de localidade, enquanto DateFormat não oferece suporte a uma localidade. Além disso, DateFormat é uma classe abstrata que fornece suporte básico para formatação e análise de datas, enquanto SimpleDateFormat é uma classe concreta que estende a classe DateFormat. Este é o exemplo de criação de um objeto SimpleDateFormat e formatação de uma data:
SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date(1212121212121L);

System.out.println(formatter.format(date));
No exemplo acima usamos o padrão "yyyy-MM-dd HH:mm:ss" que significa:
  • 4 dígitos para ano (aaaa);
  • 2 dígitos para mês (MM);
  • 2 dígitos para dia (dd);
  • 2 dígitos para horas no formato 24 horas (HH);
  • 2 dígitos para minutos (mm);
  • 2 dígitos para segundos (ss).
As marcas de separação e a ordem dos símbolos do padrão são preservadas. Saída do console:
2008-05-30 08:20:12
Existem muitos modelos de cartas para a classe SimpleDateFormat . Para que você não se confunda, reunimos em uma tabela:
Símbolo Descrição Exemplo
G era (na localização em inglês - AD e BC) DE ANÚNCIOS
sim ano (número de 4 dígitos) 2020
aa ano (últimos 2 dígitos) 20
aaaa ano (número de 4 dígitos) 2020
M número do mês (sem zeros à esquerda) 8
MILÍMETROS número do mês (com zeros à esquerda se o número do mês <10) 04
MMM abreviatura de três letras do mês (de acordo com a localização) janeiro
MMMM nome completo do mês Junho
c semana do ano (sem zeros à esquerda) 4
uau semana do ano (com zeros à esquerda) 04
C semana no mês (sem zeros à esquerda) 3
Guerra Mundial semana no mês (com zero à esquerda) 03
D dia do ano 67
d dia do mês (sem zeros à esquerda) 9
dd dia do mês (com zeros à esquerda) 09
F dia da semana no mês (sem zeros à esquerda) 9
FF dia da semana no mês (com zeros à esquerda) 09
E dia da semana (abreviatura) C
EEEE dia da semana (completo) Sexta-feira
você número do dia da semana (sem zeros à esquerda) 5
você número do dia da semana (com zeros à esquerda) 05
a Marcador AM/PM SOU.
H horas no formato de 24 horas sem zeros à esquerda 6
HH relógio no formato de 24 horas com zero à esquerda 06
k número de horas no formato de 24 horas 18
K número de horas no formato de 12 horas 6
h hora no formato de 12 horas sem zeros à esquerda 6
ah hora no formato de 12 horas com zero à esquerda 06
eu minutos sem zeros à esquerda 32
milímetros minutos com zero à esquerda 32
é segundos sem zeros à esquerda onze
ss segundos com zero à esquerda onze
S milissegundos 297
z Fuso horário EET
Z fuso horário no formato RFC 822 300
Exemplos de combinações de caracteres padrão:
Amostra Exemplo
dd-MM-aaaa 11/01/2020
aaaa-MM-dd 01/10/2019
HH:mm:ss.SSS 23:59.59.999
aaaa-MM-dd HH:mm:ss 30/11/2018 03:09:02
aaaa-MM-dd HH:mm:ss.SSS 01-03-2016 01:20:47.999
aaaa-MM-dd HH:mm:ss.SSS Z 13/13/2013 23:59:59.999 +0100
Se você cometer um pequeno erro com o formato, poderá se tornar o proprietário de um java.text.ParseException, e isso não é uma conquista particularmente agradável. Bem, a breve excursão ao SimpleDateFormat acabou - vamos voltar à tradução da string java até o momento . SimpleDateFormat nos oferece esses recursos e percorreremos esse processo passo a passo.
  1. Crie uma linha a partir da qual você precisa definir a data:

    String strDate = "Sat, April 4, 2020";
  2. Criamos um novo objeto SimpleDateFormat com um modelo que corresponde ao que temos na string (caso contrário não poderemos analisá-lo):

    SimpleDateFormat formatter = new SimpleDateFormat("EEE, MMMM d, yyyy", Locale.ENGLISH);

    Como você pode ver, temos um argumento Locale aqui. Se o omitirmos, usaremos o Locale padrão, que nem sempre é o inglês.

    Se o código do idioma não corresponder à string de entrada, os dados da string vinculados ao idioma, como o nosso Mon ou April , não serão reconhecidos e lançarão um java.text.ParseException, mesmo que o padrão corresponda.

    No entanto, não precisamos especificar o formato se estivermos usando um modelo que não seja específico do idioma. Por exemplo - aaaa-MM-dd HH:mm:ss

  3. Criamos uma data usando um formatador, que por sua vez a analisa a partir da string de entrada:

    try {
      Date date = formatter.parse(strDate);
      System.out.println(date);
    }
    catch (ParseException e) {
      e.printStackTrace();
    }

    Saída do console:

    
    Sat Apr 04 00:00:00 EEST 2020

    Hummm... Mas o formato já não é o mesmo!

    Para fazer o mesmo formato, usamos novamente o formatador:

    System.out.println(formatter.format(date));

    Saída do console:

    
    Sat, April 4, 2020

SimpleDateFormat e calendário

SimpleDateFormat permite formatar todos os objetos de data e calendário criados para uso posterior. Consideremos um ponto tão interessante como trabalhar com épocas. Para criar uma data “BC”, você precisa usar o campo Calendar.Era. Por exemplo, vamos criar uma data indicando a Batalha de Canas, na qual Aníbal derrotou o exército de Roma. Isso aconteceu em 2 de agosto de 216 AC. ex.:
public static void main(String[] args) {
   GregorianCalendar cannes = new GregorianCalendar(216, Calendar.AUGUST, 2);
   cannes.set(Calendar.ERA, GregorianCalendar.BC);

   DateFormat df = new SimpleDateFormat("dd MMM yyy GG");
   System.out.println(df.format(cannes.getTime()));
}
Aqui utilizamos a classe SimpleDateFormat para exibir a data em um formato que nos seja mais compreensível (conforme indicado acima, as letras “GG” são responsáveis ​​por exibir a época). Conclusão:

02 авг 216 до н.э.

Formato de data Java

Aqui está outro caso. Suponhamos que este formato de data não nos convém:

Sat Nov 25 10:42:12 MSK 2017
Então aqui está. Usando nossos recursos no formato de data java, você pode alterá-lo para o seu próprio sem muita dificuldade:
public static void main(String[] args) {

   SimpleDateFormat dateFormat = new SimpleDateFormat("EEEE, d MMMM 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()));
}
Conclusão:

суббота, 25 Ноябрь 2017
Muito melhor, certo? :)
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION