Modern Java in Action 6 - Time and Date

Reasons to abandon old API
java.util.Date
- mutable
- unintuitive constructor (days, months, minutes and seconds are 0-based, year represented as delta from 1900), values wrap-around
- cannot be internationalized
java.util.Calendar
- not thread safe
- mutable (no clear semantics date change)
- when to use which?
java.util.DateFormat
- not thead-safe
- can only parse
Date, notCalendar
New API

java.time package
Classes and interfaces in a new package java.time (modelled after Joda Time classes) provide better way of thinking about and working with time concepts.
The most important classess in this package are: LocalDate, LocalTime, LocalDateTime, Instant, Duration, and Period .
LocalDateTime and LocalTime instances don’t contain timezone information. They are:
-
immutable
-
can read fields in two ways:
- using getters (e.g.
date.getYear()) - using TeporalField enum (e.g.
date.get(ChronoField.YEAR))
- using getters (e.g.
-
parsing is possible separately for dates and times:
LocalDate date = LocalDate.parse("2022-06-30"); LocalTime time = LocalTime.parse("12:35:20"); -
combine 2022-06-30 12:36:48 and time with LocalDateTime
LocalDateTime dt1 = LocalDateTime.of(2022, Month.JUNE, 30, 12, 35, 20); LocalDateTime dt2 = LocalDateTime.of(date, time); LocalDateTime dt3 = date.atTime(12, 35, 20); LocalDateTime dt4 = date.atTime(time); LocalDateTime dt5 = time.atDate(date); -
extract LocalDate and LocalTime from LocalDateTime (
dt.toLocalDate()anddt.toLocalTime())
Instant - for machine processing
- number of seconds since epoch (midninght, Jan 1 1970 UTC)
- fatcory method
Instant.of(num_of_seconds)andInstant.of(num_of_seconds, nano_adjustment) Instant.now()captures intant of current moment- cannot provide tempopral details (yers or seconds)
Duration
- denotes how much time there is between two temporal objects
- used to represent the amount measured in seconds and nanoseconds
- created with
Duration.between(a1, a2)where a1 and a2 are either:- time
- datetime
- instant
- created also with:
Duration.ofMinutes(10)Duration.of(2, CroniUnit.MINUTES)
Period
- represents amount of days, months, years
- can be created with
Period.between - also with:
Period.ofWeeks(3)- period of three weeksPeriod.of(10, 2, 3)- 10 years, 2 months and 3 days
Manipulation
It is not a manupulation but a way to receive another LocalDate from existing one:
LocalDate birthday = LocalDate.of(1978, 09, 11);
LocalDate this_year_birthday = date1.withYear(2022);
LocalDate day_after_party = this_year_birthday.withDayOfMonth(12);
LocalDate next_month_after_party = this_year_birthday.with(ChronoField.MONTH_OF_YEAR, 10);Fun with simple arithmetics
Temporal interface allow to do dates arithmetics:
- you can
plusandminussomeTemporalAmount(i.e. Duration or Period) fromTemporals - you can check how much is left
untilanother Temporal (expressed in givenTemporalUnit
Note: ChronoField and ChronoUnit are located in java.time.temporal package.
// my birthday
var bd = LocalDate.of(2022, 9, 11);
// how many days left?
System.out.println(LocalDate.now().until(bd, ChronoUnit.DAYS));
//72- or what would be next Monday after specific LocalDate:
jshell> bd.with(TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY))
$14 ==> 2022-09-12More fun with TemporalAdjusters
Class TemporalAdjusters allows to find :
- first or last day of this/next month
- first or last day in the year
- first or last day-of-week within a month (first Friday in May)
- next or previous day of week (next Sunday)
You can create your own adjuster with:
public static TemporalAdjuster ofDateAdjuster(UnaryOperator<LocalDate> dateBasedAdjuster)or implement custo m TemporalAdjuster:
@FunctionalInterface
public interface TemporalAdjuster {
Temporal adjustInto(Temporal temporal);
}Formatting and parsing
This functionality lives in java.time.format package. Predefined instances of DateTimeFormatter (as static contants) provde common ways for formatting/parsing of dates.
- formatting
String s2 = bd.format(DateTimeFormatter.ISO_LOCAL_DATE);
System.out.println(s2);
// 2022-09-11- parsing
LocalDate date2 = LocalDate.parse("2022-09-11",
DateTimeFormatter.ISO_LOCAL_DATE);
System.out.println(date2);
// 2022-09-11Working with timezones
This is the pearl of this package.
- ZoneId represents a zone in a form “{area}/{city}” (taken from IANA)
- each might have specific rules determining the time
LocalDateTime can be converted to Instant provided the ZoneId; Instant can be converted to LocalDateTime also only when it is known in what timezone the date is needed:
jshell> TimeZone warsawZone = TimeZone.getDefault()
warsawZone ==> sun.util.calendar.ZoneInfo[id="Europe/Warsaw",off ... me=3600000,endTimeMode=2]]
jshell> Instant instant = Instant.now();
instant ==> 2022-06-30T14:29:46.492899089Z
jshell> LocalDateTime timeFromInstant = LocalDateTime.ofInstant(instant,warsawZone.toZoneId())
timeFromInstant ==> 2022-06-30T16:29:46.492899089ZoneOffset can express a time zone with fixed offset from UTC/Greenwich:
ZoneOffset newYorkOffset = ZoneOffset.of("-06:00");which can be used to see hat offset time there is right now:
LocalDateTime dateTime = LocalDateTime.now();
OffsetDateTime dateTimeInNewYork = OffsetDateTime.of(date, newYorkOffset);Alternative calendar systems
There are other calendar systems available as well:
ThaiBuddhistDate, MinguoDate, JapaneseDate, and HijrahDate
Example:
jshell> LocalDate date = LocalDate.of(2014, Month.MARCH, 18);
...> JapaneseDate japaneseDate = JapaneseDate.from(date);
date ==> 2014-03-18
japaneseDate ==> Japanese Heisei 26-03-18Note
As a refresher on date-time types in PostgreSQL, see my other blog post: postgres - dates
This text is part of the series modern-java-in-action...
- 2022-05-07 - Modern Java in Action 8 - concurrency and reactive programming
- 2022-02-07 - Modern Java in Action 7 - notes about the module system
- 2022-30-06 - Modern Java in Action 6 - Time and Date
- 2022-20-06 - Modern Java in Action 5 - Optional
- 2022-17-06 - Modern Java in Action 4 - refactoring and testing
- 2022-15-06 - Modern Java in Action 3 - collection API
- 2022-14-06 - Modern Java in Action 2 - fork-join and spliterators
- 2022-03-06 - Modern Java in Action 1 - Java 8 refresher