Java 8 Date Time API is one of the most sought after change for developers. Java has been missing a consistent approach for Date and Time from start and Java 8 Date Time API is a welcome addition to the core Java APIs.
Before we start looking at the Java 8 Date Time API, let’s see why do we need a new API for this. There have been several problems with the existing date and time related classes in java, some of them are:
There are some other issues with the methods defined in Date and Calendar classes but above problems make it clear that a robust Date Time API was needed in Java. That’s why Joda Time played a key role as a quality replacement for Java Date Time requirements.
Java 8 Date Time API is JSR-310 implementation. It is designed to overcome all the flaws in the legacy date time implementations. Some of the design principles of new Date Time API are:
Java 8 Date Time API consists of following packages.
We have looked into most of the important parts of Java Date Time API. It’s time now to look into most important classes of Date Time API with examples.
-
LocalDate
LocalDate
is an immutable class that represents Date with default format of yyyy-MM-dd. We can usenow()
method to get the current date. We can also provide input arguments for year, month and date to create LocalDate instance. This class provides overloaded method for now() where we can pass ZoneId for getting date in specific time zone. This class provides the same functionality asjava.sql.Date
. Let’s look at a simple example for it’s usage.1234567891011121314151617181920212223242526272829303132333435package com.journaldev.java8.time;import java.time.LocalDate;import java.time.Month;import java.time.ZoneId;/*** LocalDate Examples* @author pankaj**/public class LocalDateExample {public static void main(String[] args) {//Current DateLocalDate today = LocalDate.now();System.out.println("Current Date="+today);//Creating LocalDate by providing input argumentsLocalDate firstDay_2014 = LocalDate.of(2014, Month.JANUARY, 1);System.out.println("Specific Date="+firstDay_2014);//Try creating date by providing invalid inputs//LocalDate feb29_2014 = LocalDate.of(2014, Month.FEBRUARY, 29);//Exception in thread "main" java.time.DateTimeException://Invalid date 'February 29' as '2014' is not a leap year//Current date in "Asia/Kolkata", you can get it from ZoneId javadocLocalDate todayKolkata = LocalDate.now(ZoneId.of("Asia/Kolkata"));System.out.println("Current Date in IST="+todayKolkata);//java.time.zone.ZoneRulesException: Unknown time-zone ID: IST//LocalDate todayIST = LocalDate.now(ZoneId.of("IST"));//Getting date from the base date i.e 01/01/1970LocalDate dateFromBase = LocalDate.ofEpochDay(365);System.out.println("365th day from base date= "+dateFromBase);LocalDate hundredDay2014 = LocalDate.ofYearDay(2014, 100);System.out.println("100th day of 2014="+hundredDay2014);}}LocalDate methods explanation is provided in comments, when we run this program, we get following output.
1234567<span style="color: #008000;"><strong><code>Current Date=2014-04-28Specific Date=2014-01-01Current Date in IST=2014-04-29365th day from base date= 1971-01-01100th day of 2014=2014-04-10</code></strong></span> -
LocalTime
LocalTime is an immutable class whose instance represents a time in the human readable format. It’s default format is hh:mm:ss.zzz. Just like LocalDate, this class provides time zone support and creating instance by passing hour, minute and second as input arguments. Let’s look at it’s usage with a simple program.
1234567891011121314151617181920212223242526272829303132package com.journaldev.java8.time;import java.time.LocalTime;import java.time.ZoneId;/*** LocalTime Examples* @author pankaj**/public class LocalTimeExample {public static void main(String[] args) {//Current TimeLocalTime time = LocalTime.now();System.out.println("Current Time="+time);//Creating LocalTime by providing input argumentsLocalTime specificTime = LocalTime.of(12,20,25,40);System.out.println("Specific Time of Day="+specificTime);//Try creating time by providing invalid inputs//LocalTime invalidTime = LocalTime.of(25,20);//Exception in thread "main" java.time.DateTimeException://Invalid value for HourOfDay (valid values 0 - 23): 25//Current date in "Asia/Kolkata", you can get it from ZoneId javadocLocalTime timeKolkata = LocalTime.now(ZoneId.of("Asia/Kolkata"));System.out.println("Current Time in IST="+timeKolkata);//java.time.zone.ZoneRulesException: Unknown time-zone ID: IST//LocalTime todayIST = LocalTime.now(ZoneId.of("IST"));//Getting date from the base date i.e 01/01/1970LocalTime specificSecondTime = LocalTime.ofSecondOfDay(10000);System.out.println("10000th second time= "+specificSecondTime);}}When we run above program for LocalTime examples, we get following output.
123456<span style="color: #008000;"><strong><code>Current Time=15:51:45.240Specific Time of Day=12:20:25.000000040Current Time in IST=04:21:45.27610000th second time= 02:46:40</code></strong></span> -
LocalDateTime
LocalDateTime
is an immutable date-time object that represents a date-time, with default format as yyyy-MM-dd-HH-mm-ss.zzz. It provides a factory method that takesLocalDate
andLocalTime
input arguments to createLocalDateTime
instance. Let’s look it’s usage with a simple example.12345678910111213141516171819202122232425262728293031323334package com.journaldev.java8.time;import java.time.LocalDate;import java.time.LocalDateTime;import java.time.LocalTime;import java.time.Month;import java.time.ZoneId;import java.time.ZoneOffset;public class LocalDateTimeExample {public static void main(String[] args) {//Current DateLocalDateTime today = LocalDateTime.now();System.out.println("Current DateTime="+today);//Current Date using LocalDate and LocalTimetoday = LocalDateTime.of(LocalDate.now(), LocalTime.now());System.out.println("Current DateTime="+today);//Creating LocalDateTime by providing input argumentsLocalDateTime specificDate = LocalDateTime.of(2014, Month.JANUARY, 1, 10, 10, 30);System.out.println("Specific Date="+specificDate);//Try creating date by providing invalid inputs//LocalDateTime feb29_2014 = LocalDateTime.of(2014, Month.FEBRUARY, 28, 25,1,1);//Exception in thread "main" java.time.DateTimeException://Invalid value for HourOfDay (valid values 0 - 23): 25//Current date in "Asia/Kolkata", you can get it from ZoneId javadocLocalDateTime todayKolkata = LocalDateTime.now(ZoneId.of("Asia/Kolkata"));System.out.println("Current Date in IST="+todayKolkata);//java.time.zone.ZoneRulesException: Unknown time-zone ID: IST//LocalDateTime todayIST = LocalDateTime.now(ZoneId.of("IST"));//Getting date from the base date i.e 01/01/1970LocalDateTime dateFromBase = LocalDateTime.ofEpochSecond(10000, 0, ZoneOffset.UTC);System.out.println("10000th second time from 01/01/1970= "+dateFromBase);}}In all the three examples, we have seen that if we provide invalid arguments for creating Date/Time, then it throws
java.time.DateTimeException
that is a RuntimeException, so we don’t need to explicitly catch it.We have also seen that we can get Date/Time data by passing
ZoneId
, you can get the list of supported ZoneId values from it’s javadoc. When we run above class, we get following output.1234567<span style="color: #003300;"><strong><code>Current DateTime=2014-04-28T16:00:49.455Current DateTime=2014-04-28T16:00:49.493Specific Date=2014-01-01T10:10:30Current Date in IST=2014-04-29T04:30:49.49310000th second time from 01/01/1970= 1970-01-01T02:46:40</code></strong></span> -
Instant
Instant class is used to work with machine readable time format, it stores date time in unix timestamp. Let’s see it’s usage with a simple program.
123456789101112131415161718package com.journaldev.java8.time;import java.time.Duration;import java.time.Instant;public class InstantExample {public static void main(String[] args) {//Current timestampInstant timestamp = Instant.now();System.out.println("Current Timestamp = "+timestamp);//Instant from timestampInstant specificTime = Instant.ofEpochMilli(timestamp.toEpochMilli());System.out.println("Specific Time = "+specificTime);//Duration exampleDuration thirtyDay = Duration.ofDays(30);System.out.println(thirtyDay);}}Output of above program is:
12345<span style="color: #008000;"><strong><code>Current Timestamp = 2014-04-28T23:20:08.489ZSpecific Time = 2014-04-28T23:20:08.489ZPT720H</code></strong></span> -
Java 8 Date API Utilities
As mentioned earlier, most of the Date Time principle classes provide various utility methods such as plus/minus days, weeks, months etc. There are some other utility methods for adjusting the date using
TemporalAdjuster
and to calculate the period between two dates.1234567891011121314151617181920212223242526272829303132package com.journaldev.java8.time;import java.time.LocalDate;import java.time.LocalTime;import java.time.Period;import java.time.temporal.TemporalAdjusters;public class DateAPIUtilities {public static void main(String[] args) {LocalDate today = LocalDate.now();//Get the Year, check if it's leap yearSystem.out.println("Year "+today.getYear()+" is Leap Year? "+today.isLeapYear());//Compare two LocalDate for before and afterSystem.out.println("Today is before 01/01/2015? "+today.isBefore(LocalDate.of(2015,1,1)));//Create LocalDateTime from LocalDateSystem.out.println("Current Time="+today.atTime(LocalTime.now()));//plus and minus operationsSystem.out.println("10 days after today will be "+today.plusDays(10));System.out.println("3 weeks after today will be "+today.plusWeeks(3));System.out.println("20 months after today will be "+today.plusMonths(20));System.out.println("10 days before today will be "+today.minusDays(10));System.out.println("3 weeks before today will be "+today.minusWeeks(3));System.out.println("20 months before today will be "+today.minusMonths(20));//Temporal adjusters for adjusting the datesSystem.out.println("First date of this month= "+today.with(TemporalAdjusters.firstDayOfMonth()));LocalDate lastDayOfYear = today.with(TemporalAdjusters.lastDayOfYear());System.out.println("Last date of this year= "+lastDayOfYear);Period period = today.until(lastDayOfYear);System.out.println("Period Format= "+period);System.out.println("Months remaining in the year= "+period.getMonths());}}Output of above program is:
123456789101112131415<span style="color: #008000;"><strong><code>Year 2014 is Leap Year? falseToday is before 01/01/2015? trueCurrent Time=2014-04-28T16:23:53.15410 days after today will be 2014-05-083 weeks after today will be 2014-05-1920 months after today will be 2015-12-2810 days before today will be 2014-04-183 weeks before today will be 2014-04-0720 months before today will be 2012-08-28First date of this month= 2014-04-01Last date of this year= 2014-12-31Period Format= P8M3DMonths remaining in the year= 8</code></strong></span> -
Java 8 Date Parsing and Formatting
It’s very common to format date into different formats and then parse a String to get the Date Time objects. Let’s see it with simple examples.
12345678910111213141516171819202122232425262728293031package com.journaldev.java8.time;import java.time.Instant;import java.time.LocalDate;import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;public class DateParseFormatExample {public static void main(String[] args) {//Format examplesLocalDate date = LocalDate.now();//default formatSystem.out.println("Default format of LocalDate="+date);//specific formatSystem.out.println(date.format(DateTimeFormatter.ofPattern("d::MMM::uuuu")));System.out.println(date.format(DateTimeFormatter.BASIC_ISO_DATE));LocalDateTime dateTime = LocalDateTime.now();//default formatSystem.out.println("Default format of LocalDateTime="+dateTime);//specific formatSystem.out.println(dateTime.format(DateTimeFormatter.ofPattern("d::MMM::uuuu HH::mm::ss")));System.out.println(dateTime.format(DateTimeFormatter.BASIC_ISO_DATE));Instant timestamp = Instant.now();//default formatSystem.out.println("Default format of Instant="+timestamp);//Parse examplesLocalDateTime dt = LocalDateTime.parse("27::Apr::2014 21::39::48",DateTimeFormatter.ofPattern("d::MMM::uuuu HH::mm::ss"));System.out.println("Default format after parsing = "+dt);}}When we run above program, we get following output.
12345678910<span style="color: #008000;"><strong><code>Default format of LocalDate=2014-04-2828::Apr::201420140428Default format of LocalDateTime=2014-04-28T16:25:49.34128::Apr::2014 16::25::4920140428Default format of Instant=2014-04-28T23:25:49.342ZDefault format after parsing = 2014-04-27T21:39:48</code></strong></span> -
Java 8 Date API Legacy Date Time Support
Legacy Date/Time classes are used in almost all the applications, so having backward compatibility is a must. That’s why there are several utility methods through which we can convert Legacy classes to new classes and vice versa. Let’s see this with a simple example.
12345678910111213141516171819202122232425262728293031323334353637package com.journaldev.java8.time;import java.time.Instant;import java.time.LocalDateTime;import java.time.ZoneId;import java.time.ZonedDateTime;import java.util.Calendar;import java.util.Date;import java.util.GregorianCalendar;import java.util.TimeZone;public class DateAPILegacySupport {public static void main(String[] args) {//Date to InstantInstant timestamp = new Date().toInstant();//Now we can convert Instant to LocalDateTime or other similar classesLocalDateTime date = LocalDateTime.ofInstant(timestamp,ZoneId.of(ZoneId.SHORT_IDS.get("PST")));System.out.println("Date = "+date);//Calendar to InstantInstant time = Calendar.getInstance().toInstant();System.out.println(time);//TimeZone to ZoneIdZoneId defaultZone = TimeZone.getDefault().toZoneId();System.out.println(defaultZone);//ZonedDateTime from specific CalendarZonedDateTime gregorianCalendarDateTime = new GregorianCalendar().toZonedDateTime();System.out.println(gregorianCalendarDateTime);//Date API to Legacy classesDate dt = Date.from(Instant.now());System.out.println(dt);TimeZone tz = TimeZone.getTimeZone(defaultZone);System.out.println(tz);GregorianCalendar gc = GregorianCalendar.from(gregorianCalendarDateTime);System.out.println(gc);}}When we run above application, we get following output.
123456789<span style="color: #008000;"><strong>Date = 2014-04-28T16:28:54.3402014-04-28T23:28:54.395ZAmerica/Los_Angeles2014-04-28T16:28:54.404-07:00[America/Los_Angeles]Mon Apr 28 16:28:54 PDT 2014sun.util.calendar.ZoneInfo[id="America/Los_Angeles",offset=-28800000,dstSavings=3600000,useDaylight=true,transitions=185,lastRule=java.util.SimpleTimeZone[id=America/Los_Angeles,offset=-28800000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]]java.util.GregorianCalendar[time=1398727734404,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/Los_Angeles",offset=-28800000,dstSavings=3600000,useDaylight=true,transitions=185,lastRule=java.util.SimpleTimeZone[id=America/Los_Angeles,offset=-28800000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2014,MONTH=3,WEEK_OF_YEAR=18,WEEK_OF_MONTH=5,DAY_OF_MONTH=28,DAY_OF_YEAR=118,DAY_OF_WEEK=2,DAY_OF_WEEK_IN_MONTH=4,AM_PM=1,HOUR=4,HOUR_OF_DAY=16,MINUTE=28,SECOND=54,MILLISECOND=404,ZONE_OFFSET=-28800000,DST_OFFSET=3600000</strong></span>]As you can see that legacy
TimeZone
andGregorianCalendar
classes toString() methods are too verbose and not user friendly.
That’s all for Java 8 Date Time API, I like this new API a lot. Some of the most used classes will be LocalDate and LocalDateTime for this new API. It’s very easy to work with and having similar methods that does a particular job makes it easy to find. It will take some time from moving legacy classes to new Date Time classes, but I believe it will be worthy of the time.