DateTime Library

Absolute points in time combining date, time, and timezone for legal deadlines and cross-timezone comparisons. Stored internally as UTC; extractors return local values in the stored timezone. Can be imported into L4 files with IMPORT datetime. Automatically imports daydate for date operations.

Location

jl4-core/libraries/datetime.l4

Prerequisites

Requires a TIMEZONE IS declaration in the document when using constructors without an explicit timezone parameter. Use with the timezone library for convenient timezone constants.

IMPORT datetime
IMPORT timezone

TIMEZONE IS SGT

Features

  • DateTime construction with flexible overloads (date + time, numbers in DMY order, or ISO-8601 strings)
  • Automatic use of document TIMEZONE IS declaration
  • Explicit timezone override per value using IANA timezone strings
  • Date, time, and timezone extraction from DateTime values
  • Time-of-day predicates (morning, afternoon, evening)
  • Cross-timezone comparison (UTC-based equality)
  • Relative datetime operations (at midnight, at noon, at specific time)
  • ISO-8601 string parsing for JSON interoperability

Key Functions

DateTime Construction (from DATE/TIME):

  • Datetime date time - Date + time in document timezone
  • Datetime date time tz - Date + time in explicit IANA timezone
  • Datetime date h m s - Date + hours/minutes/seconds in document timezone
  • Datetime date h m s tz - Date + hours/minutes/seconds in explicit timezone
  • Datetime date - Date at midnight in document timezone
  • Datetime date tz - Date at midnight in explicit timezone

DateTime Construction (from numbers, DMY order):

  • Datetime d m y h mn s - Day, month, year, hour, minute, second in document timezone
  • Datetime d m y h mn s tz - Same with explicit timezone
  • Datetime d m y h mn - Seconds default to 0
  • Datetime d m y h - Minutes and seconds default to 0
  • Datetime d m y - Midnight in document timezone
  • Datetime m y - 1st of month, midnight
  • Datetime y - January 1st, midnight

All number-based constructors accept an optional trailing tz (STRING) for explicit timezone.

DateTime Construction (from strings, returns MAYBE DATETIME):

  • Datetime str - Parse ISO-8601 string (e.g. "2024-06-15T10:30:00Z")
  • Datetime str tz - Parse ISO-8601 string with explicit display timezone

DateTime Extractors:

  • Date of dt - Get the date component
  • Time of dt - Get the time component (local)
  • Timezone of dt - Get the IANA timezone name
  • the hour of dt, the minute of dt, the second of dt
  • the day of dt, the month of dt, the year of dt

DateTime Serial:

  • dt Datetime to serial - UTC-based serial number

Predicates:

  • is morning, is afternoon, is evening
  • is before noon, is after noon

Relative Operations:

  • at midnight dt - Same date, midnight
  • at noon dt - Same date, noon
  • dt at time - Same date, different time

Comparators:

  • the earlier of dt1 dt2
  • the later of dt1 dt2
  • dt1 is before dt2, dt1 is after dt2
  • Standard comparison operators: LESS THAN, GREATER THAN, AT MOST, AT LEAST

Example: DateTime Operations

-- DateTime Example: Absolute points in time with timezones
IMPORT datetime
IMPORT timezone
IMPORT daydate

TIMEZONE IS SGT


-- DateTime construction from DATE + time components (uses document timezone SGT by default)
DECIDE `the deadline` IS Datetime (Date 31 12 2025) 17 0 0
#EVAL `the deadline`  -- 2025-12-31T17:00:00+08:00

-- With explicit timezone override
DECIDE `london meeting` IS Datetime (DATE_FROM_DMY 1 6 2026) (TIME_FROM_HMS 9 0 0) "Europe/London"
#EVAL `london meeting`  -- 2026-06-01T09:00:00+01:00

-- Date-only (midnight in document timezone)
DECIDE `start of year` IS Datetime (Date 1 1 2026)
#EVAL `start of year`  -- 2026-01-01T00:00:00+08:00


-- DateTime construction from numbers (DMY order, like Date d m y)
DECIDE `full datetime` IS Datetime 31 12 2025 17 30 0
#EVAL `full datetime`  -- 2025-12-31T17:30:00+08:00

DECIDE `date and hour` IS Datetime 15 6 2025 14
#EVAL `date and hour`  -- 2025-06-15T14:00:00+08:00

DECIDE `date only` IS Datetime 25 12 2025
#EVAL `date only`  -- 2025-12-25T00:00:00+08:00

DECIDE `month and year` IS Datetime 6 2025
#EVAL `month and year`  -- 2025-06-01T00:00:00+08:00

DECIDE `year only` IS Datetime 2025
#EVAL `year only`  -- 2025-01-01T00:00:00+08:00

-- Number constructors with explicit timezone
DECIDE `nyc new year` IS Datetime 1 1 2026 0 0 0 EST
#EVAL `nyc new year`  -- 2026-01-01T00:00:00-05:00


-- DateTime from ISO-8601 string (JSON interop) - returns MAYBE DATETIME
DECIDE `from iso` IS Datetime "2025-06-15T10:30:00Z"
#EVAL `from iso`  -- JUST OF (2025-06-15T18:30:00+0800)

-- ISO string with explicit display timezone - returns MAYBE DATETIME
DECIDE `from iso tz` IS Datetime "2025-06-15T10:30:00Z" SGT
#EVAL `from iso tz`  -- JUST OF (2025-06-15T18:30:00+0800)


-- Extracting components (returns local values)
DECIDE `meeting` IS Datetime (Date 15 6 2025) (TIME_FROM_HMS 14 30 0)
#EVAL `Date of` `meeting`      -- the date component
#EVAL `Time of` `meeting`      -- the time component
#EVAL `Timezone of` `meeting`  -- "Asia/Singapore"
#EVAL `the hour of` `meeting`  -- 14
#EVAL `the day of` `meeting`   -- 15

-- Predicates
DECIDE `afternoon check` IS `meeting` `is afternoon`
#EVAL `afternoon check`  -- TRUE

-- Relative operations
#EVAL `at midnight` `meeting`  -- same date at 00:00:00
#EVAL `at noon` `meeting`      -- same date at 12:00:00

-- Cross-timezone comparison (compares UTC instants)
DECIDE `sg morning` IS Datetime (Date 1 6 2026) 8 0 0 SGT
DECIDE `london midnight` IS Datetime (Date 1 6 2026) 0 0 0 "Europe/London"
DECIDE `sg is later` IS `sg morning` GREATER THAN `london midnight`
#EVAL `sg is later`  -- TRUE (SGT 08:00 = UTC 00:00, London 00:00 BST = UTC 23:00 prev day)

-- DateTime comparisons
DECIDE `before deadline` IS `meeting` LESS THAN `the deadline`
#EVAL `before deadline`  -- TRUE

DECIDE `meeting is before deadline` IS `meeting` `is before` `the deadline`
DECIDE `deadline is after meeting` IS `the deadline` `is after` `meeting`
#EVAL `meeting is before deadline`  -- TRUE
#EVAL `deadline is after meeting`   -- TRUE

#EVAL `the earlier of` `meeting` `the deadline`
#EVAL `the later of` `meeting` `the deadline`

See datetime.l4 source for all functions.