Temporal integration
This API is available since Optique 0.4.0.
The @optique/temporal package provides value parsers for the Temporal API, a modern JavaScript proposal for working with dates and times. These parsers offer type-safe parsing of various temporal values including instants, durations, dates, times, and time zones.
IMPORTANT
These parsers require globalThis.Temporal at runtime. If your runtime does not ship the Temporal API yet, install and initialize a polyfill such as @js-temporal/polyfill before parsing.
deno add --jsr @optique/temporalnpm add @optique/temporalpnpm add @optique/temporalyarn add @optique/temporalbun add @optique/temporalinstant() parser
The instant() parser validates ISO 8601 timestamp strings and returns Temporal.Instant objects representing precise moments in time:
import { instant } from "@optique/temporal";
// Basic instant parser
const timestamp = instant();
// Instant with custom metavar
const createdAt = instant({ metavar: "TIMESTAMP" });The parser accepts ISO 8601 strings with timezone information:
// Valid instant formats
"2023-12-25T10:30:00Z" // UTC
"2023-12-25T10:30:00+09:00" // With timezone offset
"2023-12-25T10:30:00.123456789Z" // With nanosecond precision
"2023-12-25T10:30:00-05:00" // Negative timezone offsetduration() parser
The duration() parser validates ISO 8601 duration strings and returns Temporal.Duration objects for representing spans of time:
import { duration } from "@optique/temporal";
// Basic duration parser
const timeout = duration();
// Duration with custom metavar
const interval = duration({ metavar: "INTERVAL" });The parser accepts ISO 8601 duration format:
// Valid duration formats
"PT30M" // 30 minutes
"P1D" // 1 day
"PT1H30M" // 1 hour 30 minutes
"P1Y2M3DT4H5M6S" // 1 year, 2 months, 3 days, 4 hours, 5 minutes, 6 seconds
"PT0.123S" // 123 millisecondszonedDateTime() parser
The zonedDateTime() parser validates ISO 8601 datetime strings with timezone information and returns Temporal.ZonedDateTime objects:
import { zonedDateTime } from "@optique/temporal";
// Basic zoned datetime parser
const appointment = zonedDateTime();
// Zoned datetime with custom metavar
const meetingTime = zonedDateTime({ metavar: "MEETING_TIME" });The parser accepts ISO 8601 strings with timezone identifiers or offsets:
// Valid zoned datetime formats
"2023-12-25T10:30:00[Asia/Seoul]" // With IANA timezone
"2023-12-25T10:30:00+09:00[Asia/Seoul]" // With offset and timezone
"2023-12-25T10:30:00-05:00[America/New_York]" // Different timezoneplainDate() parser
The plainDate() parser validates ISO 8601 date strings and returns Temporal.PlainDate objects representing calendar dates without time information:
import { plainDate } from "@optique/temporal";
// Basic date parser
const birthDate = plainDate();
// Date with custom metavar
const deadline = plainDate({ metavar: "DEADLINE" });The parser accepts ISO 8601 date format:
// Valid date formats
"2023-12-25" // Basic date format
"2023-01-01" // New Year's Day
"1999-12-31" // Y2K eveplainTime() parser
The plainTime() parser validates ISO 8601 time strings and returns Temporal.PlainTime objects representing wall-clock time without date or timezone:
import { plainTime } from "@optique/temporal";
// Basic time parser
const startTime = plainTime();
// Time with custom metavar
const alarmTime = plainTime({ metavar: "ALARM_TIME" });The parser accepts ISO 8601 time format:
// Valid time formats
"10:30:00" // Hour, minute, second
"14:15" // Hour, minute (seconds default to 00)
"09:30:00.123" // With milliseconds
"23:59:59.999999999" // With nanosecond precisionplainDateTime() parser
The plainDateTime() parser validates ISO 8601 datetime strings without timezone information and returns Temporal.PlainDateTime objects:
import { plainDateTime } from "@optique/temporal";
// Basic datetime parser
const localTime = plainDateTime();
// Datetime with custom metavar
const eventTime = plainDateTime({ metavar: "EVENT_TIME" });The parser accepts ISO 8601 datetime format:
// Valid datetime formats
"2023-12-25T10:30:00" // Basic datetime
"2023-12-25T14:15" // Without seconds
"2023-12-25T09:30:00.123" // With milliseconds
"2023-12-25 10:30:00" // Space separator (also valid)plainYearMonth() parser
The plainYearMonth() parser validates year-month strings and returns Temporal.PlainYearMonth objects for representing specific months:
import { plainYearMonth } from "@optique/temporal";
// Basic year-month parser
const reportMonth = plainYearMonth();
// Year-month with custom metavar
const billingPeriod = plainYearMonth({ metavar: "BILLING_PERIOD" });The parser accepts year-month format:
// Valid year-month formats
"2023-12" // December 2023
"2024-01" // January 2024
"1999-06" // June 1999plainMonthDay() parser
The plainMonthDay() parser validates month-day strings and returns Temporal.PlainMonthDay objects for representing recurring dates:
import { plainMonthDay } from "@optique/temporal";
// Basic month-day parser
const birthday = plainMonthDay();
// Month-day with custom metavar
const holiday = plainMonthDay({ metavar: "HOLIDAY_DATE" });The parser accepts month-day format:
// Valid month-day formats
"12-25" // Christmas (December 25)
"01-01" // New Year's Day (January 1)
"07-04" // Independence Day (July 4)
"02-29" // Leap day (February 29)
"--12-25" // ISO 8601 format with -- prefix is also acceptedtimeZone() parser
The timeZone() parser validates timezone identifiers and returns the TimeZone union type exported by @optique/temporal:
import { timeZone } from "@optique/temporal";
// Basic timezone parser
const userTimezone = timeZone();
// Timezone with custom metavar
const displayTimezone = timeZone({ metavar: "DISPLAY_TZ" });The parser accepts valid two-segment and three-segment IANA identifiers, plus a curated set of single-segment identifiers for cross-runtime compatibility:
// Valid timezone identifiers
"UTC" // Coordinated Universal Time
"GMT" // Greenwich Mean Time alias
"EST" // POSIX-style single-segment identifier
"Japan" // Deprecated alias still accepted
"Cuba" // Deprecated alias still accepted
"Asia/Seoul" // South Korea
"America/New_York" // Eastern Time (US)
"Europe/London" // Europe/London
"America/Argentina/Buenos_Aires" // Three-segment identifierSingle-segment identifiers are matched case-insensitively and normalized to their canonical casing, so inputs like utc, gmt, and japan parse as "UTC", "GMT", and "Japan".
Error messages
All temporal parsers provide clear, specific error messages for different validation failures:
$ myapp --timestamp "not-a-timestamp"
Error: Invalid instant: not-a-timestamp. Expected ISO 8601 format like 2020-01-23T17:04:36Z.
$ myapp --duration "invalid-duration"
Error: Invalid duration: invalid-duration. Expected ISO 8601 format like PT1H30M.
$ myapp --timezone "Invalid/Timezone"
Error: Invalid timezone identifier: Invalid/Timezone. Must be a valid IANA timezone like "Asia/Seoul" or "UTC".Integration with Temporal API
The temporal parsers return native Temporal objects with rich functionality:
const timestampArg = argument(instant());
const result = parse(timestampArg, ["2023-12-25T10:30:00Z"]);
if (result.success) {
const instant = result.value;
console.log(`Epoch milliseconds: ${instant.epochMilliseconds}`);
console.log(`UTC string: ${instant.toString()}`);
console.log(`In timezone: ${instant.toZonedDateTimeISO("Asia/Seoul")}`);
}
const timeoutArg = argument(duration());
const durationResult = parse(timeoutArg, ["PT1H30M"]);
if (durationResult.success) {
const duration = durationResult.value;
console.log(`Total seconds: ${duration.total("seconds")}`);
console.log(`Hours: ${duration.hours}, Minutes: ${duration.minutes}`);
}The temporal parsers provide comprehensive date and time handling capabilities with full type safety and integration with the modern Temporal API.