Background
Before Java 8 how do we work with Date/Time. We used java.util.Date class. Like below -
Date d = new Date(); System.out.println(d); Date cd = Calendar.getInstance().getTime(); System.out.println(cd); System.out.println(d.getDate()); System.out.println(d.getTime()); System.out.println(System.currentTimeMillis());//same as getTime above
Output :
Sat Feb 18 10:42:17 IST 2017
Sat Feb 18 10:42:17 IST 2017
18
1487394737708
1487394737728
In Java 8 Date/Time APIs are completely revamped. Most of them are in java.time.* package. We will look at them now.
Sat Feb 18 10:42:17 IST 2017
Sat Feb 18 10:42:17 IST 2017
18
1487394737708
1487394737728
In Java 8 Date/Time APIs are completely revamped. Most of them are in java.time.* package. We will look at them now.
New Date/Time classes
New Date/Time classes are as follows -
- LocalDate : Contains date. No time or timezone.
- LocalTime : Contains time. No date or timezone.
- LocalDateTime : Contains date and time but not the timezone.
- ZonedDateTime : Contains date and time with the timezone.
System.out.println(LocalDate.now()); System.out.println(LocalTime.now()); System.out.println(LocalDateTime.now()); System.out.println(ZonedDateTime.now());
For me the output is as follows -
2017-02-18
10:59:48.133
2017-02-18T10:59:48.133
2017-02-18T10:59:48.134+05:30[Asia/Kolkata]
NOTE : Notice how T separator is used to separate Date and time in the output of LocalDateTime and ZonedDateTime. In the output of ZonedDateTime what you see as +5.30 is relative to GMT. So current time in Asia/Kolkata time zone is 5hours 30 minutes ahead of GMT.
More ways to create Date/Time class instances
LocalDate :
public static LocalDate of(int year, int month, int dayOfMonth)
public static LocalDate of(int year, Month month, int dayOfMonth)
public static LocalDate of(int year, Month month, int dayOfMonth)
NOTE : month starts with 1 (end at 12) unlike normal convention used Java which is 0 based. Also Month is an enum. You cannot compare it with int.
LocalTime :
public static LocalTime of(int hour, int minute)
public static LocalTime of(int hour, int minute, int second)
public static LocalTime of(int hour, int minute, int second, int nanos)
public static LocalTime of(int hour, int minute, int second)
public static LocalTime of(int hour, int minute, int second, int nanos)
LocalDateTime:
public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute)
public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second)
public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanos)
public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute)
public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second)
public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second, int nanos)
public static LocalDateTime of(LocalDate date, LocalTime time)
public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second)
public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanos)
public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute)
public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second)
public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second, int nanos)
public static LocalDateTime of(LocalDate date, LocalTime time)
NOTE : Notice how you can can use a LocalDate and LocaleTime instance to create a LocalDateTime instance.
ZonedDateTime :
public static ZonedDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanos, ZoneId zone)
public static ZonedDateTime of(LocalDate date, LocalTime time, ZoneId zone)
public static ZonedDateTime of(LocalDateTime dateTime, ZoneId zone)
NOTE : Notice how each constructor needs a ZoneId instance. It basically tells what time zone we are working with. You can print out all the ZoneIds available or filter it to suit your needs.
ZoneId.getAvailableZoneIds().stream() .filter(z -> z.contains("Kolkata")) .sorted().forEach(System.out::println); ZoneId zone = ZoneId.of("Asia/Kolkata"); System.out.println(zone);
And it prints :
Asia/Kolkata
Asia/Kolkata
NOTE : Note that there are no explicit constructors. You need to use static method as I have mentioned above. Also you will get DateTimeException if you pass invalid arguments
You can try :
System.out.println(LocalDate.of(2017, 13, 21)); System.out.println(LocalDate.of(2017, 2, 29));
You will get :
Exception in thread "main" java.time.DateTimeException: Invalid value for MonthOfYear (valid values 1 - 12): 13
at java.time.temporal.ValueRange.checkValidValue(ValueRange.java:311)
at java.time.temporal.ChronoField.checkValidValue(ChronoField.java:703)
at java.time.LocalDate.of(LocalDate.java:267)
at HelloWorld.main(HelloWorld.java:83)
and
Exception in thread "main" java.time.DateTimeException: Invalid date 'February 29' as '2017' is not a leap year
at java.time.LocalDate.create(LocalDate.java:429)
at java.time.LocalDate.of(LocalDate.java:269)
at HelloWorld.main(HelloWorld.java:84)
NOTE : 2012 and 2016 are leap years.
Manipulating Date/Time
You can manipulate date/time as follows -
Using Periods
Period is well span of LocalDate. That means span consisting of Year, Month, Day, Week etc.
Eg.
Period annually = Period.ofYears(1); // every 1 year Period quarterly = Period.ofMonths(3); // every 3 months Period everyTwoWeeks = Period.ofWeeks(2); // every 2 weeks Period everyYearAndAWeek = Period.of(1, 0, 5); // every year and 5 days
NOTE : There is no time involvement in Periods. You cannot use Period with LocalTime.Also note you cannot concatenate Period methods. Well you can technically but only last one will be picked and used since these are static methods. Eg.
Period incorrectUsage = Period.ofYears(2).ofWeeks(2); // every 2 week
Now lets try printing out a Period value -
System.out.println(Period.of(2, 12, 21));
It outputs : P2Y12M21D
Now lets analyze this string. It starts with a P denoting it's a period. Then you have Y for years, M for months and D for day. If any of the parameters are not present then Java simply omits it (it will not say 0M).
Eg.
System.out.println(Period.of(2, 0, 21));
prints: P2Y21D
System.out.println(Period.of(2, 12, 21));
It outputs : P2Y12M21D
Now lets analyze this string. It starts with a P denoting it's a period. Then you have Y for years, M for months and D for day. If any of the parameters are not present then Java simply omits it (it will not say 0M).
Eg.
System.out.println(Period.of(2, 0, 21));
prints: P2Y21D
Also values greater than expected limit is fine. You can give months value as 14 and Java takes care of it.
Eg.
System.out.println(Period.of(2, 14, 21));
prints : P2Y14M21D
Eg.
System.out.println(Period.of(2, 14, 21));
prints : P2Y14M21D
But while computing it will subtract 14M = 1Y and 2M. You get the point. Let's see one example of how it is used and then we move to next topic -
LocalDate localDate = LocalDate.of(2017, 8, 2);
System.out.println(locateDate.plus(Period.of(0, 1, 2)));
print : 2017-09-04
(Adds 0 years, 1 month and 2days to existing date.)
Also note the parameters in duration are Y,M and D. So if you give something like -
System.out.println(Period.ofWeeks(2));
it will print : P14D
Using Duration
Same as Period but works with LocalTime rather than LocalDate. Like Period began with P Duration begins with PT (Period of time). As Period had parameters - Years,Months,Days - Y,M,D duration has Hours.Minutes,Seconds H,M,S.
Some examples -
Duration twoDays = Duration.ofDays(2); // PT48HDuration hourly = Duration.ofHours(1); // PT1H
Duration everyTwoMinute = Duration.ofMinutes(2); // PT2M
Duration everyTwentySeconds = Duration.ofSeconds(20); // PT20S
Duration everyMilli = Duration.ofMillis(1); // PT0.001S
Duration and Period Usage
Do not mix Period with Time and Duration with Date. Period is intended to be used with Date and Duration with Time. Refer following picture for reference.
Working with Instants
Instant class represents a specific moment in time in terms of GMT time zone. Simple example -
Instant ins1 = Instant.now(); Thread.sleep(1000); Instant ins2 = Instant.now(); System.out.println(Duration.between(ins1, ins2));
and it prints : PT1.001S
That's a second and some time needed for processing. You cannot use Instant with LocalDate or LocalTime or LocalDateTime. It has to be ZonedDateTime since it is associated with a time zone.
NOTE : Instant is related to ZonedDateTime but it always corresponds to GMT i.e point in time as per GMT.
That's a second and some time needed for processing. You cannot use Instant with LocalDate or LocalTime or LocalDateTime. It has to be ZonedDateTime since it is associated with a time zone.
NOTE : Instant is related to ZonedDateTime but it always corresponds to GMT i.e point in time as per GMT.
Accounting for Daylight Savings Time
Daylight savings time is obeserved in some countries. In this clock is adjusted by an hour twice a year to make better use of the sunlight. This transition happens on Weekend Sunday 2 AM. So when clock is at 2 AM it is moved to 3 AM.
Lets say June 29, 2017, is the weekend that clocks spring ahead for daylight savings time. Now consider following code -
LocalDate date = LocalDate.of(2017, Month.JUNE, 29); LocalTime time = LocalTime.of(1, 30); ZoneId usZone = ZoneId.of("US/Eastern"); ZonedDateTime zonedDateTime1 = ZonedDateTime.of(date, time, usZone); ZonedDateTime zonedDateTime2 = dateTime1.plus(1, ChronoUnit.HOURS); long hours = ChronoUnit.HOURS.between(zonedDateTime1, zonedDateTime2); int hours1 = dateTime1.getHour(); int hours2 = dateTime2.getHour(); System.out.println(hours + "," + hours1 + "," + hours2);
This will output 1,1,3. While the values are two hours apart, the time zone offset changes as well, making it only change from 6:30 GMT to 7:30 GMT.
NOTE : Java is smart enough to adjust for daylight savings time. So you don't have to worry about handling it in code. Logic may differ but you don't have to worry that it might cause exception or error.
NOTE : Java is smart enough to adjust for daylight savings time. So you don't have to worry about handling it in code. Logic may differ but you don't have to worry that it might cause exception or error.