A API de data do JAVA 8
Como já vimos neste mesmo bat-blog trabalhar com datas no Java nunca foi uma coisa legal, muitos desenvolvedores utilizavam o projeto Joda Time para facilitar isso e ele foi tão bem aceito que se tornou a base para a API Date and Time API do JAVA 8.
Uma das características novas das datas é que agora elas são imutáveis, ou seja, elas não podem ser modificadas após sua criação, sempre que adicionarmos/subtraímos dias, meses, anos, minutos, estamos criando um novo objeto(como quando estamos trabalhando com uma String). Outra grande mudança é que agora os números dos meses não começam por 0, finalmente Janeiro sendo o mês 1 e não 0.
Temos um novo pacote(java.time
) com várias classe para trabalhar com objetos que armazenam somente datas, apenas horas ou ambas simultaneamente.
Data – LocalDate
Para criar um objeto que representa somente a data existe a classe LocalDate
, que possui um método estático now
que retorna a data atual do sistema operacional.
LocalDate dataAtual = LocalDate.now();
System.out.println("Data Atual:"+dataAtual);
Note que a a data já foi mostrada no formato aaaa-mm-dd
.
Se for necessário criar uma data a partir de parâmetros, existe o método estático of( int ano , int mes , int dia)
que retorna um objeto com os valores informados.
LocalDate dataNatal = LocalDate.of( 2014 , 12, 25 );
System.out.println("Natal: "+dataNatal);
Outra opção pode ser criar um objeto LocalDate
com a data do sistema e alterá-la através dos métodos withYear(int)
, withMonth(int)
e withDayOf(int)
. Estes métodos retornam um novo objeto com a data alterada.
LocalDate data = LocalDate.now();
System.out.println("Data Inicial: "+data);
data = data.withYear(2015);
System.out.println("Data com ano modificado: "+data);
data = data.withMonth(1);
System.out.println("Data com mês modificado: "+data);
data = data.withDayOfMonth(15);
System.out.println("Data com dia modificado: "+data);
Lembrando que os objetos de data são imutáveis, então sempre que chamamos um método que modifica(na verdade cria um novo objeto) uma data devemos atribuir seu retorno novamente para a mesma variável, ou a “alteração será perdida”.
Uma tarefa que ficou muito simples(sem o uso de constantes) com a nova API foi adicionar dias, meses, anos a uma data, sendo feito através dos métodos plusDays(int)
, plusMonths(int)
, plusYears(int)
para adicionar e minusDays(int)
, minusMonths(int)
, minusYears(int)
para subtrair.
Lembrando que como cada método retorna um objeto podemos encadear as chamadas.
LocalDate dataEnc = LocalDate.of(2014,10,10).plusMonths(4).plusDays(7);
System.out.println("Data com 7 dias e 4 meses adicionada: "+dataEnc);
Se for necessário pegar o ano, mês ou dia separadamente do objeto de data podemos utilizar os seguintes métodos:
LocalDate d = LocalDate.now();
System.out.println("DIA: "+d.getDayOfMonth() );
System.out.println("MÊS: "+d.getMonthValue() );
System.out.println("ANO: "+d.getYear() );
Também é possível pegar o mês de forma textual através de getMonth()
que retorna o Enum Month
, mas ele retornará por padrão em inglês, o qual pode ser formatado através do método getDisplayName()
que recebe um Enum TextStyle
como primeiro parâmetro, que representa o mês no formato completo(TextStyle.FULL
), abreviado(TextStyle.SHORT
) ou a primeira letra(TextStyle.NARROW
), e o segundo parâmetro é o Locale
do idioma que pode ser utilizado o padrão do sistema através do método getDefalut()
. A classe Locale
também possui várias constantes representando outras línguas como Locale.ENGLISH
, Locale.CHINA
, Locale.FRANCH, Locale.ITALY
.
//mostra o texto completo
System.out.println(d.getMonth().getDisplayName(TextStyle.FULL, Locale.getDefault() ) );
//mostra a abreviação
System.out.println(d.getMonth().getDisplayName(TextStyle.SHORT, Locale.getDefault() ) );
//mostra somente a primeira letra
System.out.println(d.getMonth().getDisplayName(TextStyle.NARROW, Locale.getDefault() ) );
Hora – LocalTime
Para manipularmos somente a hora existe a classe LocalTime
que tem um funcionamento muito parecido com a LocalDate
, podendo ser criado através do método estático now()
que retorna a hora atual do sistema ou por parâmetros com o método of( int hora , int minuto, int segundo)
.
LocalTime time = LocalTime.now();
System.out.println("Hora atual: "+time);
LocalTime timeOutro = LocalTime.of(12 , 11 ,10);
System.out.println("Hora com parâmetros: "+timeOutro);
Para alterar algum dos valores da hora pode-se utilizar os métodos withHour(int)
, withMinute(int)
, withSecond(int)
e withNano(int)
.
LocalTime time = LocalTime.now().withHour(3).withMinute(4).withSecond(6).withNano(500_000_000);
System.out.println( time );
Adicionar e subtrair tempo também segue a mesma ideia, bastando chamar os métodos plusHours(int)
, plusMinutes(int)
, plusSeconds(int)
. Para subtrair um tempo existem os métodos minusHours(int)
, minusMinutes(int)
, minusSeconds(int)
.
LocalTime time = LocalTime.of(12 , 11 ,10);
timeOutro = time.plusHours(1).plusMinutes(1).plusSeconds(1);
System.out.println(time);
Para pegar os valores de hora, minuto, segundo e nanosegundo utilizamos os métodos getHour(),
getMinute()
, getMinute()
, getSecond()
, getNano()
.
System.out.println("HORA: "+time.getHour() );
System.out.println("MINUTO: "+time.getMinute() );
System.out.println("SEGUNDOS: "+time.getSecond() );
System.out.println("NANOSEGUNDO: "+time.getNano() );
Data e Hora, agora tudo junto – LocalDateTime
Com a classe LocalDateTime
podemos manipular a data e a hora tudo junto, como as outras classes podemos pegar do sistema utilizando now()
ou passando parâmetros através do método of(int ano, int mes, int dia , int hora , int minuto , int segundo
). Também temos o método of( LocalDate, LocalTime)
sobrecarregado recebendo como parâmetro objetos LocalDate
e LocalTime
.
LocalDateTime agora = LocalDateTime.now();
System.out.println("Agora: "+agora);
LocalDateTime dateTime = LocalDateTime.of( 2014 , 12 , 15 , 10 ,45 , 0 );
System.out.println("Date e Hora com parâmetro: "+dateTime);
LocalDate data = LocalDate.of(2014,11,12);
LocalTime time = LocalTime.of( 14 , 15 , 40);
LocalDateTime dateTime2 = LocalDateTime.of( data , time);
System.out.println("Date e Hora: "+dateTime2);
Lembrando que a classe LocalDateTime
possui todos os métodos já vistos das classes LocalDate
e LocalTime
.
Se for necessário podemos retirar somente a LocalDate
ou o LocalTime
através dos métodos toLocalDate()
e toLocalTime()
.
LocalDateTime agora = LocalDateTime.now();
LocalDate dataAgora = agora.toLocalDate();
LocalTime timeAgora = agora.toLocalTime();
System.out.println("Data Agora: "+dataAgora );
System.out.println("Time Agora: "+timeAgora );
Enums
Como comentado alguns parágrafos acima, os meses possuem um Enum para representá-los, o Month
com os valores Month.JANUARY
, Month.FEBRUARY
, Month.MARCH
, Month.APRIL
, Month.MAY
, Month.JUNE
, Month.JULY
, Month.AUGUST
, Month.SEPTEMBER
, Month.OCTOBER
, Month.NOVEMBER
, Month.DECEMBER
que podem ser utilizados para a construção de datas ao invés dos seus valores numéricos
LocalDate comMes = LocalDate.of(2014 , Month.DECEMBER , 9);
System.out.println("Data com mes enum: "+comMes);
Um método interessante do Month
é lenght
que retorna no número de dias que um determinados mês tem.
Month m = Month.of(11);
System.out.println("Números de dias do mês"+m.length(true) );
Outro Enum muito útil é o de DayOfWeek
que possui os valores DayOfWeek.FRIDAY
, DayOfWeek.MONDAY
, DayOfWeek.SATURDAY
, DayOfWeek.SUNDAY
, DayOfWeek.THURSDAY
, DayOfWeek.TUESDAY
, DayOfWeek.WEDNESDAY
e pode ser obtido através do método getDayOfWeek()
de um objeto de data.
LocalDate dayWeek = LocalDate.now();
System.out.println("Dia da semana: "+dayWeek.getDayOfWeek());
System.out.println("Dia da semana em PT: "+dayWeek.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.getDefault() ) );
Formatando datas
A formatação de datas ficou um pouco mais fácil, já que os objetos LocalDate
, LocalTime
e LocalDateTime
possuem um método format(DateTimeFormatter)
que recebe um objeto de DateTimeFormatter
que pode ser criado com os métodos ofLocalizedDate(FormatStyle)
e ofLocalizedDateTime(FormatStyle)
que recebem como parâmetro o formato, que pode ser FULL
, LONG
, MEDIUM
, SHORT
.
LocalDateTime data = LocalDateTime.now();
System.out.println("Data FULL: "+ data.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL) ) );
System.out.println("Data LONG: "+ data.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG) ) );
System.out.println("Data MEDIUM: "+ data.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM) ) );
System.out.println("Data SHORT: "+ data.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT) ) );
System.out.println("Data Time MEDIUM: "+ data.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM) ) );
System.out.println("Data Time SHORT: "+ data.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT) ) );
Mas em alguns casos é necessário uma formatação mais personalizada, o que pode ser conseguido com o uso do método ofPattern(String)
que recebe como parâmetro uma String com o formato.
LocalDateTime data = LocalDateTime.now();
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd/MM/yyyy hh:mm:ss");
System.out.println("DATA PATTERN: "+fmt.format(data) );
Na String de formato é aceito vários caracteres cada representando uma informação.
Símbolo | Significado | Exemplo |
---|---|---|
G | era | AD; Anno Domini; A |
u | year | 2004; 04 |
y | year-of-era | 2004; 04 |
D | day-of-year | 189 |
M/L | month-of-year | 7; 07; Jul; July; J |
d | day-of-month | 10 |
Q/q | quarter-of-year | 3; 03; Q3; 3rd quarter |
Y | week-based-year | 1996; 96 |
w | week-of-week-based-year | 27 |
W | week-of-month | 4 |
E | day-of-week | Tue; Tuesday; T |
e/c | localized day-of-week | 2; 02; Tue; Tuesday; T |
F | week-of-month | 3 |
a | am-pm-of-day | PM |
h | clock-hour-of-am-pm (1-12) | 12 |
K | hour-of-am-pm (0-11) | 0 |
k | clock-hour-of-am-pm (1-24) | 1 |
H | hour-of-day (0-23) | 0 |
m | minute-of-hour | 30 |
s | second-of-minute | 55 |
S | fraction-of-second | 978 |
A | milli-of-day | 1234 |
n | nano-of-second | 987654321 |
N | nano-of-day | 1234000000 |
V | time-zone ID | America/Los_Angeles; Z; -08:30 |
z | time-zone name | Pacific Standard Time; PST |
O | localized zone-offset | GMT+8; GMT+08:00; UTC-08:00; |
Convertendo datas
É outro recurso que ficou melhor, agora para converter uma String em um objeto de data pode-se utilizar as próprias classes de data já que elas tem o método parse, que recebem como parâmetros a String com o texto da data e um objeto DateTimeFormatter
com o formato de data em que a String está.
String stringData = "09/12/2014";
DateTimeFormatter fmt2 = DateTimeFormatter.ofPattern("dd/MM/yyyy");
LocalDate sData = LocalDate.parse( stringData , fmt2 );
Como será feita uma migração entre APIs é interessante saber como converter objetos Date
para LocalDate
e vice-versa.
Date ts = new Date();
Instant instant = ts.toInstant();
LocalDateTime dataEmLocalDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
System.out.println("Date to LocalDateTime: "+dataEmLocalDateTime );
A classe Date
armazena internamente o seu valor em um long que representa os milissegundos a partir de 01/01/1970 às 00:00:00. Na nova API este número é representando como a classe Instant e a classe Date agora possui o método toInstant()
, ao qual podemos utilizar no método ofInstant
de LocalDateTime
como parâmetro para criar um objeto LocalDateTime
junto com um objeto ZoneId
do sistema.
LocalDateTime data = LocalDateTime.now();
Instant instant = data.atZone(ZoneId.systemDefault()).toInstant();
Date d = Date.from(instant);
System.out.println("Date: "+d);
Diferença entre datas
No java sempre foi complicado calcular a diferença entre datas, na nova API foram criadas classes para facilitar isso, no exemplo abaixo vamos ver como calcular a diferença com a classe Period
utilizando seu método between
.
LocalDate data1 = LocalDate.of(2013,1,1);
LocalDate data2 = LocalDate.now();
Period period = Period.between( data , data);
System.out.println("Diferença entre "+data1+" e "+data2);
System.out.println("Dias: "+period.getDays() );
System.out.println("Meses: "+period.getMonths() );
System.out.println("Anos: "+period.getYears() );
Um objeto Period
possui os métodos getDays()
, getMonths()
e getYears()
que retornam o o números de dias, meses e anos respectivamente que se passaram entre as duas datas. Esta classe não calcula horas, minutos e segundo, nem é capaz de nos fornecer a diferença de tempo somente em dias por exemplo para isso temos a classe Duration
.
LocalDateTime data1 = LocalDateTime.of(2014,11,1 , 1,1,1);
LocalDateTime data2 = LocalDateTime.now();
Duration dur = Duration.between(data1 , data2);
System.out.println( dur.toDays() +" dias");
System.out.println( dur.toHours()+" horas");
System.out.println( dur.toMinutes()+" minutos");
System.out.println( dur.getSeconds() +" segundos");
Na classe Duration
os métodos toDays()
retorna a diferença de tempo em dias, se a diferença for de 2 meses, o método toDays()
vai retornar 60, já na classe Duration
o getDays()
retornaria 0 e o método getMonths()
retornaria 2.
Como sempre este post é somente uma visão geral, mais recursos podem ser visto nos links da documentação
- http://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html
- http://docs.oracle.com/javase/8/docs/api/java/time/LocalTime.html
- http://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html
- http://docs.oracle.com/javase/8/docs/api/java/util/Locale.html
- https://docs.oracle.com/javase/8/docs/api/java/time/Month.html
- https://docs.oracle.com/javase/8/docs/api/java/time/DayOfWeek.html
- https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html
- https://docs.oracle.com/javase/8/docs/api/java/time/Period.html