Java 8. DateTime Serhii Kartashov October 2015 Softjourn
Java 8. DateTime
Serhii KartashovOctober 2015Softjourn
Agenda
Previous implementation and problems in real world
Date Time Java 8 (JSR 310)
Legacy Date Time Integration
JSR 310 vs JodaTime
Agenda
Previous implementation and problems in real world
Date Time Java 8 (JSR 310)
Legacy Date Time Integration
JSR 310 vs JodaTime
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)
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
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
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
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!).
Agenda
Previous implementation and problems in real world
Date Time Java 8 (JSR 310)
Legacy Date Time Integration
JSR 310 vs JodaTime
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)
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
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;
Temporal Based classes
Time
Duration(Temporal Amount)
Period(Temporal Amount)
Instant(Temporal)
Instant(Temporal)
LocalDate, etc.(Temporal)
LocalDate, etc.(Temporal)
Machine time
Human readable
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
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
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
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
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);
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).
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
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.
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.)
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.
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.
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
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.
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.
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
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
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
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); }}
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
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);
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
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
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}
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.
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
Epoch
• Reference point to measure time• Maybe based on religious or political
milestones• Divided the timeline into eras• Start of a particular era
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
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
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
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
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
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)
Agenda
Previous implementation and problems in real world
Date Time Java 8 (JSR 310)
Legacy Date Time Integration
JSR 310 vs JodaTime
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); }}
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
Agenda
Previous implementation and problems in real world
Date Time Java 8 (JSR 310)
Legacy Date Time Integration
JSR 310 vs JodaTime
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.
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).
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.
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.
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
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.
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.).
Intervals
JSR-310 does not support this feature while Joda-Time has limited support.
NOTE: Time4j has more rich package (range) for this purpose!
Questions andAnswers
Useful links– Java Tutorial– API – Examples from presentation (GitHub)– Comparison Table: JSR 310 vs JodaTime– JSR 310 – Java 8 Date/Time library performance