Classes

Classes de Data

Classes de data

Não é mais comum utilizar as classes mencionadas neste tutorial para interagir com tratamento e manipulação de datas na linguagem Java, pesquise e pratique sobre java.time

Trabalhar com datas na linguagem Java é uma jornada que inicialmente pode parecer um tanto complexa.

Classes de Data

Um calendário é um sistema que permite medir e representar graficamente o passar do tempo. Com origem etimológica no vocábulo latino calendarium, o calendário recorre à divisão temporária em unidades como anos, meses, semanas e dias.

Este calendário, instaurado pelo papa Gregório XIII em 1582, divide o ano em doze meses, compostos por sua vez entre 28 a 31 dias conforme o caso. O ano do calendário gregoriano começa a 1 de Janeiro e termina a 31 de Dezembro.

Outros calendários são o calendário juliano (que regia até à implementação do gregoriano), o calendário hebreu (também chamado de calendário judaico e qual é usado dentro do judaísmo), o calendário chinês e o calendário muçulmano, os quais se baseiam em diversos dados astronômicos.

Data e Hora

O mais fascinante na linguagem Java é a estruturação de classes que representam perfeitamente esta classificação do tempo.

Vamos apresentar as classes que você não poderá deixar de conhecer:

Quando compreendemos que data não é string já é um bom começo.

java.util.Calendar

A classe Calendar é uma classe abstrata que representa um instante de tempo distribuída em ANO, MES, DIA, HORA, MINUTO, SEGUNDO e MILISSEGUNDO.

Para criar uma instância de Calendar na sua aplicação, é necessário executar o método estático Calendar.getInstance() retornando um objeto do tipo java.util.GregorianCalendar.

java.util.GregorianCalendar[time=1677545679000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,
zone=sun.util.calendar.ZoneInfo[id="America/Sao_Paulo",offset=-10800000,
dstSavings=0,useDaylight=false,transitions=93,lastRule=null],firstDayOfWeek=1,
minimalDaysInFirstWeek=1,
ERA=1,YEAR=2023,MONTH=1,WEEK_OF_YEAR=9,WEEK_OF_MONTH=5,DAY_OF_MONTH=27,DAY_OF_YEAR=58,DAY_OF_WEEK=2,
DAY_OF_WEEK_IN_MONTH=4,AM_PM=1,HOUR=9,HOUR_OF_DAY=21,MINUTE=54,SECOND=39,
MILLISECOND=0,ZONE_OFFSET=-10800000,DST_OFFSET=0]
Sim, mas como iremos obter uma estrutura de data e hora em que estamos acostumados a compreender?

O primeiro ponto relevante de um calendário é que ele retorna objetos que representam data e hora na aplicação, e este objeto é do tipo java.util.Date.

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

        Calendar agora = Calendar.getInstance();

        Date data = agora.getTime();

        System.out.println(data);
        // Mon Feb 27 22:04:29 BRT 2023
    }
}
Assim como números, a representação de dados exige uma compreensão de valor literal versus a formatação aplicada com base é um idioma (locale).

Mas se é mais comum utilizar Date ao invés de Calender, quando instanciar Calendar faz sentido no dia-a-dia? E a resposta é: Quando você precisa realizar alterações no tempo ou obter informações de forma isolada, exemplo:

Vamos imaginar que com base no instante atual você gostaria aumentar em 30 dias e zerar os campos hora, minuto e segundo ?

public class CalendarApp {
   public static void main(String[] args) {
      Calendar agora = Calendar.getInstance();
    
      //adicionado um mês
      agora.add(Calendar.MONTH,1);
    
      //ou adicionando 30 dias corridos
      //agora.add(Calendar.DAY_OF_MONTH,30);
    
      //set = definir valores
      agora.set(Calendar.HOUR,0);
      agora.set(Calendar.MINUTE,0);
      agora.set(Calendar.SECOND,0);
      //são necessários, afinal o tempo é muiiiito específico
      agora.set(Calendar.MILLISECOND,0);
      agora.set(Calendar.AM_PM, Calendar.AM);
    
      System.out.println(agora.getTime());

      //Obtem o ano, dia do mês e semana do mês respectivamente
      System.out.println(calendar.get(Calendar.YEAR));
      System.out.println(calendar.get(Calendar.DAY_OF_MONTH));
      System.out.println(calendar.get(Calendar.WEEK_OF_MONTH));
   }
}
Cuidado com a pegadinha ao definir (set) mês em um calendar:
calendar.set(Calendar.MONTH,6); 
// aqui será Julio e não Junho, pois mês em Calendar começa com zero (0)

Sabemos que manipular o tempo exige uma certa pré-definição de valores, afinal não existem mês 13, dia 32, hora 25 e etc. Por isso, quando for manipular um calendário com base em fluxo de repetição onde um campo não deva modificar outro campo, opte por usar o método roll ao invés do add conforme ilustração abaixo:

Definir hora

public class CalendarApp {
   public static void main(String[] args) {
     Calendar calendar = Calendar.getInstance();
     System.out.println(calendar.getTime());
   
     //executa primeiro com esta linha
     calendar.add(Calendar.SECOND,65);
   
     //em seguida, comente a linha acima
     //e execute a linha abaixo
     //calendar.roll(Calendar.SECOND,65);
   
     System.out.println(calendar.getTime());

     //Mon Feb 27 22:48:23 BRT 2023
     //Mon Feb 27 22:48:28 BRT 2023
 }
}

java.util.GregorianCalendar

GregorianCalendar é uma implementação concreta da classe abstrata java.util.Calendar. Não surpreendentemente, o calendário gregoriano é o calendário civil mais utilizado no mundo.

Existem duas opções disponíveis para obter uma instância de GregorianCalendar: Calendar.getInstance() e usar um dos construtores.

Usar o método de fábrica estático Calendar.getInstance() não é uma abordagem recomendada, pois retornará uma instância subjetiva para a localidade padrão.
public class CalendarApp {
    public static void main(String[] args) {
        GregorianCalendar gregorianCalendar = new GregorianCalendar();
        System.out.println(gregorianCalendar.getTime());

        //05 de março de 2023 00:00:00 (lembra que o mês começa com zero)
        gregorianCalendar = new GregorianCalendar(2023, 2, 5);
        System.out.println(gregorianCalendar.getTime());

        //05 de março de 2023 23:17:14 (lembra que o mês começa com zero)
        gregorianCalendar = new GregorianCalendar(2023, 2, 5, 23, 17, 14);
        System.out.println(gregorianCalendar.getTime());

        /*
            Resultado no console respectivamente

            Tue Feb 28 09:40:51 BRT 2023
            Sun Mar 05 00:00:00 BRT 2023
            Sun Mar 05 23:17:14 BRT 2023
         */

    }
}

Fuso horário

Devemos levar em consideração que exibir data e hora também devemos nos preocupar com a localização relacionada ao meridiano.

No Brasil, existem 4 fusos horários e estão localizados a oeste do Marco Zero (Meridiano de Greenwich), incluindo as ilhas oceânicas e variando de duas a cinco horas a menos em relação ao meridiano principal. Como são medidos a partir de Greenwich, os fusos do Brasil são os fusos -2 GMT, -3 GMT, -4 GMT e -5 GMT, sendo o fuso -3 GMT o Horário Oficial de Brasília.

public class CalendarApp {
    public static void main(String[] args) {
        GregorianCalendar gregorianCalendar = new GregorianCalendar();
        DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");

        int f = 5;
        while(f>=2){
            formatter.setTimeZone(TimeZone.getTimeZone("GMT-" + f--));
            System.out.println(formatter.format(gregorianCalendar.getTime()));
        }
    }
    /* 
         2023-02-28 09:54:07 GMT-05:00
         2023-02-28 10:54:07 GMT-04:00
         2023-02-28 11:54:07 GMT-03:00
         2023-02-28 12:54:07 GMT-02:00
     */

java.util.Date

A classe Date é a representação fiel de uma data na linguagem Java, após explorarmos Calendar e GregorianCalender, é necessário estar convicto que tudo tem a finalidade de retornar uma data em nossa aplicação.

public class CalendarApp {
    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();
        GregorianCalendar gregorianCalendar = new GregorianCalendar();

        Date dateCalendar = calendar.getTime();
        Date dateGregorianCalender = gregorianCalendar.getTime();

        Date dateDefault = new Date();
        //evite usar
        Date date = new Date(2023,3,1);

        System.out.println(dateDefault.getTime());
        //retorna um número longo representado em milissegundos
    }
}
Atualmente a classe Date está depreciada (descontinuada, sem manutenções e melhorias )☠️. Opte por utilizar a LocalDate e LocalDateTime

java.text.DateFormat

A classe DateFormat é responsável por formatar objetos do tipo Date considerando um padrão baseado na localização (locale) da aplicação.

Para criar uma instãncia de NumberFormat é necessário executar alguns de seus métodos de inicialização.

  • DateFormat.getDateInstance() -> Retorna um formatador de data exibindo somente dia, mês e ano de acordo com sua localização.
  • DateFormat.getTimeInstance() -> Retorna um formatador de data exibindo somente hora, minuto e segundo de acordo com sua localização.
  • DateFormat.getDateTimeInstance() -> Retorna um formatador de data\hora de acordo com sua localização.
public class CalendarApp {
    public static void main(String[] args) {
        //iniciando um formatador de datas
        DateFormat formatador = DateFormat.getDateInstance();
        //criando um objeto calendar
        Calendar calendario = Calendar.getInstance();
        //Obtendo o objeto date para ser formatado
        Date data = calendario.getTime();
        System.out.println("Formato original da data é: " + data);
        //Usando um formatador para exibir a data formatada
        String dataFormatada = formatador.format(data);
        System.out.println("A data formatada é: " + dataFormatada);
        
        /*
           Formato original da data é: Tue Feb 28 13:33:34 BRT 2023
           A data formatada é: 28 de fev. de 2023
        */
    }
}

Estilos de formatação

Já pensou que você tenha a necessidade de exibir a mesma data com estilos diferentes?

Exemplo de uma data\hora explorando os estilos de formatação pré-definidos.

Data\hora: 28/02/2023 13:55:17

EstiloResultado
FULLterça-feira, 28 de fevereiro de 2023 13:55:17 Horário Padrão de Brasília
LONG28 de fevereiro de 2023 13:55:17 BRT
MEDIUM28 de fev. de 2023 13:55:17
SHORT28/02/2023 13:55
public class CalendarApp {
    public static void main(String[] args) {
        Calendar calendario = new GregorianCalendar(2023,1,28,13,55,17);
        for(int estilo=0; estilo<=3; estilo++){
            String style = estilo==0?"FULL":estilo==1?"LONG":estilo==2?"MEDIUM":"SHORT";
            
            DateFormat formatador = DateFormat.getDateTimeInstance(estilo,estilo);
            
            System.out.println("A data formatada com o estilo: " + style + " é: " + formatador.format(calendario.getTime()));
        }

    }
}

Formatação por região

Aprendemos que existem quatro estilos de formatação, porém ainda assim gostaríamos de aplicar uma formatação com base no idioma (localização) do usuário. Diante deste cenário, aplicamos a devida formatação considerando uma instância de Locale.

public class CalendarApp {
    public static void main(String[] args) {
        Calendar calendario = new GregorianCalendar(2023,1,28,13,55,17);

        for(int estilo=0; estilo<=3; estilo++){
            String style = estilo==0?"FULL":estilo==1?"LONG":estilo==2?"MEDIUM":"SHORT";

            Locale locale = Locale.US;
            //Locale localeBr = new Locale("pt","BR");
            DateFormat formatador = DateFormat.getDateTimeInstance(estilo,estilo, locale);
            System.out.println("A data formatada com o estilo: " + style + " é: " + formatador.format(calendario.getTime()));
            
            /*
                A data formatada com o estilo: FULL é: Tuesday, February 28, 2023 at 1:55:17 PM Brasilia Standard Time
                A data formatada com o estilo: LONG é: February 28, 2023 at 1:55:17 PM BRT
                A data formatada com o estilo: MEDIUM é: Feb 28, 2023, 1:55:17 PM
                A data formatada com o estilo: SHORT é: 2/28/23, 1:55 PM
             */
        }

    }
}

java.text.SimpleDateFormat

Já pensou agora o usuário solicitar que uma mesma data fosse apresentada conforme abaixo?

Data\hora: 28/02/2023 13:55:17

SolicitaçãoExemplo
Ano abreviado28/02/23
Somente ano-mês2023-02
Mês legendado abreviado28/fev./2023
Mês legendado completo28/fevereiro/2023
public class CalendarApp {
    public static void main(String[] args) {
        Calendar calendario = new GregorianCalendar(2023,1,28,13,55,17);

        //Ano abreviado
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd/MM/yy");
        System.out.println(simpleDateFormat.format(calendario.getTime()));

        //Somente ano e mês
        simpleDateFormat = new SimpleDateFormat("yyyy/MM");
        System.out.println(simpleDateFormat.format(calendario.getTime()));

        //Mês legendado abreviado
        simpleDateFormat = new SimpleDateFormat("dd/MMM/yyyy");
        System.out.println(simpleDateFormat.format(calendario.getTime()));

        //Mês legendado completo
        simpleDateFormat = new SimpleDateFormat("dd/MMMM/yyyy");
        System.out.println(simpleDateFormat.format(calendario.getTime()));

    }
}
Já que você aprendeu como formatar datas para string, qual praticar como converter (parse) string para datas ?
LetraCampoExemplo
GEra designatorAD
yYear2018 (yyyy), 18 (yy)
MMonth in yearJuly (MMMM), Jul (MMM), 07 (MM)
wResults in week in year16
WResults in week in month3
DGives the day count in the year266
dDay of the month09 (dd), 9(d)
FDay of the week in month4
EDay name in the weekTuesday, Tue
uDay number of weekwhere 1 represents Monday, 2 represents Tuesday and so on
aAM or PM markerAM
HHour in the day(0-23) 12
kHour in the day(1-24) 23
KHour in am/pmfor 12 hour format (0-11) 0
hHour in am/pmfor 12 hour format (1-12) 12
mMinute in the hour59
sSecond in the minute35
SMillisecond in the minute978
zTimezone Pacific StandardTime; PST; GMT-08:00
ZTimezone offset in hours (RFC pattern)-0800
XTimezone offset in ISO format-08; -0800; -08:00
A nossa jornada em trabalhar com Data na linguagem não para por aqui, conheça sobre o Java Time, um recurso super poderoso e repleto de novas funcionalidades.