Scala 3: Creating New Date and Time Instances

This is an excerpt from the Scala Cookbook, 2nd Edition. This is Recipe 3.9, Creating New Date and Time Instances.

Problem

You need to create new date and time instances using the Date and Time API that was introduced with Java 8.

Solution

Using the Java 8 API you can create new dates, times, and date/time values. Descriptions of common Java 8 Date and Time classes provides a description of some of the new classes you’ll use (from the java.time Javadoc), all of which work in the ISO-8601 calendar system.

Table 1. Descriptions of common Java 8 Date and Time classes

Class Description

LocalDate

A date without a time-zone, such as 2007-12-03.

LocalTime

A time without a time-zone, such as 10:15:30.

LocalDateTime

A date-time without a time-zone, such as 2007-12-03T10:15:30.

ZonedDateTime

A date-time with a time-zone, such as 2007-12-03T10:15:30+01:00 Europe/Paris.

Instant

Models a single instantaneous point on the time-line. This might be used to record event timestamps in the application.

To create new date/time instances:

  • Use now methods on those classes to create new instances that represent the current moment

  • Use of methods on those classes to create dates that represent past or future date/time values

“Now”

To create instances to represent the current date and time, use the now methods that are available on the new classes in the API:

import java.time._

LocalDate.now       // 2019-01-20
LocalTime.now       // 12:19:26.270
LocalDateTime.now   // 2019-01-20T12:19:26.270
Instant.now         // 2019-01-20T19:19:26.270Z
ZonedDateTime.now   // 2019-01-20T12:44:53.466-07:00[America/Denver]

The results of those methods demonstrate the data that’s stored in each type.

Past or future

To create dates and times in the past or future, use the of factory methods on each of the classes shown. For example, here are a few ways to create java.time.LocalDate instances with its of factory methods:

val squirrelDay = LocalDate.of(2020, 1, 21)
val squirrelDay = LocalDate.of(2020, Month.JANUARY, 21)
val squirrelDay = LocalDate.of(2020, 1, 1).plusDays(20)

Note that with LocalDate, January is represented by 1 (not 0).

java.time.LocalTime has five of* factory methods, including these:

LocalTime.of(hour: Int, minute: Int)
LocalTime.of(hour: Int, minute: Int, second: Int)

LocalTime.of(0, 0)    // 00:00
LocalTime.of(0, 1)    // 00:01
LocalTime.of(1, 1)    // 01:01
LocalTime.of(23, 59)  // 23:59

These intentional exceptions help demonstrate the valid values for minutes and hours:

LocalTime.of(23, 60)  // DateTimeException: Invalid value for MinuteOfHour,
                      // (valid values 0 - 59): 60

LocalTime.of(24, 1)   // DateTimeException: Invalid value for HourOfDay,
                      // (valid values 0 - 23): 24

java.time.LocalDateTime has nine of* factory method constructors, including these:

LocalDateTime.of(year: Int, month: Int, dayOfMonth: Int, hour: Int, minute: Int)
LocalDateTime.of(year: Int, month: Month, dayOfMonth: Int, hour: Int, minute: Int)
LocalDateTime.of(date: LocalDate, time: LocalTime)

java.time.ZonedDateTime has seven of* factory method constructors, including these:

of(int year, int month, int dayOfMonth, int hour, int minute, int second,
   int nanoOfSecond, ZoneId zone)
of(LocalDate date, LocalTime time, ZoneId zone)
of(LocalDateTime localDateTime, ZoneId zone)
ofInstant(Instant instant, ZoneId zone)

Here’s an example of the second method:

val zdt = ZonedDateTime.of(
    LocalDate.now,
    LocalTime.now,
    ZoneId.of("America/New_York")
)

// result: 2021-01-01T20:38:57.590542-05:00[America/New_York]

While I’m in the neighborhood, a few other java.time.ZoneId values look like this:

ZoneId.of("Europe/Paris")       // java.time.ZoneId = Europe/Paris
ZoneId.of("Asia/Tokyo")         // java.time.ZoneId = Asia/Tokyo
ZoneId.of("America/New_York")   // java.time.ZoneId = America/New_York

// an offset from UTC (Greenwich) time
ZoneId.of("UTC+1")              // java.time.ZoneId = UTC+01:00

java.time.Instant has three of* factory methods:

Instant.ofEpochMilli(epochMilli: Long)
Instant.ofEpochSecond(epochSecond: Long)
Instant.ofEpochSecond(epochSecond: Long, nanoAdjustment: Long)

Instant.ofEpochMilli(100)   // Instant = 1970-01-01T00:00:00.100Z
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

The Instant class is nice for many reasons, including giving you the ability to calculation the time duration between two instants:

import java.time.{Instant, Duration}

val start = Instant.now                     // Instant = 2021-01-02T03:41:20.067769Z
Thread.sleep(2000)
val stop = Instant.now                      // Instant = 2021-01-02T03:41:22.072429Z
val delta = Duration.between(start, stop)   // Duration = PT2.00466S
delta.toMillis                              // Long = 2004
delta.toNanos                               // Long = 2004660000