Site Search:

Work with dates and times across timezones and manage changes resulting from daylight savings including Format date and times values

Back>

Last topic is about the syntax of dates and times across timezones. This topic focuses on the calculation and comparing of zoned date and time.

spring forward & fall back
spring forward & fall back

Dates and Times Across Timezones


OCPJP>cat ZonedDateTimeCal.java 
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class ZonedDateTimeCal {
    public static void main(String...args) {
        ZoneId.getAvailableZoneIds().stream()
        .filter(i -> i.startsWith("Indian")).limit(1)
        .forEach(System.out::println);
        
        ZonedDateTime zonedDateTime = ZonedDateTime
                .of(LocalDateTime.of(LocalDate.now(), LocalTime.of(1, 1)), 
                        ZoneId.of("UTC"));
        System.out.println(zonedDateTime);
        System.out.println(zonedDateTime.toInstant());
        System.out.println();
        
        zonedDateTime = ZonedDateTime
                .of(LocalDateTime.of(LocalDate.now(), LocalTime.of(1, 1)), 
                        ZoneId.of("GMT"));
        System.out.println(zonedDateTime);
        System.out.println(zonedDateTime.toInstant());
        System.out.println();
        
        ZonedDateTime zonedDateTime1 = ZonedDateTime
                .of(LocalDateTime.of(LocalDate.now(), LocalTime.of(1, 1)), 
                        ZoneId.of("US/Eastern"));
        System.out.println(zonedDateTime1);
        System.out.println(zonedDateTime1.toInstant());
        System.out.println();
        
        ZonedDateTime zonedDateTime2 = ZonedDateTime
                .of(LocalDateTime.of(LocalDate.now(), LocalTime.of(1, 1)), 
                        ZoneId.of("Indian/Comoro"));
        System.out.println(zonedDateTime2);
        System.out.println(zonedDateTime2.toInstant());
        System.out.println();
        
        Duration duration = Duration.between(zonedDateTime1.toInstant(), zonedDateTime.toInstant());
        System.out.println(duration);
        System.out.println();
        
        duration = Duration.between(zonedDateTime2.toInstant(), zonedDateTime.toInstant());
        System.out.println(duration);
        System.out.println();
        
        duration = Duration.between(zonedDateTime2.toInstant(), zonedDateTime1.toInstant());
        System.out.println(duration);
        System.out.println();
    }
}
OCPJP>
OCPJP>
OCPJP>javac ZonedDateTimeCal.java 
OCPJP>java ZonedDateTimeCal
Indian/Comoro
2017-11-03T01:01Z[UTC]
2017-11-03T01:01:00Z

2017-11-03T01:01Z[GMT]
2017-11-03T01:01:00Z

2017-11-03T01:01-04:00[US/Eastern]
2017-11-03T05:01:00Z

2017-11-03T01:01+03:00[Indian/Comoro]
2017-11-02T22:01:00Z

PT-4H

PT3H

PT7H


OCPJP>


in the above example, we calculated how many hours are between zonedDateTimes:
2017-11-03T01:01-04:00[US/Eastern]
and
2017-11-03T01:01+03:00[Indian/Comoro]

How to read these zonedDateTime is as following:
Java uses T to separate the date and time. The date and time is followed by timezone offset from Greenwich Mean Time (GMT) or Coordinated Universal Time (UTC). The last part is the timezone.

GMT or UTC is a time zone in Europe that is used as time zone zero.

For hand calculating during the example, follow the following steps:

First, we translate the 2017-11-03T01:01-04:00[US/Eastern] to GMT. It can be done by subtracting the offsets to the date and time part, 01:01 - (-04:00) = 01:01 + 04:00 = 05:01. So the GMT time is 2017-11-03T05:01:00Z.

Second, we translate the 2017-11-03T01:01+03:00[Indian/Comoro] to GMT. The time is 01:01 - 03:00. There is only 1 hour, we need to subtract 3 hours, so we borrow a day from date,  2017-11-02T25:01+03:00,  then calculate time 25:01 - 3:00 = 22:01. So the GMT time is 2017-11-02T22:01:00Z.

Now, we have two instances in the same timezone (GMT or UTC), they can be compared directly:
017-11-03T05:01:00Z and 2017-11-02T22:01:00Z has 7 hours between them.

Daylight Savings Time



In a normal day, the time proceeds from 1:00am to 1:59 am then 2:00 am to 3:00 am then 3:00 am to 4:00 am. However there is an edge condition the OCPJP will test.

Some countries participate in daylight saving time to make better use of the sunlight. For example, in the first weekend of March, time springs forward from 1:59 am to 3:00 am, skipping 2:00 am to 3:00am, making that day 23 hours long; and in the first weekend of November, time falls back from 1:59 am back to 1:00 am, experiencing 1:00 am to 1:59 am twice, making that day 25 hours long.

If you are counting time in those timezones observing daylight saving time, you have to consider this edge condition. US/Eastern, for example, is one of the timezone using daylight saving time.

OCPJP>cat DaylightSavingDemo.java 
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;

public class DaylightSavingDemo {
    public static void main(String[] args) {
        LocalDateTime localDateTime = LocalDateTime.of(2017, Month.MARCH, 12, 1, 30);
        ZoneId zoneId = ZoneId.of("US/Eastern");
        ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, zoneId);
        System.out.println("Spring forward");
        ZonedDateTime jumpOneHour = zonedDateTime.plus(1, ChronoUnit.HOURS);
        System.out.println(zonedDateTime);
        System.out.println(zonedDateTime.toInstant());
        System.out.println(jumpOneHour);
        System.out.println(jumpOneHour.toInstant());
        System.out.println(Duration.between(zonedDateTime, jumpOneHour));
        
        System.out.println("fall backward");
        localDateTime = LocalDateTime.of(2017, Month.NOVEMBER, 5, 1, 30);
        zonedDateTime = ZonedDateTime.of(localDateTime, zoneId);
        ZonedDateTime fallOneHour = zonedDateTime.plusHours(1);
        System.out.println(zonedDateTime);
        System.out.println(zonedDateTime.toInstant());
        System.out.println(fallOneHour);
        System.out.println(fallOneHour.toInstant());
        System.out.println(Duration.between(zonedDateTime, fallOneHour));
        
        System.out.println();
        System.out.println(ZonedDateTime.now());
    }
}
OCPJP>
OCPJP>
OCPJP>javac DaylightSavingDemo.java 
OCPJP>java DaylightSavingDemo
Spring forward
2017-03-12T01:30-05:00[US/Eastern]
2017-03-12T06:30:00Z
2017-03-12T03:30-04:00[US/Eastern]
2017-03-12T07:30:00Z
PT1H
fall backward
2017-11-05T01:30-04:00[US/Eastern]
2017-11-05T05:30:00Z
2017-11-05T01:30-05:00[US/Eastern]
2017-11-05T06:30:00Z
PT1H

2017-11-05T07:32:07.812-05:00[America/New_York]

OCPJP>

notice when time springs froward from 1:30 am to 3:30 am in the spring or falls back from 1:30 am to 1:30 am in the fall, the UTC offset also changes, the time really only changes only by one hour from GMT or UTC's point of view.

Formatting Dates and Times

java.time.format provided a class DateTimeFormatter to format any type of date and time object.

OCPJP>cat DateTimeFormatterDemo.java 
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;

public class DateTimeFormatterDemo {
    public static void main(String...args) {
        LocalDate localDate = LocalDate.of(2000, Month.JANUARY, 1);
        LocalTime localTime = LocalTime.of(1, 1);
        LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
        
        System.out.println(localDate.format(DateTimeFormatter.ISO_LOCAL_DATE));
        System.out.println(localTime.format(DateTimeFormatter.ISO_LOCAL_TIME));
        System.out.println(localDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
        
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT);
        System.out.println(dateTimeFormatter.format(localDate));
        System.out.println(localDate.format(dateTimeFormatter));
        dateTimeFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);
        System.out.println(dateTimeFormatter.format(localDate));
        System.out.println(localDate.format(dateTimeFormatter));
        dateTimeFormatter =  DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT);
        System.out.println(dateTimeFormatter.format(localTime));
        System.out.println(localTime.format(dateTimeFormatter));
        dateTimeFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM);
        System.out.println(dateTimeFormatter.format(localTime));
        System.out.println(localTime.format(dateTimeFormatter));
        dateTimeFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
        System.out.println(dateTimeFormatter.format(localDateTime));
        System.out.println(localDateTime.format(dateTimeFormatter));
        dateTimeFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.MEDIUM);
        System.out.println(dateTimeFormatter.format(localDateTime));
        System.out.println(localDateTime.format(dateTimeFormatter));
        
        dateTimeFormatter = DateTimeFormatter.ofPattern("MMMM dd, yy, hh:mm");
        System.out.println(dateTimeFormatter.format(localDateTime));
        System.out.println(localDateTime.format(dateTimeFormatter));
        
        localDate = LocalDate.parse("Jan 02 2015", DateTimeFormatter.ofPattern("MMM dd yyyy"));
        System.out.println(localDate.format(DateTimeFormatter.ofPattern("M dd yy")));
        
    }
}
OCPJP>
OCPJP>
OCPJP>javac DateTimeFormatterDemo.java 
OCPJP>java DateTimeFormatterDemo
2000-01-01
01:01:00
2000-01-01T01:01:00
1/1/00
1/1/00
Jan 1, 2000
Jan 1, 2000
1:01 AM
1:01 AM
1:01:00 AM
1:01:00 AM
1/1/00 1:01 AM
1/1/00 1:01 AM
Jan 1, 2000 1:01:00 AM
Jan 1, 2000 1:01:00 AM
January 01, 00, 01:01
January 01, 00, 01:01
1 02 15

OCPJP>


The static methods DateTimeFormatter.ofLocalizedDate, DateTimeFormatter.ofLocalizedTime, DateTimeFormatter.ofLocalizedDateTime, DateTimeFormatter.ofPatten are used to create DateTimeFormatter instances.