Temporal Built-ins

Temporal API reference — dates, times, durations, and time zones.

Implements the ECMAScript Temporal API. See the Temporal documentation for the full specification reference.

GocciaScript differences: ISO 8601 calendar only. Duration.total() and Duration.round() do not yet support relativeTo for calendar-relative conversions (years/months).

Executive Summary#

  • Modern date/time API — Implements the ECMAScript Temporal API, replacing legacy Date with immutable, type-safe alternatives
  • Rich type system — Provides distinct types for dates, times, date-times, instants, durations, year-months, month-days, and timezone-aware date-times
  • ISO 8601 only — All types use the ISO 8601 calendar; operations return new instances (immutability by design)
  • Timezone supportZonedDateTime and Temporal.Now handle IANA timezone identifiers and DST transitions
  • Arithmetic and comparison — Every type supports add, subtract, until, since, equals, and static compare

Overview (Goccia.Builtins.Temporal.pas)#

An implementation of the ECMAScript Temporal API providing modern date/time handling. ISO 8601 calendar only. All Temporal types are immutable — operations return new instances.

Namespace structure:

Temporal.Now           // Current time utilities
Temporal.Duration      // Time duration representation
Temporal.Instant       // Absolute point in time (epoch-based)
Temporal.PlainDate     // Calendar date (no time/timezone)
Temporal.PlainTime     // Wall-clock time (no date/timezone)
Temporal.PlainDateTime // Date + time (no timezone)
Temporal.PlainYearMonth // Year and month (no day/time/timezone)
Temporal.PlainMonthDay  // Month and day (no year/time/timezone)
Temporal.ZonedDateTime  // Date + time + timezone

Time Zone Data#

Temporal.ZonedDateTime loads IANA timezone data from TZif zoneinfo data. Lookup order is:

1. GOCCIA_TZDIR when set 2. system zoneinfo directories on Unix-like platforms (/usr/share/zoneinfo, /usr/share/zoneinfo.default) 3. Windows ICU on Windows 10 and newer 4. embedded generated TZif resource data

The embedded data is generated from the upstream IANA timezone data distribution and linked as a FreePascal .res resource. This keeps named IANA zones and DST transitions available in single-binary builds even when neither system zoneinfo nor Windows ICU can provide the requested zone. Define GOCCIA_TEMPORAL_NO_EMBEDDED_TZDATA at compile time to omit the embedded fallback.

Temporal.Duration#

Represents a length of time with 10 components (years through nanoseconds).

Constructor / StaticDescription
new Temporal.Duration(y?, mo?, w?, d?, h?, min?, s?, ms?, us?, ns?)Create from components (all default to 0)
Temporal.Duration.from(item)Create from string ("P1Y2M3DT4H5M6S"), Duration, or object
Temporal.Duration.compare(one, two)Compare two durations (-1, 0, 1)
GetterDescription
years, months, weeks, daysDate components
hours, minutes, secondsTime components
milliseconds, microseconds, nanosecondsSub-second components
sign-1, 0, or 1
blankTrue if all components are zero
MethodDescription
negated()Return negated duration
abs()Return absolute duration
add(other)Add another duration
subtract(other)Subtract another duration
with(fields)Return new duration with overridden fields
total(unit)Convert to total of a single unit (e.g., "hours"). Accepts a string or options object { unit, relativeTo? }. Throws RangeError if duration has non-zero years/months without relativeTo. Calendar-relative conversion (relativeTo) is not yet supported.
round(options)Round the duration. Accepts a string (smallestUnit) or options object { smallestUnit, largestUnit, roundingMode, roundingIncrement }. Rebalances components from largestUnit down. Throws RangeError if duration has years/months (requires relativeTo, not yet supported). At least smallestUnit or largestUnit must be specified.
toString() / toJSON()ISO 8601 duration string (e.g., "P1Y2M3DT4H5M6S")
valueOf()Throws TypeError (prevents implicit coercion)

Temporal.PlainDate#

Represents a calendar date without time or timezone.

Constructor / StaticDescription
new Temporal.PlainDate(year, month, day)Create from components
Temporal.PlainDate.from(item [, options])Create from string ("2024-03-15"), PlainDate, or object. Options: { overflow } where overflow is "constrain" (default, clamps out-of-range values) or "reject" (throws RangeError).
Temporal.PlainDate.compare(one, two)Compare two dates (-1, 0, 1)
GetterDescription
calendarIdAlways "iso8601"
year, month, dayDate components
monthCode"M01" through "M12"
dayOfWeek1 (Monday) through 7 (Sunday)
dayOfYear, weekOfYear, yearOfWeekISO week-date components
daysInWeek, daysInMonth, daysInYear, monthsInYearCalendar info
inLeapYearBoolean
MethodDescription
with(fields)Return new date with overridden fields
add(duration) / subtract(duration)Date arithmetic
until(other [, options]) / since(other [, options])Difference as Duration. Options: { largestUnit, smallestUnit, roundingMode, roundingIncrement }. Units: "year", "month", "week", or "day" (defaults: largest "day", smallest "day"). Rounding mode defaults to "trunc"; increment defaults to 1.
equals(other)Equality check
toPlainDateTime(time?)Combine with a time
toPlainYearMonth()Extract year and month as PlainYearMonth
toPlainMonthDay()Extract month and day as PlainMonthDay
toZonedDateTime(timeZone)Combine with a timezone (string or { timeZone } object) to create a ZonedDateTime at midnight
toString() / toJSON()ISO date string (e.g., "2024-03-15")
valueOf()Throws TypeError

Temporal.PlainTime#

Represents a wall-clock time without date or timezone.

Constructor / StaticDescription
new Temporal.PlainTime(h?, min?, s?, ms?, us?, ns?)Create from components (all default to 0)
Temporal.PlainTime.from(item)Create from string ("13:45:30"), PlainTime, or object
Temporal.PlainTime.compare(one, two)Compare two times (-1, 0, 1)
GetterDescription
hour, minute, secondTime components
millisecond, microsecond, nanosecondSub-second components
MethodDescription
with(fields)Return new time with overridden fields
add(duration) / subtract(duration)Time arithmetic (wraps at midnight)
until(other [, options]) / since(other [, options])Difference as Duration. Options: { largestUnit, smallestUnit, roundingMode, roundingIncrement }. Units: "hour" through "nanosecond" (defaults: largest "hour", smallest "nanosecond"). Rounding mode defaults to "trunc"; increment defaults to 1.
round(options)Round to nearest unit. Accepts a string (smallestUnit) or options object { smallestUnit, roundingMode, roundingIncrement }.
equals(other)Equality check
toString([options]) / toJSON()ISO time string (e.g., "13:45:30"). toString accepts { fractionalSecondDigits } (0-9 or "auto").
valueOf()Throws TypeError

Temporal.PlainDateTime#

Represents a date and time without timezone. Combines PlainDate and PlainTime.

Constructor / StaticDescription
new Temporal.PlainDateTime(y, mo, d, h?, min?, s?, ms?, us?, ns?)Create from components
Temporal.PlainDateTime.from(item)Create from string, PlainDateTime, or object
Temporal.PlainDateTime.compare(one, two)Compare two date-times (-1, 0, 1)
GetterDescription
All PlainDate getters + all PlainTime gettersCombined date and time access
MethodDescription
with(fields)Return new date-time with overridden fields
withPlainTime(time?)Replace time component
add(duration) / subtract(duration)Date-time arithmetic
until(other [, options]) / since(other [, options])Difference as Duration. Options: { largestUnit, smallestUnit, roundingMode, roundingIncrement }. Any unit from "year" to "nanosecond" (defaults: largest "day", smallest "nanosecond"). Mode defaults to "trunc", increment to 1.
round(options)Round to nearest unit. Accepts a string (smallestUnit) or options object { smallestUnit, roundingMode, roundingIncrement }.
equals(other)Equality check
toPlainDate() / toPlainTime()Extract date or time component
toPlainYearMonth()Extract year and month as PlainYearMonth
toPlainMonthDay()Extract month and day as PlainMonthDay
toZonedDateTime(timeZone)Combine with a timezone (string or { timeZone } object) to create a ZonedDateTime
toString([options]) / toJSON()ISO string (e.g., "2024-03-15T13:45:30"). toString accepts { fractionalSecondDigits } (0-9 or "auto").
valueOf()Throws TypeError

Temporal.Instant#

Represents an absolute point in time (epoch-based), independent of calendar or timezone.

Constructor / StaticDescription
new Temporal.Instant(epochNanoseconds)Create from epoch nanoseconds (BigInt)
Temporal.Instant.from(item)Create from string or Instant
Temporal.Instant.fromEpochMilliseconds(ms)Create from epoch milliseconds (Number)
Temporal.Instant.fromEpochNanoseconds(ns)Create from epoch nanoseconds (BigInt)
Temporal.Instant.compare(one, two)Compare two instants (-1, 0, 1)
GetterDescription
epochMillisecondsMilliseconds since Unix epoch (Number)
epochNanosecondsNanoseconds since Unix epoch (BigInt)
MethodDescription
add(duration) / subtract(duration)Time arithmetic (no calendar units)
until(other [, options]) / since(other [, options])Difference as Duration. Options: { largestUnit, smallestUnit, roundingMode, roundingIncrement }. "hour" through "nanosecond" only — calendar units not allowed (defaults: largest "hour", smallest "nanosecond"). Rounding: mode "trunc", increment 1.
round(options)Round to nearest unit. Accepts a string (smallestUnit) or options object { smallestUnit, roundingMode, roundingIncrement }.
equals(other)Equality check
toString([options]) / toJSON()ISO string with UTC (e.g., "2024-03-15T13:45:30Z"). toString accepts { fractionalSecondDigits } (0-9 or "auto").
valueOf()Throws TypeError

Temporal.PlainYearMonth#

Represents a year and month without a day, time, or timezone.

Constructor / StaticDescription
new Temporal.PlainYearMonth(year, month)Create from components
Temporal.PlainYearMonth.from(item)Create from string ("2024-03"), PlainYearMonth, or object
Temporal.PlainYearMonth.compare(one, two)Compare two year-months (-1, 0, 1)
GetterDescription
calendarIdAlways "iso8601"
year, monthDate components
monthCode"M01" through "M12"
daysInMonth, daysInYear, monthsInYearCalendar info
inLeapYearBoolean
MethodDescription
with(fields)Return new year-month with overridden fields
add(duration) / subtract(duration)Year-month arithmetic (years and months only)
until(other [, options]) / since(other [, options])Difference as Duration. Options: { largestUnit, smallestUnit, roundingMode, roundingIncrement }. "year" (default largest) or "month" (default smallest). Supports rounding via mode ("trunc" default) and increment (default 1).
equals(other)Equality check
toPlainDate(item)Combine with a day ({ day }) to create a PlainDate
toString() / toJSON()ISO string (e.g., "2024-03")
valueOf()Throws TypeError

Temporal.PlainMonthDay#

Represents a month and day without a year, time, or timezone. Uses a reference year (1972) for validation.

Constructor / StaticDescription
new Temporal.PlainMonthDay(month, day)Create from components
Temporal.PlainMonthDay.from(item)Create from string ("12-25"), PlainMonthDay, or object with { monthCode, day }
Temporal.PlainMonthDay.compare(one, two)Compare two month-days (-1, 0, 1)
GetterDescription
calendarIdAlways "iso8601"
monthCode"M01" through "M12"
dayDay of month
MethodDescription
with(fields)Return new month-day with overridden fields (accepts monthCode and day)
equals(other)Equality check
toPlainDate(item)Combine with a year ({ year }) to create a PlainDate
toString() / toJSON()Month-day string (e.g., "12-25")
valueOf()Throws TypeError

Temporal.ZonedDateTime#

Represents an absolute date and time in a specific timezone. Combines an instant (epoch-based) with a timezone identifier for wall-clock interpretation.

Constructor / StaticDescription
new Temporal.ZonedDateTime(epochNanoseconds, timeZone)Create from epoch nanoseconds (BigInt) and timezone ID
Temporal.ZonedDateTime.from(item)Create from ISO string with timezone annotation (e.g., "2024-03-15T13:45:30+05:30[Asia/Kolkata]"), ZonedDateTime, or object
Temporal.ZonedDateTime.compare(one, two)Compare two zoned date-times (-1, 0, 1)
GetterDescription
calendarIdAlways "iso8601"
timeZoneIdIANA timezone identifier (e.g., "America/New_York")
year, month, monthCode, dayDate components (wall-clock, timezone-adjusted)
dayOfWeek, dayOfYear, weekOfYear, yearOfWeekISO week-date components
daysInWeek, daysInMonth, daysInYear, monthsInYearCalendar info
inLeapYearBoolean
hoursInDayHours in the wall-clock day (accounts for DST transitions)
hour, minute, secondTime components
millisecond, microsecond, nanosecondSub-second components
offsetUTC offset string (e.g., "+05:30")
offsetNanosecondsUTC offset in nanoseconds
epochMillisecondsMilliseconds since Unix epoch (Number)
epochNanosecondsNanoseconds since Unix epoch (BigInt)
MethodDescription
with(fields)Return new ZonedDateTime with overridden fields
withPlainDate(date)Replace date component
withPlainTime(time?)Replace time component
withTimeZone(timeZone)Re-interpret the same instant in a different timezone
add(duration) / subtract(duration)Date-time arithmetic
until(other [, options]) / since(other [, options])Difference as Duration. Options: { largestUnit, smallestUnit, roundingMode, roundingIncrement }. Accepts any unit from "year" to "nanosecond" (defaults: largest "hour", smallest "nanosecond"). Rounding via mode ("trunc" default) and increment (default 1). Calendar-aware for day-or-larger units, including DST-aware rounding across variable-length local days.
round(options)Round to nearest unit. Accepts a string (smallestUnit) or options object { smallestUnit, roundingMode, roundingIncrement }.
equals(other)Equality check
startOfDay()Return ZonedDateTime at the start of the wall-clock day
toInstant()Extract the underlying Instant
toPlainDate() / toPlainTime()Extract date or time component
toPlainDateTime()Extract date-time without timezone
toString([options]) / toJSON()ISO string with offset and timezone annotation (e.g., "2024-03-15T13:45:30+05:30[Asia/Kolkata]"). toString accepts { fractionalSecondDigits } (0-9 or "auto").
valueOf()Throws TypeError

Temporal.Now#

Provides current time in various representations.

MethodDescription
Temporal.Now.timeZoneId()System timezone identifier (e.g., "America/New_York")
Temporal.Now.instant()Current time as Instant
Temporal.Now.zonedDateTimeISO([timeZone])Current date-time as ZonedDateTime in the given timezone (defaults to system timezone)
Temporal.Now.plainDateISO()Current date as PlainDate
Temporal.Now.plainTimeISO()Current time as PlainTime
Temporal.Now.plainDateTimeISO()Current date-time as PlainDateTime