Skip to content

Migrate from Day.js to Temporal with GMT

Checked against Day.js 1.11.23 on 2026-10-27.

Migrate to Temporal with GMT explains the one change that applies to every call below: GMT takes strings in and gives strings out.

Day.jsGMTNote
dayjs(s)
isValidDate@northguild/gmt/plain/validate
isValidDateTime@northguild/gmt/plain/validate
The string is the value; check it with a validator. dayjs("2024-02-30") is 2024-03-01. Measured in M9, M9b.
dayjs(s, "DD/MM/YYYY", true) (customParseFormat)
parseDateWithPattern@northguild/gmt/plain/parse
Rewrite the tokens to dd/MM/yyyy. Measured in M9d.
dayjs(s, "YYYY-MM", true) (customParseFormat)
parseYearMonth@northguild/gmt/plain/parse
parseYearMonthWithPattern@northguild/gmt/plain/parse
YYYY-MM is the ISO form, which parseYearMonth reads. For another pattern, rewrite the tokens, as in MM/yyyy.
.isValid()
isValidDate@northguild/gmt/plain/validate
.format("LL") (localizedFormat)
formatDate@northguild/gmt/plain/format
GMT has no token formatter; pass a locale and dateStyle.
.toISOString()noneNone for a GMT UTC string; it is already ISO 8601. Measured in M14.
dayjs(), dayjs().tz(z)
getUtcNow@northguild/gmt/utc/get
getZonedNow@northguild/gmt/zoned/get
dayjs().format("YYYY-MM-DD")
getToday@northguild/gmt/plain/get
getZonedToday@northguild/gmt/zoned/get
.add(1, "day")
addDate@northguild/gmt/plain/calculate
addZoned@northguild/gmt/zoned/calculate
With the timezone plugin, Day.js keeps the starting offset after a clock change: 2024-03-30 12:00 in Berlin plus one day gives 12:00+01:00; Temporal gives 12:00+02:00. Measured in M1, M2, M3, M5.
.add(1, "month")
addDate@northguild/gmt/plain/calculate
The day is clamped to the month length. Measured in M7.
.subtract(n, unit)
subtractDate@northguild/gmt/plain/calculate
subtractZoned@northguild/gmt/zoned/calculate
.add(1, "hour")
addZoned@northguild/gmt/zoned/calculate
b.diff(a, "day")
diffDate@northguild/gmt/plain/calculate
The arguments are in the other order: earlier first.
b.diff(a, "month")
diffDate@northguild/gmt/plain/calculate
From 2024-01-31 to 2024-02-29 Day.js counts 1 month and GMT counts 0. Measured in M8.
.startOf("month")
startOfDate@northguild/gmt/plain/calculate
.endOf("month")
endOfDate@northguild/gmt/plain/calculate
dayjs.tz(s, z).startOf("day") (timezone)
startOfZoned@northguild/gmt/zoned/calculate
On a day whose midnight is skipped, Day.js returns a 00:00 that does not exist unless the host zone is America/Santiago, so the result depends on the host zone. Measured in M6.
.isBefore(b), .isAfter(b)
isBeforeDate@northguild/gmt/plain/compare
isAfterDate@northguild/gmt/plain/compare
.isSame(b)
areDatesEqual@northguild/gmt/plain/compare
areUtcEqual@northguild/gmt/utc/compare
Measured in M3b.
.isSame(b, "day")
areDatesEqualBy@northguild/gmt/plain/compare
.isBetween(a, b) (isBetween)
isBetweenDate@northguild/gmt/plain/compare
Day.js excludes both ends by default; pass { inclusiveStart: false, inclusiveEnd: false }. Day.js also returns true when a is after b; GMT returns false.
dayjs.min(…), dayjs.max(…) (minMax)
minDate@northguild/gmt/plain/calculate
maxDate@northguild/gmt/plain/calculate
.daysInMonth(), .isLeapYear() (isLeapYear)
getDaysInMonth@northguild/gmt/plain/calculate
getDaysInYearMonth@northguild/gmt/plain/calculate
isLeapYear@northguild/gmt/plain/validate
.isoWeek(), .isoWeekYear(), .isoWeeksInYear() (isoWeek)
getIsoWeekDate@northguild/gmt/calendar/calculate
getWeeksInYear@northguild/gmt/plain/calculate
.week() (weekOfYear) is a locale week. Measured in M12.
dayjs.tz(local, z), .tz(z) (timezone)
convertPlainDateTimeToZoned@northguild/gmt/zoned/convert
convertZonedToZoned@northguild/gmt/zoned/convert
GMT takes disambiguation for a wall time in a gap or an overlap. Measured in M4, M4b, M16.
.fromNow() (relativeTime)
formatRelativeZoned@northguild/gmt/zoned/format
formatRelativeDate@northguild/gmt/plain/format
dayjs.duration(s).humanize() (duration)
parseDuration@northguild/gmt/duration/parse
formatDuration@northguild/gmt/duration/format
dayjs.unix(sec), .unix()
convertUnixToUtc@northguild/gmt/unix/convert
convertUtcToUnix@northguild/gmt/utc/convert
Pass { epochUnit: "seconds" }.
  • Day.js values are immutable objects. Most calls in the table need a plugin from the same package; the plugin is named in brackets.
  • month() counts months from 0. GMT counts them from 1 to 12.
  • b.diff(a, unit) subtracts the earlier value from the later one. diffDate(a, b, unit) takes the earlier value first.
  • Invalid input gives an object whose format() returns "Invalid Date". GMT returns "", null, false or [].
import { diffDate } from "@northguild/gmt/plain/calculate";
diffDate("2024-03-01", "2024-03-15", "days"); // 14

Each item is a case where the library’s result differs from Temporal’s. The full matrix also lists the cases where it matches.

  • M1 Add one calendar day across a DST gap

    Input
    2024-03-30T02:30:00+01:00[Europe/Berlin], plus 1 day (02:30 does not exist on 2024-03-31)
    Library returns
    2024-03-31T02:30:00+01:00
    Temporal returns
    2024-03-31T03:30:00+02:00[Europe/Berlin]
  • M2 Add one calendar day, not 24 hours

    Input
    2024-03-30T12:00:00+01:00[Europe/Berlin], plus 1 day (the day of 2024-03-31 has 23 hours)
    Library returns
    2024-03-31T12:00:00+01:00
    Temporal returns
    2024-03-31T12:00:00+02:00[Europe/Berlin]
  • M5 Add one day across a 30-minute DST change

    Input
    2024-10-05T02:15:00+10:30[Australia/Lord_Howe], plus 1 day (the clocks move 30 minutes on 2024-10-06)
    Library returns
    Asia/Kolkata host: 2024-10-06T02:15:00+10:30, Europe/London host: 2024-10-06T02:15:00+10:30, Australia/Sydney host: 2024-10-06T03:15:00+10:30, America/Santiago host: 2024-10-06T02:15:00+10:30
    Temporal returns
    2024-10-06T02:45:00+11:00[Australia/Lord_Howe]
  • M6 Start of a day whose midnight does not exist

    Input
    2024-09-08T12:00:00-03:00[America/Santiago], start of day (the clocks skip from 00:00 to 01:00)
    Library returns
    Asia/Kolkata host: 2024-09-08T00:00:00-04:00, Europe/London host: 2024-09-08T00:00:00-04:00, Australia/Sydney host: 2024-09-08T00:00:00-04:00, America/Santiago host: 2024-09-08T01:00:00-03:00
    Temporal returns
    2024-09-08T01:00:00-03:00[America/Santiago]
  • M8 Whole months between January 31 and February 29

    Input
    2024-01-31 until 2024-02-29
    Library returns
    1
    Temporal returns
    0
  • M9 Parse a date whose year has one digit

    Input
    "2-12-12" read as an ISO 8601 date
    Library returns
    2012-02-12
    Temporal returns
    rejected
  • M9b Parse a date that is not on the calendar

    Input
    "2024-02-30"
    Library returns
    2024-03-01
    Temporal returns
    rejected
  • M10 Read a string with a bracketed time zone

    Input
    2024-03-31T03:30:00+02:00[Europe/Berlin]
    Library returns
    rejected
    Temporal returns
    2024-03-31T01:30:00Z
  • M10c Read a string with a calendar annotation

    Input
    2024-03-31T03:30:00+02:00[Europe/Berlin][u-ca=japanese]
    Library returns
    rejected
    Temporal returns
    accepted
  • M14 Offset written for a UTC instant

    Input
    2024-03-31T01:30:00Z, written back as ISO 8601 with each library's default writer
    Library returns
    Asia/Kolkata host: 2024-03-31T07:00:00+05:30, Europe/London host: 2024-03-31T02:30:00+01:00, Australia/Sydney host: 2024-03-31T12:30:00+11:00, America/Santiago host: 2024-03-30T22:30:00-03:00
    Temporal returns
    2024-03-31T01:30:00Z
Day.jsGMTNote
.quarter() (quarterOfYear)
getQuarterForDate@northguild/gmt/plain/calculate
.month(1)
setDate@northguild/gmt/plain/calculate
month() counts from 0; GMT counts from 1.
.dayOfYear() (dayOfYear)
getDayOfYear@northguild/gmt/plain/calculate
.utcOffset()
getZonedOffsetAs@northguild/gmt/zoned/parse
Pass the unit minutes.

Code examples: MIT-0. Packages: MIT. Third-party data and components: their own licences, credited where they appear. Everything else:© 2026 NorthGuild, all rights reserved.