Skip to content

Parsing Date and Time

  • The core functions, which every industry uses.

GMT’s parse functions accept ISO 8601 strings and common wire formats, returning plain or zoned components. They never throw — invalid input yields an empty string or null.

HIGH

Not handling the empty string on invalid input

parseRfc2822, parseHttpDate, and parseSqlDateTime return an empty string for invalid input and never throw. Passing the result on unchecked turns bad input into an empty value somewhere downstream.

Wrong

const result = parseRfc2822(invalidInput); // ""
save({ sentAt: result }); // stores an empty timestamp

Right

import { parseRfc2822 } from "@northguild/gmt/zoned";
const result = parseRfc2822(invalidInput);
if (result === "") {
// invalid RFC 2822 input
}
MEDIUM

Checking a wire format with its regex

A pattern such as rfc3339DateTime proves the shape of a string, not that its date exists. It matches 29 February in a year that has none. The validator for the format is true exactly when the parser returns a value.

Wrong

rfc3339DateTime.test("2023-02-29T10:00:00Z"); // true — but 2023 has no 29 February

Right

import { isValidRfc3339DateTime } from "@northguild/gmt/zoned";
isValidRfc3339DateTime("2023-02-29T10:00:00Z"); // false
isValidRfc3339DateTime("2024-03-15T14:30:00-04:00"); // true
MEDIUM

Using string manipulation instead of parse functions

Splitting a date string on '-' and indexing the parts works for ISO 8601 today, but it breaks the moment your input includes a calendar annotation, a different separator, or fractional seconds.

Wrong

const [y, m, d] = dateStr.split("-"); // fragile — breaks on annotations or edge formats

Right

import { parseYearFromDate, parseMonthFromDate, parseDayFromDate } from "@northguild/gmt";
const y = parseYearFromDate(dateStr);
const m = parseMonthFromDate(dateStr);
const d = parseDayFromDate(dateStr);
MEDIUM

Assuming month is 1-indexed in arithmetic

parseMonthFromDate returns the 1-indexed month as a two-digit string, '01' to '12'. Adding or subtracting months on that number without a date-aware function can produce invalid month values.

Wrong

const m = parseMonthFromDate("2024-12-15"); // "12"
const next = Number(m) + 1; // 13 — not a valid month

Right

import { addDate } from "@northguild/gmt";
addDate("2024-12-15", { months: 1 }); // "2025-01-15" — handles overflow
MEDIUM

Confusing getWeekOfMonth with parseWeekFromDate

getWeekOfMonth tells you which week-of-month a date falls in (1-6). parseWeekFromDate returns the ISO week number (1-53). They answer different questions and produce different numbers for the same input.

Wrong

const wom = getWeekOfMonth("2024-01-31", "en-US"); // 5
// used as if it were an ISO week number

Right

import { getIsoWeekDate, parseWeekFromDate } from "@northguild/gmt";
const isoWeek = parseWeekFromDate("2024-01-31"); // 5
getIsoWeekDate("2024-01-31"); // { year: 2024, week: 5, weekday: 3 } — year is the week-year
MEDIUM

Week number without week-year is a bug in waiting

'Wait until week 35' is ambiguous without a week-year. ISO week 35 of 2024 and week 35 of 2025 are 52 weeks apart. Always pair the week number with its week-year.

Wrong

const week = parseWeekFromDate(startDate); // 35
// wait until week 35 — but which year?
parseYearFromDate("2024-12-30"); // "2024" — the calendar year, but that date is in week 1 of 2025

Right

import { getIsoWeekDate } from "@northguild/gmt";
getIsoWeekDate("2024-12-30"); // { year: 2025, week: 1, weekday: 1 }
const { year: weekYear, week } = getIsoWeekDate(startDate);
// wait until week <week> of <weekYear>
MEDIUM

Checking for null on parseRfc2822/parseHttpDate/parseSqlDateTime/parseRfc3339

These functions return an empty string for invalid input, never null. A null check never fires, so invalid input passes straight through it. Check for the empty string.

Wrong

const r = parseRfc3339(input);
if (r === null) { /* never true — invalid input returns "" */ }

Right

import { parseRfc3339 } from "@northguild/gmt/zoned";
const r = parseRfc3339(input);
if (r === "") {
// invalid input
}