# 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](https://github.com/smucclaw/l4-ide/blob/main/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](/l4/reference/libraries/timezone.md) library for convenient timezone constants.

```l4
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



```l4-file
-- 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](https://github.com/smucclaw/l4-ide/blob/main/jl4-core/libraries/datetime.l4) source for all functions.**
