Scala FAQ: How Do I Create New Date and Time Instances with Scala

Scala FAQ: How do I create new date and time instances with Scala? Specifically, using Scala, how do I create new date and time instances using the Date and Time API that was introduced with Java 8.

Solution: Creating dates and times in Scala (Java and Kotlin, too)

Using the Java 8 API and newer, you can create new dates, times, and date/time values. The table below provides a description of some of the new Java date/time 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” in Scala

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

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

This is an excerpt from the Scala Cookbook, 2nd Edition. This is Recipe 3.9, Creating New Date and Time Instances. Note that this solution also works with Java and Kotlin.