Date Time APIs in Java 8
There are lots of blogs and stories on the internet which can give you a good idea of Date-Time API in Java 8, yet here is my attempt to explain it one more time with my understandings.
Why Date and Time calculations are important — In today's world of social media how we get the memories of our photos, posts, tweets, anniversaries, birthdays and etc? How banks can restrict the fund transfer for a particular period? There are so many such questions that are related and the answer is ‘Date and Time calculations’. These software systems save the Date in their databases, process them, and provide us the result.
As part of our academics, we all are familiar with time and its different attributes, Like in a year there are 365 days, there are 12 months, each day has 24 hours, each hour has 60 minutes, each minute has 60 seconds. There are other attributes too if we keep digging. With all these numbers one can easily interpret the next day schedule, vacation plan, and a waste of time in a traffic jam :), but in a software system, these calculations can be pretty much big, complex, and have to be exact all the time whenever asked. Hence there is a strong urge for a good Date-Time API that serves reliable results all the time.
All the programming languages support APIs related to Date and Time. Some programming language provides very basic features and let the programmers handle their own manipulations. On the other hand, most of the programming languages provide very detailed and generous APIs for Date and Time manipulations. Let's see what Java offers.
Before Java 8, programmers used to use only java.util.Date and java.util.Calender objects to store and process the date calculations. Those are still helpful but for some complex operations, suitable APIs are not provided by these classes hence we need to write our own implementation for those operations, but in new Classes which are introduced in Java 8 like LocalDate, LocalTime and LocalDateTime all the complex part are handled by Java itself. All these classes are put in a new package called java.time. Let's see a quick example.
public static void main(String[] args) {
/****************OLD WAY*********************/
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MONTH, 1);
Date time = cal.getTime();
System.out.println(time);
/****************JAVA 8 WAY*********************/
LocalDate localDate = LocalDate.now().plusMonths(1);
System.out.println(localDate);
}
In the above example, I am trying to print the date after one month from today's date. Both the codes will give you the output which you have predicted, but the Java 8 way looks much simpler to me. the Date class could not do much here, so we used Calender object as a helper to play around with the dates. But LocalDate class does not need any helper class. Going forward we will focus our discussion on the new APIs and Classes which are introduced by Java in version 8.
Java classified the physical time on the basis of Date, Time, and Zone, and there is a reason behind it. To specify the exact time we always need to specify which Date it was, what was the clock time and which was the place, the place is needed because there are different Clock time at different places like USA and India. But sometimes specifying a date or specifying a time is enough. That is the reason I think Java kept these two entities different. Let's say if anyone asks, what's your birthday, then just providing a date would be sufficient. If anyone asks you, at what time the sun rises, then an appropriate clock time is enough to give the answer. But if someone asks you to schedule an online meeting then you need a date, and exact clock time and maybe your need to mention a timezone so that other people may not confuse with the meeting time.
Java might have used a similar thought while implementing these classes for us. In the diagram above all the orange block are the classes which represent time in Java. Let's see a quick example.
public static void main(String[] args) {
LocalDate localDate = LocalDate.of(2020, Month.JANUARY, 1);
LocalTime localTime = LocalTime.of(12, 30);
LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneId.of("Indian/Cocos"));
System.out.println(localDate);
System.out.println(localTime);
System.out.println(localDateTime);
System.out.println(zonedDateTime);
}output -2020-01-01
12:30
2020-01-01T12:30
2020-01-01T12:30+06:30[Indian/Cocos]
By reading the above code you can easily interpret how we have created the objects of particular classes. All the constructors are private, hence we need to create objects with static factory methods. There are other overloaded methods of these factory methods are also available which we can be used to create the objects.
LocalDate — needs Year, Month and Day of Month
LocalTime — needs Hour and Minute
LocalDateTime — needs LocalDate and LocalTime
ZonedDateTime — needs LocalDateTime and Zone
Let's see the other methods to create these objects.
LocalDate localDate = LocalDate.of(2020, Month.JANUARY, 1);
LocalDate localDate1 = LocalDate.of(2020, 1, 1);
LocalDate localDate2 = LocalDate.now();
LocalTime localTime = LocalTime.of(12, 30);
LocalTime localTime1 = LocalTime.of(12, 30, 59);// with seconds
LocalTime localTime2 = LocalTime.of(12, 30, 59, 1000);// with seconds and nanoSeconds
LocalTime localTime3 = LocalTime.ofSecondOfDay(1234);
LocalTime localTime4 = LocalTime.ofNanoOfDay(1000);
LocalTime localTime5 = LocalTime.now();
LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
LocalDateTime.of(2020, 1, 1, 12, 30);
LocalDateTime.of(2020, 1, 1, 12, 30, 59);
LocalDateTime.of(2020, Month.JANUARY, 1, 12, 30, 59);
LocalDateTime.of(2020, Month.JANUARY, 1, 12, 30, 59, 100);
I have not included the ZonedDateTime in the above example as the factory methods would be simply an extension of LocalDateTime and ZoneId with different overloaded versions. ZoneIds can be found on the Java documentation, and arbitrary Zone Id will throw an exception, it has to be an exact match.
Now we have seen how to hold the time in variables, now let's see how to manipulate the time and how Java 8 APIs simplified our life with it.
For LocalDate — adding days, months, year weeks, etc
public static void main(String[] args) {
LocalDate localDate = LocalDate.of(2020, Month.JANUARY, 1);
LocalDate localDatePlusMonth = localDate.plusMonths(1);
LocalDate localDatePlusDays = localDate.plusDays(1);
LocalDate localDatePlusYear = localDate.plusYears(1);
LocalDate localDatePlusWeeks = localDate.plusWeeks(1);
System.out.println(localDate);
System.out.println(localDatePlusMonth);
System.out.println(localDatePlusDays);
System.out.println(localDatePlusYear);
System.out.println(localDatePlusWeeks);
}Output -
2020-01-01
2020-02-01
2020-01-02
2021-01-01
2020-01-08
Similarly, we can subtract the days, months, years, and weeks also in the above code.
Let's see the code for LocalTime — Subtracting Hours, minutes, seconds, etc. And we can add those too!
public static void main(String[] args) {
LocalTime localTime = LocalTime.of(12, 30);
LocalTime localTimeMinusHr = localTime.minusHours(1);
LocalTime localTimeMinusMin = localTime.minusMinutes(10);
LocalTime localTimeMinusSec = localTime.minusSeconds(50);
LocalTime localTimeMinusNano = localTime.minusNanos(122);
System.out.println(localTime);
System.out.println(localTimeMinusHr);
System.out.println(localTimeMinusMin);
System.out.println(localTimeMinusSec);
System.out.println(localTimeMinusNano);
}output -12:30
11:30
12:20
12:29:10
12:29:59.999999878
All the above methods for adding and subtracting the days, months, weeks, hours, minutes, seconds, etc are available on the objects of LocalDateTime and ZonedDateTime classes as these two classed exhibits the property of both Date and Time.
Chaining of these methods is also possible which will give the best possible way to handle the Date manipulations.
LocalDateTime localDateTime = LocalDateTime.now().plusDays(1).minusHours(2).plusMonths(3);
Java is very clever and always thinks beyond our imagination. Java came with a generic way to handle these date manipulations. It comes up with two objects 1. Period and 2. Duration. The thumb rule is the same, Period works with LocalDate and Duration will work with LocalTime. Let's revise the figure-1 again with these latest changes.
Let's see LocalDate with the helper class Period.
public static void localDate() {
LocalDate localDate = LocalDate.of(2020, Month.JANUARY, 1);
Period period = Period.of(1, 1, 1);
serviceMyBike(localDate, period); // after 1 year, 1 day and 1 month
serviceMyBike(localDate, Period.of(0, 0, 1));//after 1 day
}
public static void serviceMyBike(LocalDate localDate, Period period) {
LocalDate localDatePlusPeriod = localDate.plus(period);
System.out.println(localDatePlusPeriod);
}output -
2021-02-02
2020-01-02
In the above example, I have created a generic method that accepts any date and any period and gives the next servicing date for your vehicle. The above example is way simpler than doing plusYears, plusMonths, plusDays, etc. Even we can pass the value as zero where we don't need the value to specify. or we can go with the following methods.
serviceMyBike(localDate, Period.ofDays(30));
serviceMyBike(localDate, Period.ofMonths(3));
serviceMyBike(localDate, Period.ofYears(1));
We can subtract the Period as well.
Let's see the LocalTime with Duration helper class.
public static void localTime() {
LocalTime localTime = LocalTime.of(12, 30);
Duration duration = Duration.ofHours(1);
remindMe(localTime,duration);
remindMe(localTime,Duration.ofMinutes(20));
remindMe(localTime,Duration.ofMillis(100));
remindMe(localTime,Duration.ofSeconds(30));
}
public static void remindMe(LocalTime localTime, Duration duration) {
LocalTime localTime1 = localTime.plus(duration);
System.out.println("Reminder will start on : " + localTime1);
}output -
Reminder will start on : 13:30
Reminder will start on : 12:50
Reminder will start on : 12:30:00.100
Reminder will start on : 12:30:30
In the above example, we are manipulating the time with Duration class which can be constructed with the factory method. The methods are self-explanatory. We can also subtract the duration if we want.
Now let's see the last part for LocalDateTime with Period and Duration.
Now you would have got the idea that it is possible for LocalDateTime to accept both period and duration as it's a combination of LocalDate and LocalTime. Let's see an example
public static void localDateTime() {
LocalDate localDate = LocalDate.of(2020, Month.JANUARY, 1);
LocalTime localTime = LocalTime.of(12, 30);
LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
Period period = Period.of(1, 1, 1);
Duration duration = Duration.ofHours(1);
setAppointment(localDateTime, period, duration);
}
public static void setAppointment(LocalDateTime localDateTime, Period period, Duration duration) {
LocalDateTime plusPeriod = localDateTime.plus(period);
LocalDateTime plusDuration = plusPeriod.plus(duration);
System.out.println("Appointment will be at : " + plusDuration);
}output -
Appointment will be at : 2021-02-02T13:30
Pretty much self-explanatory. We have added both Period and Duration to the object of LocalDateTime.
There are lots of ways to create objects of Period and Duration, Some of them are as follows.
Period.of(1, 1, 1);
Period.ofDays(1);
Period.ofYears(1);
Period.ofMonths(2);
Period.ofWeeks(2);
Duration.ofHours(1);
Duration.ofMinutes(10);
Duration.ofSeconds(23);
Duration.ofMillis(2323);
Duration.ofNanos(45);
Exception handling in new APIs.
Suppose we try to create an object with some invalid date then an exception will be thrown. for example, if we run the following code -
LocalDate localDate = LocalDate.of(2020, 2, 30);// No such Dateoutput will be-
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:269)
at validation.DateDemo.main(DateDemo.java:8)
There are other exceptions too which will be thrown when you come across the other invalid scenarios like wrong dates or parsing unwanted characters.
Working with GMT time.
Sometimes it's very hard to work with different timezones and it's very complex to write such programs considering different time zone. To overcome this situation many companies follow the standards of GMT(Greenwich Mean Time) time which is common across the globe. Java provides one more class that works with the standards of the GMT known as Instance. The factory methods, adding and subtracting period and duration are almost the same for this class.
public static void main(String[] args) {
Instant now = Instant.now();
System.out.println(now);
}output -
2020-11-21T20:06:03.330Z
That's it! This is my understanding of the new Date-Time API in java 8. :)
Please clap, share if you really like this article.