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.
LocalDate data = LocalDate.of(2014,10,27); data = data.plusDays(5); System.out.println("Data com 5 dias adicionado: "+data); data = data.minusDays(40); System.out.println("Data com 40 dias subtraídos: "+data);
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 égar 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 util é 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 millisegundos 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
0sem comentários ainda