Introduction to the new Java 8 Date Time
Java 8 introduced a new API for Date and Time. In this post, we will cover features of the Java 8 Date Time.
Java 1.0 introduced support for date and time using java.util.Date class. This API contains a lot of issues including not representing the date as a human-readable date but the point in time with milliseconds. We will cover issues or drawbacks of the existing Date API which made way for the Java 8 Date Time.
1. Issues with the Existing Date Time API
- API Design – Initial Date class introduced in Java 1.0 was not a true representation of the date but a point in time with milliseconds as precision. Calender API introduced as a replacement was poorly designed and lead to confusion in day to day use.
- Thread Safety – The Date and Calendar classes are not thread-safe.None of the instance methods are synchronized, and none of the instance fields are volatile, even get method can cause an instance of these classes as Mutable. A developer needs to ensure thread safety in case they are using these classes.
- Usability – Most of the methods provided by Java before Java 8 Date Time API were lacking readability and needs a more clear understanding of the underlying working of the code before using it.
Because of all these designs flaws and inconsistencies, most of the enterprise applications were forced to use the third party solution like Joda-Time, etc. To resolve all these issues, Java 8 introduced a brand new Date and Time API which is integrated many of the Joda-Time API features.
2. LocalDate, LocalTime and LocalDateTime
LocalDate, LocalTime, and LocaleDateTime are the most commonly used classes in the new Date API. These classes provide information independent of time zone i.e. we need not worry about the time zone.
2.1 Working with LocalDate
LocalDate represents date without time zone in ISO format. This is one of the most commonly used classes in the new Date API.An instance of this class is immutable and represents date without information of the time and timezone.LocalDate provides multiple utility methods to create an instance of this class. We can use of static factory method of the LocalDate class to create an instance of this class.
LocalDate date = LocalDate.of(2018, 01,8); //2018-01-08
Above code will represent the LocalDate for 8 January 2018. LocalDate instance provides several methods which can be used for the most common values required while working to Date. We will cover methods in this section.
LocalDate date = LocalDate.of(2018, 01,8); int year = date.getYear(); //2018. boolean isLeap = date.isLeapYear(); //f alse, 2018 is not Leap Year int day = date.getDayOfMonth(); // 8 DayOfWeek dayOfWeek =date.getDayOfWeek(); //MONDAY Month month =date.getMonth(); //JANUARY int monthLength = date.lengthOfMonth(); //31 int daysOfYear = date.getDayOfYear(); // 8
We can use
LocalDate.now() factory method to get current date based on the system clock.
LocalDate systemDate = LocalDate.now(); //2018-01-08
LocalDate provides other utility methods to get a different information. We will cover different operations that can be performed on the LocalDate object in other section of this post.
2.2 Working with LocalTime
LocalTime represents a time of the day (e.g 20:22: 12) without time zone and date.Like LocalDate, we can get an instance of LocalTime by using the static factory method.
LocalTime time = LocalTime.of(20, 45); //20:45 LocalTime time = LocalTime.of(20, 45, 12); //20:45 : 12
LocalTime class provides numbers of utility method to get information from the LocalTime instance.
LocalTime time = LocalTime.of(20, 45, 34); //20:45:34 int hour = time.getHour(); //20 int minutes = time.getMinute(); //45 int seconds = time.getSecond(); //34
To get time zone independent current LocalTime based on the system clock, we can use LocalTime.now() factory method.
LocalTime systemTime = LocalTime.now(); //20:49:35.509403
We can also create an instance of LocalTime by parsing String using LocalTime.parse() method
LocalTime systemTime = LocalTime.parse("15:45:45"); //15:45:45
2.3 Working with LocalDateTime
LocalDateTime is the combination of LocalDate and LocalTime. LocalDateTime represents a date and time without time zone. We can create an instance of the LocalDateTime class by using now method or we can combine a date and time instance to create the LocalDateTime object.
LocalDateTime localDateTime = LocalDateTime.of(2018, Month.JANUARY, 8, 21, 26, 12); //2018-01-08T21:26:12 LocalDate date= LocalDate.now(); LocalTime time = LocalTime.now(); LocalDateTime combieDataIssue = LocalDateTime.of(date,time); //2018-01-08T21:30:03.663603 LocalDateTime ldt = date.atTime(time); //2018-01-08T21:41:50.068417 LocalDateTime ldt1 = time.atDate(date); //2018-01-08T21:41:50.068417
3. Period and Duration
Use Duration class to represent time in seconds and nanoseconds and Period for the time in years, months and days.
Duration is the time-based amount of time (e.g 12.4 seconds etc), here are example for Duration
Duration twoMinutes = Duration.ofMinutes(3); Duration duration = Duration.of(3, ChronoUnit.MINUTES); LocalDateTime localDateTime = LocalDateTime.now(); LocalDateTime localDateTime1 =LocalDateTime.of(2018, Month.JUNE, 5, 10, 15, 45); Duration duration1 = Duration.between(localDateTime1, localDateTime);
A date-based amount of time in the ISO calendar system.The period class can change a value for a date or to find the difference between dates. Let’s take an example to understand how this can be used.
LocalDate initialDate= LocalDate.of(2017, 10, 11);
Use the period class to get useful information from the 2 date instances.
Period days = Period.ofDays(4); Period weeks = Period.ofWeeks(3); LocalDate initialDate= LocalDate.of(2017, 10, 11); LocalDate finalDate = LocalDate.of(2017, 11, 15); int dayDuration = Period.between(initialDate, finalDate).getDays(); //4 int monthDuration = Period.between(finalDate,initialDate).getMonths(); // -1
[pullquote align=”normal”]Read our article Period and Duration in Java for more detail [/pullquote]
4. Change Dates Instance
One of the main features of the Java 8 Date Time API is thread safety and most of the classes we discussed are immutable. In certain cases, we might need we need a new instance of the give LocaleDate instance to work with.
To create a new object for the given LocalDate, we can use one of it’s withAttribute or more generic with a method.
LocalDate currentDate = LocalDate.now(); //current system date LocalDate withYearDate= currentDate.withYear(2017); //Returns a copy of this date with the year altered //2017-01-09 LocalDate daysOfMonth = withYearDate.withDayOfMonth(12); // Returns a copy of this date with the day-of-month altered // 2017-01-12
These methods return a new object without keeping original LocalDate instance unchanged.
5. Manipulate Dates
New Java 8 Date Time API provides convenient ways to manipulate LocalDate instance. We can perform add, subtract on a Date instance.
//Date Manipulation LocalDate date = LocalDate.of(2017, 8, 23); LocalDate date1 = date.plus(1, ChronoUnit.DAYS); // 2017-08-24 LocalDate date2 = date1.plusWeeks(1); // 2017-08-31 , one week added to date LocalDate addYear = date2.plusYears(2); // 2019-08-31 , added 2 years LocalDate minusYear = date2.minusYears(4); // 2013-08-31 LocalDate fromYear = minusYear.from(ZonedDateTime.now());
Please note that like
withAttribute methods defined in the earlier section, These methods return a new Object with changed attributes.
[pullquote align=”normal”] Read our article Period and Duration in Java for more detail [/pullquote]
6. Parsing Dates
Before Java 8 parsing and formatting of Date object were difficult. Java 8 new java.time.format package provides a lot of helpful methods to format or parse date easily.DateTimeFormatter is one of the most important class under this package. We can use parse() method of the LocalDate instance to format given date instance.
LocalDate date = LocalDate.of(2011, 12, 17); String formattedDate = date.format(DateTimeFormatter.BASIC_ISO_DATE); // 20111217
Use DateTimeFormatter for converting String to the LocalDate instance.
LocalDate stringFormattedDate = LocalDate.parse("20161217", DateTimeFormatter.BASIC_ISO_DATE); // 2016-12-17 LocalDate date1 = LocalDate.parse("2016-08-17", DateTimeFormatter.ISO_LOCAL_DATE); // 2016-08-17
DateTimeFormatter provides several formatters to work with, however, what is the option if we want to format a date for which we do not have formatter provided by DateTimeFormatter class? The DateTimeFormatter class provides a static factory method for creating custom formatter.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); LocalDate currentDate = LocalDate.now(); // output : 2018-01-09 String formattedDate1 = currentDate.format(formatter); // output : 09/01/2018 in LocalDate newDate = LocalDate.parse(formattedDate,formatter);
So we did a few things in the above example of created a new LocalDate instance based on new formatter.
- We created DateTimeFormatter for dd/MM/yyyy format.
- We created String representation of the LocalDate instance.
- Used parse method provided by LocalDate class to create a new instance with required format.
If you are looking for Local based formatter, use the overloaded method of DateTimeFormatter by passing Local as an additional parameter.
DateTimeFormatter japaneseFormatter = DateTimeFormatter.ofPattern("M'月' yyyy'年'", Locale.JAPANESE); String newFormatter = currentDate.format(japaneseFormatter); // output : 1月 2018年 LocalDate localDate = LocalDate.parse(formattedDate1,formatter);
This is numbers of benefits of using this new formatter.
- This is thread safe as compare to old DateFormat class.
- We can use the single instance of this formatter across multiple threads.
The parse() method can throw DateTimeParseException in case it is not able to parse String to a valid LocalDate or LocalTime instance.
[pullquote align=”normal”] Read our article How to Format LocalDateTime for more detail [/pullquote]
6.1 Using DateTimeFormatterBuilder
New Java Date and Time API provide DateTimeFormatterBuilder class to create complex formatter.
DateTimeFormatter builder = new DateTimeFormatterBuilder() .appendLiteral("Day of Month is :") .appendValue(ChronoField.DAY_OF_MONTH) .appendLiteral(", Month is :") .appendValue(ChronoField.MONTH_OF_YEAR) .appendLiteral(", Year is : ") .appendValue(ChronoField.YEAR) .appendLiteral(", Time is :") .appendValue(ChronoField.HOUR_OF_DAY) .appendLiteral(":") .appendText(ChronoField.MINUTE_OF_HOUR, TextStyle.FULL_STANDALONE) .parseCaseSensitive() .toFormatter(); LocalDateTime localDateTime = LocalDateTime.now(); String date = localDateTime.format(builder);
Current Day is :9, Month is :1, Year is : 2018, Time is :21:16
7. Java Date Time API Features
We covered basic features of Java 8 Date and Time API. There are numbers of features improvement this new API brings in, here are some of the most important features of new API.
- Most of the classes provided by new API are immutable which is more in line with functional programming introduced with Java 8.
- Better readability, think about Calander.getInstance() method as compare to LocalDate.now() or LocalTime().
- The new API uses immutable objects, which makes it thread safe.
In this article, we covered new Java 8 Date Time. We covered different features and improvement introduced by Java Date and Time API. This API is a complete replacement of the old Java API and integrate many of the features of Joda-Time API.