JSR 310. New Date API in Java 8

60
Java 8. DateTime Serhii Kartashov October 2015 Softjourn

Transcript of JSR 310. New Date API in Java 8

Page 1: JSR 310. New Date API in Java 8

Java 8. DateTime

Serhii KartashovOctober 2015Softjourn

Page 2: JSR 310. New Date API in Java 8

Agenda

Previous implementation and problems in real world

Date Time Java 8 (JSR 310)

Legacy Date Time Integration

JSR 310 vs JodaTime

Page 3: JSR 310. New Date API in Java 8

Agenda

Previous implementation and problems in real world

Date Time Java 8 (JSR 310)

Legacy Date Time Integration

JSR 310 vs JodaTime

Page 4: JSR 310. New Date API in Java 8

Previous implementation and problems in real world

• Date it’s an instance of time (not a date)• Calendar is date and time• Date instance are mutable• Months is 0 based• Years is 1900 based (the year 2015 is

represented as 115)

Page 5: JSR 310. New Date API in Java 8

Example 1

public static void main(String[] args) { Date start = new Date(2012, Calendar.FEBRUARY, 1); Calendar startEmployment = Calendar.getInstance(); // calendar.set(2011, 2, 1); startEmployment.set(2011, Calendar.FEBRUARY, 1); Calendar now = Calendar.getInstance(); long numberOfDays1 = countDays(startEmployment, now); long numberOfDays2 = countDays(startEmployment, now); System.out.println(String.format("First try=%d , second try=%d", numberOfDays1, numberOfDays2));}

private static long countDays(Calendar start, Calendar end) { long totalNumberOfDays = 0; while(start.before(end)) { start.add(Calendar.DAY_OF_MONTH, 1); totalNumberOfDays++; } return totalNumberOfDays;}

Months starts from 0

Calendar is mutable

Deprecated

Deprecated

Page 6: JSR 310. New Date API in Java 8

Example 2

private static final int SECOND = 1000;private static final int MINUTE = 60 * SECOND;private static final int HOUR = 60 * MINUTE;private static final int DAY = 24 * HOUR;

public static void main(String[] args) {

Calendar now = Calendar.getInstance(); Date nowDate = now.getTime();

long twoHoursByMillis = 2 * HOUR; long thirtyMinutesByMillis = 30 * MINUTE;

Date twoHoursAndThirtyMinutesFromNow = new Date(twoHoursByMillis + thirtyMinutesByMillis); System.out.println(String.format("now %s and later %s", nowDate, twoHoursAndThirtyMinutesFromNow));

now Wed Oct 07 17:36:13 EEST 2015 and later Thu Jan 01 04:30:00 EET 1970

Page 7: JSR 310. New Date API in Java 8

Example 3private static final int SECOND = 1000;private static final int MINUTE = 60 * SECOND;private static final int HOUR = 60 * MINUTE;private static final int DAY = 24 * HOUR;

public static void main(String[] args) {

long ms = 10304004543l; StringBuilder text = new StringBuilder(""); if (ms > DAY) { text.append(ms / DAY).append(" days "); ms %= DAY; } if (ms > HOUR) { text.append(ms / HOUR).append(" hours "); ms %= HOUR; } if (ms > MINUTE) { text.append(ms / MINUTE).append(" minutes "); ms %= MINUTE; } if (ms > SECOND) { text.append(ms / SECOND).append(" seconds "); ms %= SECOND; } text.append(ms + " ms"); System.out.println(text.toString()); 119 days 6 hours 13 minutes 24 seconds 543 ms

Page 8: JSR 310. New Date API in Java 8

Difference between java.util.Date and java.sql.Date

• java.sql.Date stores years, months and days. Additionally sql.Date isn't tied to timezones.

• java.sql.Time only contains information about hour, minutes, seconds and milliseconds.

• java.sql.Timestamp corresponds to SQL TIMESTAMP which is exact date to the nanosecond (note that util.Date only supports milliseconds!).

Page 9: JSR 310. New Date API in Java 8

Agenda

Previous implementation and problems in real world

Date Time Java 8 (JSR 310)

Legacy Date Time Integration

JSR 310 vs JodaTime

Page 10: JSR 310. New Date API in Java 8

Date Time Java 8 (JSR 310)

• Immutable and Thread Safe• Domain-Driven Design

– Well-defined and clear purpose– Extensible, by use of strategy pattern– Amount of time – different representation for

different cases• Human (year, month, day, time zones, calendar systems)• Machine Time

• Separation of chronologies (calendars)

Page 11: JSR 310. New Date API in Java 8

New packages

• java.time – instants, duration, dates, times, timezone, periods

• java.time.format – formatting and parsing• java.time.temporal – field, unit, adjustment

access to temporals• java.time.zone – support for time zone• java.time.chrono – calendar systems other

than ISO-8601

Page 12: JSR 310. New Date API in Java 8

DayOfWeek and Month Enums// DayOfWeekDayOfWeek day = DayOfWeek.MONDAY; // the numeric value of {@code 1}.System.out.println(day); // MONDAYSystem.out.println(day.getValue()); // 1System.out.println(Arrays.asList(DayOfWeek.values()));// formatLocale locale = Locale.getDefault();System.out.println(day.getDisplayName(TextStyle.FULL, locale)); // MondaySystem.out.println(day.getDisplayName(TextStyle.NARROW, locale)); // MSystem.out.println(day.getDisplayName(TextStyle.SHORT, locale)); // Mon

// MonthMonth month = Month.JANUARY; // the numeric value of {@code 1}.System.out.println(month);System.out.println(Arrays.asList(Month.values()));

// useful constantsLocalTime lt1 = LocalTime.MIDNIGHT; // 00:00LocalTime lt2 = LocalTime.NOON; // 12:00LocalTime lt3 = LocalTime.MIN; // 00:00LocalTime lt4 = LocalTime.MAX; // 23:59:59.999999999LocalDate lt5 = LocalDate.MAX; // +999999999-12-31LocalDate lt6 = LocalDate.MIN; // -999999999-01-01LocalDateTime lt7 = LocalDateTime.MAX; // +999999999-12-31T23:59:59.999999999LocalDateTime lt8 = LocalDateTime.MAX; // +999999999-12-31T23:59:59.999999999

ChronoField millisecondsOfDay = ChronoField.MILLI_OF_DAY;System.out.println(millisecondsOfDay); // MilliOfDayChronoField secondsOfMinute = ChronoField.SECOND_OF_MINUTE;ChronoField daysOfYear = ChronoField.DAY_OF_YEAR;

Page 13: JSR 310. New Date API in Java 8

Temporal Based classes

Time

Duration(Temporal Amount)

Period(Temporal Amount)

Instant(Temporal)

Instant(Temporal)

LocalDate, etc.(Temporal)

LocalDate, etc.(Temporal)

Machine time

Human readable

Page 14: JSR 310. New Date API in Java 8

Date and Time

• LocalDate– Contains just a date—no time and no time zone– Corresponds to SQL DATE type

• LocalTime– Contains just a time—no date and no time zone– Corresponds to SQL TIME type

• LocalDateTime– Contains both a date and time but no time zone– Corresponds to SQL TIMESTAMP type

Page 15: JSR 310. New Date API in Java 8

Examples

// LocalDate Contains just a date—no time and no time zone.LocalDate date1 = LocalDate.of(2015, Month.JANUARY, 20);LocalDate date2 = LocalDate.of(2015, 1, 20);System.out.println(date1); // 2015-01-20System.out.println(date2); // 2015-01-20// LocalDate d = new LocalDate(); // does not compile - private constructor// LocalDate.of(2015, Month.JANUARY, 32); // throws DateTimeException

// LocalTime Contains just a time—no date and no time zone.LocalTime time1 = LocalTime.of(6, 15); // hour and minuteLocalTime time2 = LocalTime.of(6, 15, 30); // + secondsLocalTime time3 = LocalTime.of(6, 15, 30, 200); // + nanosecondsSystem.out.println(time1); // 06:15System.out.println(time2); // 06:15:30System.out.println(time3); // 06:15:30.000000200

// LocalDateTime Contains both a date and time but no time zone.LocalDateTime dateTime1 = LocalDateTime.of(2015, Month.JANUARY, 20, 6, 15, 30);LocalDateTime dateTime2 = LocalDateTime.of(date1, time1);System.out.println(dateTime1); // 2015-01-20T06:15:30System.out.println(dateTime2); // 2015-01-20T06:15

Page 16: JSR 310. New Date API in Java 8

Examples

// YearMonthYearMonth yearMonth1 = YearMonth.now();System.out.printf("%s: %d%n", yearMonth1, yearMonth1.lengthOfMonth()); // 2015-10: 31

YearMonth yearMonth2 = YearMonth.of(2010, Month.FEBRUARY);System.out.printf("%s: %d%n", yearMonth2, yearMonth2.lengthOfMonth()); // 2010-02: 28

YearMonth yearMonth3 = YearMonth.of(2012, Month.FEBRUARY);System.out.printf("%s: %d%n", yearMonth3, yearMonth3.lengthOfMonth()); // 2012-02: 29

// MonthDayMonthDay date = MonthDay.of(Month.FEBRUARY, 29);boolean validLeapYear = date.isValidYear(2010);System.out.println(validLeapYear); // false

// Yearboolean validLeapYear1 = Year.of(2012).isLeap();System.out.println(validLeapYear1); // true

Page 17: JSR 310. New Date API in Java 8

Instant

// Instant is useful for generating a time stamp to represent machine time.Instant timestamp = Instant.now();// Gets the number of seconds from the Java epoch of 1970-01-01T00:00:00Z.System.out.println("timestamp: " + timestamp.getEpochSecond()); // timestamp: 1444654450

// How many seconds have occurred since the beginning of the Java epoch.long secondsFromEpoch = Instant.ofEpochSecond(0L).until(Instant.now(), ChronoUnit.SECONDS);System.out.println("Amount of seconds from java epoch: " + secondsFromEpoch); // 1444654450long minutesFromEpoch = Instant.ofEpochSecond(0L).until(Instant.now(), ChronoUnit.MINUTES);System.out.println("Amount of minutes from java epoch: " + minutesFromEpoch); // 24077574

// Convert "machine time" to human unitsLocalDateTime humanTime = LocalDateTime.ofInstant(timestamp, ZoneId.systemDefault());// different methods to operate time!// toString the sameSystem.out.println("timestamp: " + timestamp); // 2015-10-12T12:54:10.787ZSystem.out.println("humanTime: " + humanTime); // 2015-10-12T13:54:10.787Z

Page 18: JSR 310. New Date API in Java 8

Parsing and Formatting

Instant instant = Instant.parse("2014-07-16T10:15:30.00Z");LocalDate localDate = LocalDate.parse("2014-07-16", DateTimeFormatter.ofPattern("yyyy-MM-dd"));LocalDate localDate2 = LocalDate.parse("2014-07-16", DateTimeFormatter.ISO_LOCAL_DATE);

DateTimeFormatter strangeFormat = new DateTimeFormatterBuilder().appendValue(MONTH_OF_YEAR, 2).appendLiteral("**").appendValue(YEAR, 4).appendLiteral("--").appendValue(DAY_OF_MONTH, 2) .toFormatter();

LocalDate localDate3 = LocalDate.parse("07**2014--16", strangeFormat);

System.out.println(instant);System.out.println(localDate);System.out.println(localDate2);System.out.println(localDate3);

LocalDate date = Year.of(2014).atMonth(7).atDay(16);String strangeDateFormat = date.format(strangeFormat);

System.out.println(strangeDateFormat);

Page 19: JSR 310. New Date API in Java 8

Time Zone and Offset Classes

A time zone is a region of the earth where the same standard time is used. • ZoneId specifies a time zone identifier and

provides rules for converting between an Instant and a LocalDateTime (format region/city (Asia/Tokyo))

• ZoneOffset specifies a time zone offset from Greenwich/UTC time (offset for Tokyo is +09:00).

Page 20: JSR 310. New Date API in Java 8

Example

private static void printAllTimeZones(){ Set<String> allZones = ZoneId.getAvailableZoneIds(); LocalDateTime dt = LocalDateTime.now();

// Create a List using the set of zones and sort it. List<String> zoneList = new ArrayList<String>(allZones); //Collections.sort(zoneList);

for (String s : zoneList) { ZoneId zone = ZoneId.of(s); ZonedDateTime zdt = dt.atZone(zone); ZoneOffset offset = zdt.getOffset(); int secondsOfHour = offset.getTotalSeconds() % (60 * 60); // just seconds!!!

String out = String.format("%35s %10s%n", zone, offset); System.out.printf(out); }}

ZoneId OffsetAsia/Jerusalem +03:00Europe/Andorra +02:00US/Samoa -11:00Asia/Vientiane +07:00

Page 21: JSR 310. New Date API in Java 8

Date-Time Classes• ZonedDateTime handles a date and time with a

corresponding time zone with a time zone offset from Greenwich/UTC.

• OffsetDateTime handles a date and time with a corresponding time zone offset from Greenwich/UTC, without a time zone ID.

• OffsetTime handles time with a corresponding time zone offset from Greenwich/UTC, without a time zone ID.

Page 22: JSR 310. New Date API in Java 8

ZonedDateTime

private static void zonedDateTime() { DateTimeFormatter format = DateTimeFormatter.ofPattern("MMM d yyyy hh:mm a");

// Leaving from San Francisco on July 20, 2013, at 7:30 p.m. LocalDateTime leaving = LocalDateTime.of(2015, Month.JULY, 20, 19, 30); ZoneId leavingZone = ZoneId.of("America/Los_Angeles"); ZonedDateTime departure = ZonedDateTime.of(leaving, leavingZone);

String out1 = departure.format(format); System.out.printf("LEAVING: %s (%s)%n", out1, leavingZone);

// Flight is 10 hours and 50 minutes, or 650 minutes ZoneId arrivingZone = ZoneId.of("Asia/Tokyo"); ZonedDateTime arrival = departure.withZoneSameInstant(arrivingZone) .plusHours(10).plusMinutes(50);

String out2 = arrival.format(format); System.out.printf("ARRIVING: %s (%s)%n", out2, arrivingZone);

// літній час if (arrivingZone.getRules().isDaylightSavings(arrival.toInstant())) { System.out.printf(" (%s daylight saving time will be in effect.)%n", arrivingZone); } else { System.out.printf(" (%s standard time will be in effect.)%n", arrivingZone); }}

LEAVING: лип. 20 2015 07:30 PM (America/Los_Angeles)ARRIVING: лип. 21 2015 10:20 PM (Asia/Tokyo) (Asia/Tokyo standard time will be in effect.)

Page 23: JSR 310. New Date API in Java 8

OffsetDateTime

// Find the last Thursday in October 2015.LocalDateTime localDate = LocalDateTime.of(2015, Month.OCTOBER, 20, 19, 30);ZoneOffset offset = ZoneOffset.of("-08:00");

OffsetDateTime offsetDate = OffsetDateTime.of(localDate, offset);OffsetDateTime lastThursday = offsetDate.with(TemporalAdjusters.lastInMonth(DayOfWeek.THURSDAY));System.out.printf("The last Thursday in October 2015 is the %sth.%n", lastThursday.getDayOfMonth());

OffsetDateTime odt = OffsetDateTime.of(LocalDateTime.now(),ZoneOffset.of("-4"));System.out.println(odt); // 2015-10-13T11:14:03.073-04:00

This class may be used when modeling date-time concepts in more detail, or when communicating to a database or in a network protocol.

Page 24: JSR 310. New Date API in Java 8

OffsetTime

OffsetTime ot = OffsetTime.ofInstant(Instant.now(),ZoneId.of("America/Los_Angeles"));System.out.println(ot); // 01:14:03.073-07:00

The OffsetTime class is used in the same situations as the OffsetDateTime class, but when tracking the date is not needed.

Page 25: JSR 310. New Date API in Java 8

Period

@Testpublic void test_period_between_dates(){ LocalDate twins = LocalDate.parse("2003-11-18"); LocalDate mayhem = LocalDate.parse("2009-06-01"); Period timeBetween = Period.between(twins,mayhem); assertThat(timeBetween.getYears(),is(5)); assertThat(timeBetween.getMonths(),is(6)); assertThat(timeBetween.getDays(),is(14));}

public static Period period(LocalDate hiringDate) { LocalDate today = LocalDate.now(); return Period.between(hiringDate, today);}

private static void period() { System.out.println("period"); Period employmentPeriod = PeriodLauncher.period(LocalDate.of(2011, Month.FEBRUARY, 1)); System.out.println(employmentPeriod.getYears()); // 4 System.out.println(employmentPeriod.getMonths()); // 8 System.out.println(employmentPeriod.getDays()); // 12}

Define an amount of time with date-based values (years, months, days)

JUnit

Page 26: JSR 310. New Date API in Java 8

Duration

public static void main(String[] args) { Instant t1 = Instant.now(); Instant t2 = Instant.now().plusSeconds(12); long nanos = Duration.between(t1, t2).toNanos(); System.out.println(nanos); // 12000000000 long milis = Duration.between(t2, t1).toMillis(); System.out.println(milis); // -12000

Duration gap = Duration.ofSeconds(13); Instant later = t1.plus(gap); System.out.println(t1); // 2015-10-13T08:58:41.312Z System.out.println(later); // 2015-10-13T08:58:54.312Z

}

The Duration class represents arbitrary amounts of time in hours, minutes or seconds.

Page 27: JSR 310. New Date API in Java 8

Chrono Units

public static void main(String[] args) {

// units Instant.now().plus(1, ChronoUnit.DAYS); // Unit that represents the concept of a day.

System.out.println(ChronoUnit.DAYS); // Days System.out.println(Arrays.asList(ChronoUnit.values())); // [Nanos, Micros, Millis, Seconds, Minutes, Hours, HalfDays, // Days, Weeks, Months, Years, Decades, Centuries, Millennia, Eras, Forever]

Instant previous = Instant.ofEpochSecond(54545454); Instant current = Instant.now();

long gap = ChronoUnit.MILLIS.between(previous, current); Duration duration = ChronoUnit.MILLIS.getDuration(); System.out.println(gap); // 1390181631925 System.out.println(duration); // PT0.001S

}

The ChronoUnit enum defines the units used to measure time.

Page 28: JSR 310. New Date API in Java 8

Class or Enum Year Month Day Hours Min Sec* Zone Offset Zone ID toString Output

Instant + 2015-08-20T15:16:26.355Z

LocalDate + + + 2015-08-20

LocalDateTime + + + + + + 2015-08-20T08:16:26.937

ZonedDateTime + + + + + + + + 2015-08-21T00:16:26.941+09:00[Asia/Tokyo]

LocalTime + + + 08:16:26.943

MonthDay + + --08-20

Year + 2015

YearMonth + + 2015-08

Mouth + AUGUST

OffsetDateTime + + + + + + + 2015-08-20T08:16:26.954-07:00

OffsetTime + + + + 08:16:26.957-07:00

Duration + PT20H (20 hours)

Period + + + P10D (10 days)

*Seconds are captured to nanosecond precision

Page 29: JSR 310. New Date API in Java 8

Temporal Adjuster

private static void adjusters() { LocalDate date = LocalDate.of(2015, Month.OCTOBER, 14); DayOfWeek dotw = date.getDayOfWeek(); System.out.printf("%s is on a %s%n", date, dotw);

System.out.printf("first day of Month: %s%n", date.with(TemporalAdjusters.firstDayOfMonth())); System.out.printf("first Monday of Month: %s%n", date.with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY))); System.out.printf("last day of Month: %s%n", date.with(TemporalAdjusters.lastDayOfMonth())); System.out.printf("first day of next Month: %s%n", date.with(TemporalAdjusters.firstDayOfNextMonth())); System.out.printf("first day of next Year: %s%n", date.with(TemporalAdjusters.firstDayOfNextYear())); System.out.printf("first day of Year: %s%n", date.with(TemporalAdjusters.firstDayOfYear()));

}

2015-10-14 is on a WEDNESDAYfirst day of Month: 2015-10-01first Monday of Month: 2015-10-05last day of Month: 2015-10-31first day of next Month: 2015-11-01first day of next Year: 2016-01-01first day of Year: 2015-01-01

Page 30: JSR 310. New Date API in Java 8

Thanksgiving, President’s Day and Programmer’s Day examples

private static void thanksgiving(int year) { LocalDate thanksGiving = Year.of(year).atMonth(Month.NOVEMBER).atDay(1) .with(TemporalAdjusters.lastInMonth(DayOfWeek.THURSDAY)); LocalDate thanksGiving4 = Year.of(year).atMonth(Month.NOVEMBER).atDay(1) .with(TemporalAdjusters.dayOfWeekInMonth(4, DayOfWeek.THURSDAY)); // the last Thursday in November System.out.println("ThanksGiving: " + thanksGiving); // the 4th Thursday in November System.out.println("ThanksGiving: " + thanksGiving4);}

private static void programmersDay(int year) { // on the 256th day LocalDate programmersDay = Year.of(year).atMonth(1).atDay(1). with(ChronoField.DAY_OF_YEAR, 256); // LocalDate programmersDay = LocalDate.of(year, 1, 1).plusDays(256); System.out.println("Programmer's Day: " + programmersDay);}

ThanksGiving: 2015-11-26ThanksGiving: 2015-11-26ThanksGiving: 2016-11-24ThanksGiving: 2016-11-24ThanksGiving: 2017-11-30ThanksGiving: 2017-11-23

Programmer's Day: 2015-09-13Programmer's Day: 2016-09-12Programmer's Day: 2017-09-13

private static void presidentDay(int year) { // the first Monday Of February LocalDate presidentsDay = Year.of(year).atMonth(Month.FEBRUARY).atDay(1) .with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY)); System.out.println("President's day (USA): " + presidentsDay);}

President's day (USA): 2015-02-02President's day (USA): 2016-02-01President's day (USA): 2017-02-06

Page 31: JSR 310. New Date API in Java 8

Custom Adjuster

public class PaydayAdjuster implements TemporalAdjuster{

/** * The adjustInto method accepts a Temporal instance * and returns an adjusted LocalDate. If the passed in * parameter is not a LocalDate, then a DateTimeException is thrown. */ public Temporal adjustInto(Temporal input) { LocalDate date = LocalDate.from(input); int day; if (date.getDayOfMonth() < 15) { day = 15; } else { day = date.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth(); } date = date.withDayOfMonth(day); if (date.getDayOfWeek() == DayOfWeek.SATURDAY || date.getDayOfWeek() == DayOfWeek.SUNDAY) { date = date.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY)); }

return input.with(date); }}

Page 32: JSR 310. New Date API in Java 8

Custom Adjuster

private static void customAdjuster() { LocalDate october_13 = LocalDate.of(2015, Month.OCTOBER, 13); LocalDate nextPayday1 = october_13.with(new PaydayAdjuster()); System.out.println("Given the date: " + october_13); System.out.println("the next payday: " + nextPayday1);

LocalDate october_18 = LocalDate.of(2015, Month.OCTOBER, 18); LocalDate nextPayday2 = october_18.with(new PaydayAdjuster()); System.out.println("Given the date: " + october_18); System.out.println("the next payday: " + nextPayday2);}

Given the date: 2015-10-13the next payday: 2015-10-15Given the date: 2015-10-18the next payday: 2015-10-30

Page 33: JSR 310. New Date API in Java 8

Temporal Query

// точністьTemporalQuery<TemporalUnit> query = TemporalQueries.precision();System.out.printf("LocalDate precision is %s%n", LocalDate.now().query(query)); // DaysSystem.out.printf("LocalDateTime precision is %s%n", LocalDateTime.now().query(query)); // NanosSystem.out.printf("Year precision is %s%n", Year.now().query(query)); // YearsSystem.out.printf("YearMonth precision is %s%n", YearMonth.now().query(query)); // MonthsSystem.out.printf("Instant precision is %s%n", Instant.now().query(query)); // NanosSystem.out.println();

LocalDateTime date = LocalDateTime.of(2014, Month.DECEMBER, 02, 0, 0);ZonedDateTime zonedDate1 = ZonedDateTime.of(date, ZoneId.of("Pacific/Chatham"));ZonedDateTime zonedDate2 = ZonedDateTime.of(date, ZoneId.of("Asia/Dhaka"));

zoneQueries(zonedDate1, zonedDate2);

offsetQueries(zonedDate1, zonedDate2);

Page 34: JSR 310. New Date API in Java 8

Temporal Query

private static void offsetQueries(ZonedDateTime zonedDate1, ZonedDateTime zonedDate2) { TemporalQuery<ZoneOffset> query = TemporalQueries.offset();

ZoneOffset offset1 = zonedDate1.query(query); ZoneOffset offset2 = zonedDate2.query(query);

System.out.println(offset1); // +13:45 System.out.println(offset2); // +06:00}

private static void zoneQueries(ZonedDateTime zonedDate1, ZonedDateTime zonedDate2) { TemporalQuery<ZoneId> query = TemporalQueries.zone();

ZoneId zoneId1 = zonedDate1.query(query); ZoneId zoneId2 = zonedDate2.query(query);

System.out.println(zoneId1); // "Pacific/Chatham" System.out.println(zoneId2); // "Asia/Dhaka"}

Pacific/ChathamAsia/Dhaka+13:45+06:00

Page 35: JSR 310. New Date API in Java 8

Custom Queries

private static void customQueries() { YearMonth yearMonth = YearMonth.of(2014, 6); System.out.println(yearMonth.query(new SchoolHolidayQuery())); // false System.out.println(YearMonth.of(2014, Month.JULY).query(new SchoolHolidayQuery())); // true System.out.println(YearMonth.of(2014, 8).query(new SchoolHolidayQuery())); // true System.out.println();

YearQuarter yearQuarter1 = YearMonth.of(2014, 6).query(YearQuarterQuery::findQuarter); System.out.println(yearQuarter1); // Q2 YearQuarter yearQuarter2 = YearMonth.of(2011, Month.DECEMBER).query(YearQuarterQuery::findQuarter); System.out.println(yearQuarter2); // Q4

}

falsetruetrue

Q2Q4

Page 36: JSR 310. New Date API in Java 8

Custom Queriespublic class SchoolHolidayQuery implements TemporalQuery<Boolean> {

@Override public Boolean queryFrom(TemporalAccessor date) { int month = date.get(ChronoField.MONTH_OF_YEAR); if (month == Month.JULY.getValue() || month == Month.AUGUST.getValue()) { return true; } return false; }}

public class YearQuarterQuery {

public static YearQuarter findQuarter(TemporalAccessor date) { int month = date.get(ChronoField.MONTH_OF_YEAR); if (month >= 1 && month <= 3) { return YearQuarter.Q1; } else if (month >= 4 && month <= 6) { return YearQuarter.Q2; } else if (month >= 7 && month <= 9) { return YearQuarter.Q3; } else { return YearQuarter.Q4; } }}

public enum YearQuarter { Q1, Q2, Q3, Q4}

Page 37: JSR 310. New Date API in Java 8

Clock

The Clock class is abstract, so you cannot create an instance of it. The following factory methods can be useful for testing

– Clock.offset(Clock, Duration) returns a clock that is offset by the specified Duration.

– Clock.systemUTC() returns a clock representing the Greenwich/UTC time zone.

– Clock.fixed(Instant, ZoneId) always returns the same Instant. For this clock, time stands still.

Page 38: JSR 310. New Date API in Java 8

Method Naming ConventionsMethod Access Description

of Static Create an instance with validation

to Instance Convert to another type (truncate fields)

at Instance Combines this object with another (expands)

from Static Convert input parameters to an instance

get Instance Part of the state of the object

is Instance Queries state of an object

with Instance Returns a copy of an object with one changed element

plus/minus Instance Returns a copy of an object with amount of added / subtracted time

parse Static Parses input string to an instance

format Instance Uses formatter to format the object’s values to produce a string

Page 39: JSR 310. New Date API in Java 8

Epoch

• Reference point to measure time• Maybe based on religious or political

milestones• Divided the timeline into eras• Start of a particular era

Page 40: JSR 310. New Date API in Java 8

Cumputer System Epochs

• January 0, 0 – Matlab• January 1, 1 – Symbian, .Net, new Windows• January 1, 1601 – COBOL, old Windows• January 1, 1900 – LISP, SNTP• January 1, 1904 – Old Mac OS• January 1, 1970 – Unix Epoch (Linux, Mac OS

X), Java, C, JavaScript, Perl, PHP, Python, Ruby

Page 41: JSR 310. New Date API in Java 8

Calendar System

• Organizes days for social, religious, commercial or administrative purposes

• Names periods like days, weeks, months and years

• Periods may follow cycles of the sun or moon• A date is a specific day in the system• May be based on an epoch

Page 42: JSR 310. New Date API in Java 8

UTC

• GMT is Greenwich Mean Time– Mean solar time at the Royal Observatory in

Greenwich• UTC is Coordinated Universal Time

– Precisely defined with atomic time. Does not change with seasons

– Replaced GMT as reference time scale on 1 January 1972

Page 43: JSR 310. New Date API in Java 8

ISO 8601

• International standard for representation of dates and times

• Uses the Gregorian calendar system• Ordered from most to least significant: year,

month, day, hour, minute• Each date and time value has a fixed number

of digits with leading zones• Uses four-digit year at minimum, YYYY

Page 44: JSR 310. New Date API in Java 8

Chronology Interface

• Pluggable calendar system (ability to create custom calendar)

• Provides access to date and time fields• Built-in

– ISO8601 (default): IsoChronology– Chinese: MinguoChronology– Japanese: JapaneseChronology (since 1868-01-01)– Thai Buddhist: ThaiBuddhistChronology– Islamic: HijrahChronology

Page 45: JSR 310. New Date API in Java 8

Era interface• An era of the time-line.• some calendar systems, have multiple eras, such as one for the

reign of each leader– the Thai Buddhist calendar system divides time into two eras, before and

after a single date. – the Japanese calendar system has one era for the reign of each Emperor.

• Bilt-in (enums)– IsoEra (BCE; CE)– MingouEra (BEFORE_ROC; ROC)– JapaneseEra (MEIJI; TAISHO; SHOWA; HEISEI)– ThaiBuddhistEra (BEFORE_BE; BE)– HijrahEra (AH)

Page 46: JSR 310. New Date API in Java 8
Page 47: JSR 310. New Date API in Java 8

Agenda

Previous implementation and problems in real world

Date Time Java 8 (JSR 310)

Legacy Date Time Integration

JSR 310 vs JodaTime

Page 48: JSR 310. New Date API in Java 8

Legacy Date Time Integration

public class Launcher {

public static void main(String[] args) { // Old to new Date date = new Date(); LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());

// New to old LocalDateTime now = LocalDateTime.now(); Instant instant = now.atZone(ZoneId.systemDefault()).toInstant(); Date dateFromOld = Date.from(instant); }}

Page 49: JSR 310. New Date API in Java 8

Mapping java.util Date and Time Functionality to java.time

java.util Functionality java.time Functionality

java.util.Date java.time.Instant

java.util.GregorianCalendar java.time.ZonedDateTime

java.util.TimeZone java.time.ZoneId or java.time.ZoneOffset

GregorianCalendar with the date set to 1970-01-01

java.time.LocalTime

GregorianCalendar with time set to 00:00. java.time.LocalDate

Page 50: JSR 310. New Date API in Java 8

Agenda

Previous implementation and problems in real world

Date Time Java 8 (JSR 310)

Legacy Date Time Integration

JSR 310 vs JodaTime

Page 51: JSR 310. New Date API in Java 8

JSR 310 vs JodaTime

• Both libraries use immutable types. Joda-Time also offers additional mutable types like MutableDateTime.

• Null. Joda-Time often use NULL as default for system timezone, default locale, current timestamp etc. while JSR-310 almost always rejects NULL values.

Page 52: JSR 310. New Date API in Java 8

Supported fields

An overview about supported fields in Java-8 (JSR-310) is given by some classes in the temporal-package (for example ChronoField and WeekFields) while Joda-Time is rather weak on this area – see DateTimeFieldType.

The biggest lack of Joda-Time is here the absence of localized week-related fields. A common feature of both field implementation design is that both are based on values of type long (no other types, not even enums).

Page 53: JSR 310. New Date API in Java 8

Enum

JSR-310 offers enums like DayOfWeek or Month while Joda-Time does not offer this because it was mainly developed in years 2002-2004 before Java 5.

Page 54: JSR 310. New Date API in Java 8

Zone API

JSR-310 offers more timezone features than Joda-Time. Latter is not able to yield a programmatically access to the history of timezone offset transitions while JSR-310 is capable to do this.

Page 55: JSR 310. New Date API in Java 8

Adjuster vs. Property• JSR 310 has very limited value because the burden to write code

is still with the user. Built-in solutions based on the new TemporalAdjuster-concept are not so many, there is currently only the helper class TemporalAdjusters with a limited set of manipulations (and the enums Month or other temporal types).

• Joda-Time offers a field-package but practice has shown evidence that new field implementations are very hard to code. On the other side Joda-Time offers so-called properties which make some manipulations much easier and more elegant than in JSR-310

Page 56: JSR 310. New Date API in Java 8

Calendar systemsJoda-Time provide 8 calendar systems:• Buddhist• Coptic (Egypt – Alexandrian Calendar)• Ethiopic (Ethiopia)• Gregorian-Julian cutover• Gregorian• Islamic• ISO• Julian

Calendars like Hebrew or Persian or Hindu are completely missing in both libraries.

Joda-Time updates calendars with each release version (you may download it from the web site manually) while java may update only with next path.

Page 57: JSR 310. New Date API in Java 8

Clocks

JSR-310 has no interface (a design mistake) but an abstract class java.time.Clock which can be used for any clock dependency injection.

Joda-Time offers the interface MillisProvider and some helper methods in DateTimeUtils instead.

So this way Joda-Time is also capable of supporting test-driven models with different clocks (mocking etc.).

Page 58: JSR 310. New Date API in Java 8

Intervals

JSR-310 does not support this feature while Joda-Time has limited support.

NOTE: Time4j has more rich package (range) for this purpose!

Page 59: JSR 310. New Date API in Java 8

Questions andAnswers