Set Your Clocks the Java Date Time API is Here!

Daniel Hinojosa

Who is this for?

Introduction to some terms

Epoch

Political Asian Epochs & Calendars

Japan

China

India:

North Korea

Thailand

Religious Epochs & Calendars

Judaism

Islam

Hindu

European Calendar

Christianity

Computer Epochs

source: http://en.wikipedia.org/wiki/Epoch_(reference_date)

The *nix/Java Standard

How we measure time

Sundials

Sundials

Water Clocks/Clepsydras

Clepsydra1
Clepsydra2

Pendulum

Pendulum

Quartz

Quartz

32,768 Hz

Atomic Clock

Atomic Clock

Cesium 133: 9,192,631,770 cycles of radiation

ISO 8601 Standard

ISO 8601 Formats

Format

Example

Date

2014-01-01

Combined Date and Time in UTC

2014-07-07T07:01Z

Combined Date and Time in MDT

2014-07-07T07:38:51.716-06:00

Date With Week Number

2014-W27-3

Ordinal Date

2014-188

Duration

P3Y6M4DT12H30M5S

Finite Interval

2014-03-01T13:00:00Z/2015-05-11T15:30:00Z

Finite Start with Duration

2014-03-01T13:00:00Z/P1Y2M10DT2H30M

Duration with with Finite End

P1Y2M10DT2H30M/2015-05-11T15:30:00Z

Kxcd ISO-8601

80%

GMT v. UTC

GMT

UTC

Life and Times Java

java.util.Date

Source: http://www.javaworld.com/article/2078757/java-se/java-101-the-next-generation-it-s-time-for-a-change.html

java.util.Calendar

Source: http://www.javaworld.com/article/2078757/java-se/java-101-the-next-generation-it-s-time-for-a-change.html

Of course then there is this:

> new java.util.GregorianCalendar

java.util.GregorianCalendar = java.util.GregorianCalendar[time=1393764079082,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/New_York",offset=-18000000,dstSaving=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/New_York,offset=-18000000,dstSaving=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=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2014,MONTH=2,WEEK_OF_YEAR=10,WEEK_OF_MONTH=2,DAY_OF_MONTH=2,DAY_OF_YEAR=61,DAY_OF_WEEK=1,DAY_OF_WEEK_IN_MONTH=1,AM_PM=0,HOUR=7,HOUR_OF_DAY=7,MINUTE=41,SECOND=19,MILLISECOND=82,ZONE_OFFSET=-18000000,DST_...

What was cool about Joda Time

About the Java 8 Date Time API

The Java Date Time Packaging

Date Time Conventions

Instant

That a lot of resolution!

mork nanoo

An Instant can be resolved as 1.844674407×1019 seconds or 584542046090 years!

Some of the basic features of Instant

Instant now = Instant.now();
System.out.println(now.getEpochSecond());
System.out.println(now.getNano());
System.out.println(Instant.parse("2014-02-20T20:21:20.432Z"));

UML Diagram of an Instant

80%

Enums

Month and DayOfWeek

Month and DayOfWeek Exemplified

DayOfWeek.SUNDAY
DayOfWeek.FRIDAY
Month.JANUARY
Month.JULY
Month.DECEMBER

ChronoUnit

UML Diagram of ChronoUnit

80%

ChronoUnit Exemplified

ChronoUnit.DAYS
ChronoUnit.CENTURIES
ChronoUnit.ERAS
ChronoUnit.MINUTES
ChronoUnit.MONTHS
ChronoUnit.SECONDS
ChronoUnit.FOREVER
Instant.now().plus(19, ChronoUnit.DAYS)

ChronoField

ChronoField Exemplified

ChronoField.MONTH_OF_YEAR
ChronoField.DAY_OF_MONTH
ChronoField.HOUR_OF_DAY
ChronoField.SECOND_OF_MINUTE
ChronoField.SECOND_OF_DAY
ChronoField.MINUTE_OF_DAY
ChronoField.MINUTE_OF_HOUR
Instant.now.get(ChronoField.HOUR_OF_DAY);

UML Diagram of ChronoField

80%

Local Dates and Times

UML Diagram of LocalDate, LocalTime, LocalDateTime

80%

LocalDate exemplified

LocalDate february20th = LocalDate.of(2014, Month.FEBRUARY, 20);
february20th;                                            //2014-02-20
LocalDate.from(february20th.plus(15, ChronoUnit.YEARS)); //2029-02-20
LocalDate.parse("2014-11-22");                           //2014-11-22

LocalTime exemplified

LocalTime.MIDNIGHT;                              //00:00
LocalTime.NOON;                                  //12:00
LocalTime.of(23, 12, 30, 500);                   //23:12:30.000000500
LocalTime.now();                                 //00:40:34.110
LocalTime.ofSecondOfDay(11 * 60 * 60);           //11:00
LocalTime.from(LocalTime.MIDNIGHT.plusHours(4)); //04:00

LocalDateTime exemplified

LocalDateTime.of(2014, 2, 15, 12, 30, 50, 200); //2014-02-15T12:30:50.000000200
LocalDateTime.now();                            //2014-02-28T17:28:21.002
LocalDateTime.from(
   LocalDateTime.of
      (2014, 2, 15, 12, 30, 40, 500)
        .plusHours(19)));                       //2014-02-16T07:30:40.000000500
LocalDateTime.MIN;                              //-999999999-01-01T00:00
LocalDateTime.MAX;                              //+999999999-12-31T23:59:59.999999999

ZonedDateTime

But first, ZoneId

# Monaco
# Shanks & Pottenger give 0:09:20 for Paris Mean Time; go with Howse's
# more precise 0:09:21.
# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
Zone	Europe/Monaco	0:29:32 -	LMT	1891 Mar 15
			0:09:21	-	PMT	1911 Mar 11    # Paris Mean Time
			0:00	France	WE%sT	1945 Sep 16 3:00
			1:00	France	CE%sT	1977
			1:00	EU	CE%sT

Creating the ZoneId

ZoneId.of("America/Denver");
ZoneId.of("Asia/Jakarta");
ZoneId.of("America/Los_Angeles");
ZoneId.ofOffset("UTC", ZoneOffset.ofHours(-6));

Creating your ZoneId naming

Map<String, String> map = new HashMap<String, String>();
map.put("Pacific", "America/Los_Angeles");
map.put("Mountain", "America/Denver");
map.put("Central", "America/Chicago");
map.put("Eastern", "America/New_York");
ZoneId.of("Mountain", map);  // Same as "America/Denver"

UML Diagram of ZonedDateTime

80%

ZonedDateTime exemplified

ZonedDateTime.now();  //Current Date Time with Zone

ZonedDateTime myZonedDateTime = ZonedDateTime.of(2014, 1, 31, 11, 20, 30, 93020122, ZoneId.systemDefault());

ZonedDateTime nowInAthens = ZonedDateTime.now(ZoneId.of("Europe/Athens"));

LocalDate localDate = LocalDate.of(2013, 11, 12);
LocalTime localTime = LocalTime.of(23, 10, 44, 12882);
ZoneId chicago = ZoneId.of("America/Chicago");
ZonedDateTime chicagoTime = ZonedDateTime.of(localDate, localTime, chicago);


LocalDateTime localDateTime = LocalDateTime.of(1982, Month.APRIL, 17, 14, 11);
ZonedDateTime jakartaTime = ZonedDateTime.of(localDateTime, ZoneId.of("Asia/Jakarta"));

Daylight Saving Time Begins

Daylight Saving Time Exemplified

LocalDateTime date = LocalDateTime.of(2012, 11, 12, 13, 11, 12);
date.atZone(ZoneId.of("America/Los_Angeles")) //2012-11-12T13:11:12-08:00[America/Los_Angeles]

LocalDateTime daylightSavingTime = LocalDateTime.of(2014, 3, 9, 2, 0, 0, 0);
daylightSavingTime.atZone(ZoneId.of("America/Denver")); //2014-03-09T03:00-06:00[America/Denver]

LocalDateTime daylightSavingTime2 = LocalDateTime.of(2014, 3, 9, 2, 30, 0, 0);
daylightSavingTime2.atZone(ZoneId.of("America/New_York")); //2014-03-09T03:30-04:00[America/New_York]

LocalDateTime daylightSavingTime3 = LocalDateTime.of(2014, 3, 9, 2, 0, 0, 0);
daylightSavingTime3.atZone(ZoneId.of("America/Phoenix")); //2014-03-09T03:59:59.999999999-05:00[America/Chicago]

LocalDateTime daylightSavingTime4 = LocalDateTime.of(2014, 3, 9, 2, 59, 59, 999999999);
daylightSavingTime4.atZone(ZoneId.of("America/Chicago")); //2014-03-09T02:00-07:00[America/Phoenix]

Daylight Saving Time Ends

Standard Time Exemplified

LocalDateTime date2 = LocalDateTime.of(2012, 11, 12, 13, 11, 12);
date2.atZone(ZoneId.of("America/Los_Angeles"))); //2012-11-12T13:11:12-08:00[America/Los_Angeles]

LocalDateTime standardTime = LocalDateTime.of(2014, 11, 2, 2, 0, 0, 0);
standardTime.atZone(ZoneId.of("America/Denver")); //2014-11-02T02:00-07:00[America/Denver]

LocalDateTime standardTime2 = LocalDateTime.of(2014, 11, 2, 2, 30, 0, 0);
standardTime2.atZone(ZoneId.of("America/New_York")); //2014-11-02T02:30-05:00[America/New_York]

LocalDateTime standardTime3 = LocalDateTime.of(2014, 11, 2, 2, 0, 0, 0);
standardTime3.atZone(ZoneId.of("America/Phoenix")); //2014-11-02T02:00-07:00[America/Phoenix]

LocalDateTime standardTime4 = LocalDateTime.of(2014, 11, 2, 2, 59, 59, 999999999);
standardTime4.atZone(ZoneId.of("America/Chicago")); //2014-11-02T02:59:59.999999999-06:00[America/Chicago]

Shifting Time

Durations and Periods

More about Duration

UML Diagram of Duration

80%

Duration Exemplified

Duration duration =  Duration.ofDays(33); //seconds or nanos
Duration duration1 = Duration.ofHours(33); //seconds or nanos
Duration duration2 = Duration.ofMillis(33); //seconds or nanos
Duration duration3 = Duration.ofMinutes(33); //seconds or nanos
Duration duration4 = Duration.ofNanos(33); //seconds or nanos
Duration duration5 = Duration.ofSeconds(33); //seconds or nanos
Duration duration6 = Duration.between(LocalDate.of(2012, 11, 11), LocalDate.of(2013, 1, 1));

More about Period

UML Diagram of Period

80%

Period Exemplified

Period p = Period.ofDays(30);
Period p1 = Period.ofMonths(12);
Period p2 = Period.ofWeeks(11);
Period p3 = Period.ofYears(50);

Shifting Dates and Time

Shifting LocalDate

LocalDate localDate = LocalDate.of(2012, 11, 23);
localDate.plus(3, ChronoUnit.DAYS); //2012-11-26
localDate.plus(Period.ofDays(3)); //2012-11-26
try {
   localDate.plus(Duration.ofDays(3));  //2012-11-26
} catch (UnsupportedTemporalTypeException e) {
   e.printStackTrace();
}

Shifting LocalTime

LocalTime localTime = LocalTime.of(11, 20, 50);
localTime.plus(3, ChronoUnit.HOURS); //14:20:50
localTime.plus(Duration.ofDays(3)); //11:20:50
try {
  localTime.plus(Period.ofDays(3));
} catch (UnsupportedTemporalTypeException e) {
  e.printStackTrace();
}

Temporal Adjusters

@FunctionalInterface
public interface TemporalAdjuster {
   Temporal adjustInto(Temporal temporal);
}

Overly Simplified Temporal Adjuster

TemporalAdjuster fourMinutesFromNow = new TemporalAdjuster() {
   @Override
   public Temporal adjustInto(Temporal temporal) {
       return temporal.plus(4, ChronoUnit.MINUTES);
   }
};

LocalTime localTime = LocalTime.of(12, 0, 0);
localTime.with(fourMinutesFromNow)); //12:04

But, wait there’s more!

Remember this?

@FunctionalInterface
public interface TemporalAdjuster {
      Temporal adjustInto(Temporal temporal);
}

That’s a Java 8 Lambda! Therefore fourMinutesFromNow can now be:

TemporalAdjuster fourMinutesFromNow = temporal -> temporal.plus(4, ChronoUnit.MINUTES);
LocalTime localTime = LocalTime.of(12, 0, 0);
localTime.with(fourMinutesFromNow)); //12:04

Refactoring and inlining

LocalTime.of(12, 0, 0).with(temporal -> temporal.plus(4, ChronoUnit.MINUTES));

Simple, isn’t it?

80%

Parsing and Formatting

Formatting LocalDate

DateTimeFormatter dateFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);

dateFormatter.format(LocalDate.now()); // Jan. 19, 2014

Formatting LocalTime

DateTimeFormatter timeFormatter =
   DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM);

timeFormatter.format(LocalTime.now())); //3:01:48 PM

Formatting LocalDateTime

DateTimeFormatter dateTimeFormatter =
   DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.SHORT);

dateTimeFormatter.format(LocalDateTime.now())); // Jan. 19, 2014 3:01 PM

Formatting Customized Patterns

DateTimeFormatter obscurePattern =
   DateTimeFormatter.ofPattern("MMMM dd, yyyy '(In Time Zone: 'VV')'");
ZonedDateTime zonedNow = ZonedDateTime.now();

obscurePattern.format(zonedNow); //January 19, 2014 (In Time Zone: America/Denver)

Formatting with Localization

ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Europe/Paris"));

DateTimeFormatter longDateTimeFormatter =
DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL, FormatStyle.FULL).withLocale(Locale.FRENCH);
longDateTimeFormatter.getLocale(); //fr
longDateTimeFormatter.format(zonedDateTime); //samedi 19 janvier 2014 00 h 00 CET

Shifting Time Zones

LocalDateTime localDateTime = LocalDateTime.of(1982, Month.APRIL, 17, 14, 11);
ZonedDateTime jakartaTime = ZonedDateTime.of(localDateTime, ZoneId.of("Asia/Jakarta"));
jakartaTime.withZoneSameInstant(ZoneId.of("America/Los_Angeles"))); //1982-04-16T23:11-08:00[America/Los_Angeles]
jakartaTime.withZoneSameLocal(ZoneId.of("America/New_York"))); //1982-04-17T14:11-05:00[America/New_York]

Temporal Querying

@FunctionalInterface
public interface TemporalQuery<R> {
    R queryFrom(TemporalAccessor temporal);
}

A Festive Example

TemporalQuery<Integer> daysBeforeChristmas = new TemporalQuery<Integer>() {
    public int daysTilChristmas (int acc, Temporal temporal) {
        int month = temporal.get(ChronoField.MONTH_OF_YEAR);
        int day = temporal.get(ChronoField.DAY_OF_MONTH);
        int max = Month.of(month).maxLength();
        if (month == 12 && day <= 25) return acc + (25 - day);
        return daysTilChristmas(acc + (max - day + 1),
           temporal.with(TemporalAdjusters.firstDayOfNextMonth()));
    }


    @Override
    public Integer queryFrom(TemporalAccessor temporal) {
        if (!(temporal instanceof Temporal))
            throw new RuntimeException("Temporal accessor must be of type Temporal");
        return daysTilChristmas(0, (Temporal) temporal);
    }
};

LocalDate.of(2013, 12, 26).query(daysBeforeChristmas); //364
LocalDate.of(2013, 12, 23).query(daysBeforeChristmas); //2
LocalDate.of(2013, 12, 25).query(daysBeforeChristmas); //0
ZonedDateTime.of(2013, 12, 1, 11, 0, 13, 938282,
  ZoneId.of("America/Los_Angeles"))
  .query(daysBeforeChristmas)); //24

Let’s come back to parsing

Simple Parsing

LOLWUT?

DateTimeFormatter dateFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);
dateFormatter.parse("Jan 19, 2014")); // {}, ISO resolved to 2014-01-19

First Attempt

TemporalQuery<LocalDate> localDateTemporalQuery = new TemporalQuery<LocalDate>() {
   @Override
   public LocalDate queryFrom(TemporalAccessor temporal) {
       return LocalDate.from(temporal);
   }
};

dateFormatter.parse("Jan 19, 2014", localDateTemporalQuery); //2014-01-19

Second Attempt

dateFormatter.parse("Jan 19, 2014", temporal -> LocalDate.from(temporal)); //2014-01-19

About Java 8 Instance Method References

Given

@FunctionalInterface
public interface Predicate<T> {
   public boolean test(T t);
}

And

static class IntPredicates {
public static boolean isOdd(Integer n) { return n % 2 != 0; }
public static boolean isEven(Integer n) { return n % 2 == 0; }
public static boolean isPositive(Integer n) { return n >= 0; }
}

About Java 8 Instance Method References (Continued)

Using the Predicate

Predicate<Integer> isOdd = n -> IntPredicates.isOdd(n);
Predicate<Integer> isEven = n -> IntPredicates.isEven(n);

We can always refer to those as:

Predicate<Integer> isOdd = IntPredicates::isOdd;
Predicate<Integer> isEven = IntPredicate::isEven;

source: http://java.dzone.com/articles/java-lambda-expressions-vs

What does that mean to us?

Inside of LocalDate.java

public static LocalDate from(TemporalAccessor temporal) {
    Objects.requireNonNull(temporal, "temporal");
    LocalDate date = temporal.query(TemporalQueries.localDate());
    if (date == null) {
        throw new DateTimeException("Unable to obtain LocalDate from TemporalAccessor: " +
                temporal + " of type " + temporal.getClass().getName());
    }
    return date;
}

Therefore, our last attempt

dateFormatter.parse("Jan 19, 2014", LocalDate::from); // Jan 19, 2014

Interoperabilility with Legacy Code

GregorianCalendar gregorianCalendar = new GregorianCalendar();
gregorianCalendar.toZonedDateTime();

Clocks

System Clock

Clock clock  = Clock.systemDefaultZone();
LocalDate localDate = LocalDate.now(clock);

Fixed Clock

Clock fixedClock = Clock.fixed(Instant.parse("2014-03-23T12:00:12Z"), ZoneId.of("America/Denver"));
LocalDate localDate = LocalDate.now(fixedClock);

(Perfect for Testing)

Offset Clock

Clock offsetClock = Clock.offset(Clock.system(ZoneId.of("America/New_York")), Duration.ofMinutes(30));
LocalTime localTime = LocalTime.now(offsetClock); //Current Time plus 30 minutes

Tick Clock

Clock tickClock = Clock.tick(Clock.system(ZoneId.of("America/New_York")), Duration.ofMinutes(30));
LocalTime localDate = LocalTime.now(tickClock); //Current time rounded to the nearest 30 minutes

Conclusion

Questions?

Thank You

#