Types in Java.time
- Duration: an amount of elapsed time
- measure machine-based time
- Only able to getSeconds() and getNano()
- Be careful of negative Durations
- Period: “1 year, 2 months and 3 days”
- A date-based amount of time.
- The total period of time is represented by all three units together: months, days, and years. To present the amount of time measured in a single unit of time, such as days, you can use the ChronoUnit.between method.
- Two Periods are only equal if their underlying fields (years, months, days) are equal
- Prefer Duration over periodically
- Instant: a point on the timeline without time zone
- Create Instant from Milliseconds from Epoch:
Instant.ofEpochMilli(timeMillis);
- Create Instant from Milliseconds from Epoch:
- Clock: provides access to current instant, date and time using a time-zone.
No time zone
- java.time.DayOfWeek/Month/Year
- java.time.YearMonth/MonthDay
- LocalDate, LocalDate, LocalDateTime
With time zone
- ZonedDateTime: a date-time with a time-zone
- OffsetDateTime
- ZoneId: a time-zone ID
APIs
Duration.between(startTime, endTime).getSeconds();
LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
ZonedDateTime.ofInstant(Instant.ofEpochMilli(mills), ZoneId.systemDefault()))
// can change simplified as:
Instant.ofEpochMilli(mills).atZone(ZoneId.systemDefault())
zonedDateTime.minus(duration).plusHours(1);
Traps
- Duration.get() only works with SECONDS or NANOS
public long get(TemporalUnit unit) {
if (unit == ChronoUnit.SECONDS) {
return this.seconds;
} else if (unit == ChronoUnit.NANOS) {
return (long)this.nanos;
} else {
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
}
Avoid any APIs that use the default system time zone
- If client need use the system default time-zone, pass ZoneId.systemDefault()
Avoid offset-based “time zones”
- do not support daylight savings changes.
- They do not respect other changes in a region’s offset over time.
Don’t use primitives to represent dates or times
- Unit confusion: easy to make mistake, difficult when debugging and logging
- Use Instant instead of the number of milliseconds to represent a point in time.
- Use Duration to represent an elapsed amount of time
- If you must use primitives, include the unit in the methods name, parameter names.
- Measure elapsed time with Guava’s Stopwatch
Converting between time units
- Using Duration
Duration.ofSeconds(seconds).toMillis();
- throw ArithmeticException correctly if an overflow occurs.
- Use Period to get the difference in days/months/years
Period.between(startDate, endDate).getMonths()
- Use java.time.temporal.ChronoUnit example to know the difference in days/months/years
ChronoUnit.DAYS.between(startDate, endDate)
- Using java.util.concurrent.TimeUnit
TimeUnit.SECONDS.toMillis(seconds);
- TimeUnit.toUnit/convert silently saturates to Long.MIN_VALUE/MAX_VALUE on overflows!
Misc Tips
- Avoid java.util.Date/Calendar
- Use ‘date.toInstant()’ to convert to new java.time APIs.
- Avoid Joda in new API
- the Clock class is intended for testing only
- Avoid any APIs that use the default system clock like
ZonedDateTime.now(), Instant.now()
- use date-time types in database to track date-time values
Use Timestamp and Duration in protocolbuffers
From Error Prone
- JavaTimeDefaultTimeZone
- java.time APIs that silently use the default system time-zone are not allowed.
- Use of java.time.Duration.withSeconds(long) is not allowed. > Duration’s withSeconds(long) method is often a source of bugs because it returns a copy of the current Duration instance, but only the seconds field is mutated (the nanos field is copied directly). Use Duration.ofSeconds(seconds, duration.getNano()) instead.
Date-Time Design Principles
- Immutable, Fluent,
- Domain-driven design
- Separation of chronologies
Problems with old Date/Calendar
- Date/Calendar/DateFormat are mutable
- Not intuitive
- month are 0 based, years are 1900 based.
- Timezones: uses String to represent TimeZone
- DateFormat is mutable, only works with Date, not Calendar
- We can pass a Calendar, but it doesn’t work.
- DateFormat is not thread-safe <!– https://www.threeten.org/threeten-extra/ org.threeten.extra ThreeTen-Extra contains additional date-time classes that complement those in java.time. These include:
Days, Weeks, Months and Years - a whole-number amount of time for various units (e.g., “7 weeks”) DayOfMonth - a day-of-month without month or year (e.g., “the 14th day of the month”) DayOfYear - a day-of-year without year (e.g., “the 51st day of the year”) AmPm - before or after midday Quarter - the four quarters of the year (e.g., “the 3rd quarter of the year”) YearQuarter - combines a year and quarter, (e.g., “the 3rd quarter of 2014”) YearWeek - combines a week-based-year and a week, (e.g., “the 6th week of 2014”) –>