Hi, dear readers! Welcome to my blog. On this post, the last on the series, we talk about the new library for Date & Time manipulation, which was inspired by the Joda Time library.
So, without further delay, let’s begin our journey through this feature!
Manipulating Dates & Time on Java
It is a old complain on the Java community how the Java APIs for manipulating Dates has his issues, like limitations, difficult to work with, etc. Thinking on this, the Java 8 comes with a new API that brings simplicity and strength to the way we work with datetimes on Java. Let’s start by learning how to create instances of the new classes.
To create a new Date instance (without time), representing the current date, all we have to do is:
LocalDate date = LocalDate.now();
To create a new Time instance, based at the time the instance was created, we do this:
LocalTime time = LocalTime.now();
And finally, to create a datetime, in other words, a date and time representation, we use this:
LocalDateTime dateTime = LocalDateTime.now();
The instance above have not timezone information, using only the local timezone. If it is needed to use a specific timezone, we created a class called ZonedDateTime. For example, if we wanted to create a instance from our timezone and them change to Sidney’s timezone, we could do like this:
ZonedDateTime zonedDateTime = ZonedDateTime.now(); System.out.println("Time at my timezone: " + zonedDateTime); zonedDateTime = zonedDateTime.withZoneSameInstant(ZoneId .of("Australia/Sydney")); System.out.println("Time at Sidney: " + zonedDateTime);
The code above print the following at my location:
Time at my timezone: 2015-06-04T14:42:30.850-03:00[America/Sao_Paulo] Time at Sidney: 2015-06-05T03:42:30.850+10:00[Australia/Sydney]
Another way of instantiating this classes is for a predefined date and/or time. We can do this like the following:
date = LocalDate.of(2015, Month.DECEMBER, 25); dateTime = LocalDateTime.of(2015, Month.DECEMBER, 25, 10, 30);
With all those classes is really simple to add and/or remove days, months or years to a date, or the same to a time object. the code bellow illustrate this simplicity:
System.out.println("Date before adding days: " + date); date = date.plusDays(10); System.out.println("Date after adding days: " + date); date = date.plusMonths(6); System.out.println("Date after adding months: " + date); date = date.plusYears(5); System.out.println("Date after adding years: " + date); date = date.minusDays(7); System.out.println("Date after subtracting days: " + date); date = date.minusMonths(6); System.out.println("Date after subtracting months: " + date); date = date.minusYears(10); System.out.println("Date after subtracting years: " + date); time = time.plusHours(12); System.out.println("Time after adding hours: " + time); time = time.plusMinutes(30); System.out.println("Time after adding minutes: " + time); time = time.plusSeconds(120); System.out.println("Time after adding seconds: " + time); time = time.minusHours(12); System.out.println("Time after subtracting hours: " + time); time = time.minusMinutes(30); System.out.println("Time after subtracting minutes: " + time); time = time.minusSeconds(120); System.out.println("Time after subtracting seconds: " + time);
Running the above code, it prints:
Date before adding days: 2015-12-25 Date after adding days: 2016-01-04 Date after adding months: 2016-07-04 Date after adding years: 2021-07-04 Date after subtracting days: 2021-06-27 Date after subtracting months: 2020-12-27 Date after subtracting years: 2010-12-27 Time after adding hours: 09:28:24.380 Time after adding minutes: 09:58:24.380 Time after adding seconds: 10:00:24.380 Time after subtracting hours: 22:00:24.380 Time after subtracting minutes: 21:30:24.380 Time after subtracting seconds: 21:28:24.380
One important thing to notice is that in all methods we had to “catch” the return of the operations. The reason for this is that, opposite to the old classes we used like the Calendar one, the instances on the new date API are immutable, so they always return a new value. This is useful for scenarios with concurrent access for example, since the instances wont carry states.
Another simplicity is on the way we get the values from a date or time. On the old days, when we wanted to get a year or month from a Calendar, for example, we would need to use the generic get method, with a indication of the field we would want, like Calendar.YEAR. With the new API, we could use specific methods with ease, like the following:
System.out.println("For the date: " + date); System.out.println("The year from the date is: " + date.getYear()); System.out.println("The month from the date is: " + date.getMonth()); System.out.println("The day from the date is: " + date.getDayOfMonth()); System.out.println("The era from the date is: " + date.getEra()); System.out.println("The day of the week is: " + date.getDayOfWeek()); System.out.println("The day of the year is: " + date.getDayOfYear());
After we run the code above, the following result will be produced:
For the date: 2010-12-27 The year from the date is: 2010 The month from the date is: DECEMBER The day from the date is: 27 The era from the date is: CE The day of the week is: MONDAY The day of the year is: 361
Another simple thing to do is comparing dates with the API. If we code the following:
// comparing dates LocalDate today = LocalDate.now(); LocalDate tomorrow = today.plusDays(1); System.out.println("Is today before tomorrow? " + today.isBefore(tomorrow)); System.out.println("Is today after tomorrow? " + today.isAfter(tomorrow)); System.out.println("Is today equal tomorrow? " + today.isEqual(tomorrow));
On the code above, as expected, only the first print will print true.
One interesting feature of the new API is the locale support. On the code bellow, for example, we print the month of a date in different languages:
System.out.println("English: "+today.getMonth().getDisplayName(TextStyle.FULL, Locale.ENGLISH)); System.out.println("Portuguese: "+today.getMonth().getDisplayName(TextStyle.FULL, Locale.forLanguageTag("pt"))); System.out.println("German: "+today.getMonth().getDisplayName(TextStyle.FULL, Locale.GERMAN)); System.out.println("Italian: "+today.getMonth().getDisplayName(TextStyle.FULL, Locale.ITALIAN)); System.out.println("Japanese: "+today.getMonth().getDisplayName(TextStyle.FULL, Locale.JAPANESE)); System.out.println("Chinese: "+today.getMonth().getDisplayName(TextStyle.FULL, Locale.CHINESE));
Running the above code, on my current date, we will get the following result:
English: June Portuguese: Junho German: Juni Italian: giugno Japanese: 6月 Chinese: 六月
Formatting dates is also a easy task with the new API. If we wanted to format a date to a “dd/MM/yyyy” format, all we have to do is pass a DateTimeFormatter with the desired format:
System.out.println(today.format(DateTimeFormatter .ofPattern("dd/MM/yyyy")));
One very common requirement we encounter from time to time is the need to calculate the time between two dates. With the new API, we can calculate this very easily, with the ChronoUnit class:
LocalDateTime oneDate = LocalDateTime.now(); LocalDateTime anotherDate = LocalDateTime.of(1982, Month.JUNE, 21, 20, 00); System.out.println("Days between the dates: " + ChronoUnit.DAYS.between(anotherDate, oneDate)); System.out.println("Months between the dates: " + ChronoUnit.MONTHS.between(anotherDate, oneDate)); System.out.println("Years between the dates: " + ChronoUnit.YEARS.between(anotherDate, oneDate)); System.out.println("Hours between the dates: " + ChronoUnit.HOURS.between(anotherDate, oneDate)); System.out.println("Minutes between the dates: " + ChronoUnit.MINUTES.between(anotherDate, oneDate)); System.out.println("Seconds between the dates: " + ChronoUnit.SECONDS.between(anotherDate, oneDate));
On my current day (08/06/2015), the above code produced:
Days between the dates: 12040 Months between the dates: 395 Years between the dates: 32 Hours between the dates: 288962 Minutes between the dates: 17337771 Seconds between the dates: 1040266275
One thing to note is that, if we use the same methods with the objects exchanged, we will receive negative numbers. If our logic needs the calculations to be always positive, we could use the classes Period and Duration to calculate the time between the dates, which have the methods isNegative() and negated() to produce this desired effect.
One final feature we will visit of the new API is the concept of invalid dates. When we were using a Calendar, if we tried to input the date of February, 30, on a year the month goes to 28 days, the Calendar will adjust the date to March, 2, in other words, it will go past the date inputted, without throwing any errors. This is not always the desired effect, since sometimes this could lead to unpredictable behaviors. On the new API, if we try for example to do the following:
LocalDate invalidDate = LocalDate.of(2014, Month.FEBRUARY, 30); System.out.println(invalidDate);
We will receive a invalid date exception, ensuring a easier way to treat this kind of bug:
Exception in thread "main" java.time.DateTimeException: Invalid date 'FEBRUARY 30' at java.time.LocalDate.create(LocalDate.java:431) at java.time.LocalDate.of(LocalDate.java:249) at com.alexandreesl.handson.DateAPIShowcase.main(DateAPIShowcase.java:174)
References
This series was inspired by a book from the publisher “Casa do Código”, which was used by me on my studies. Unfortunately the book is on Portuguese, but it is a good source for developers who want to quickly learn about the new features of Java 8:
Conclusion
And that concludes our series about the new features of the Java 8. Of course, there is other subjects we didn’t talked about, like the end of the PermGen, that it was replaced by another memory technique called metaspace. If the reader wants to know more about this, this article is very interesting on the subject. However, with this series, the reader can have a good base to start developing on Java 8.
On a programming language like Java, it is normal to have changes from time to time. For a language with so many years, it is impressive how Java can still evolve, reflecting the new tendencies from the more modern languages. Will it Java continue like this forever? Only time will tell….
Thank you for following me on another post from my blog, until next time.