Skip to content

Migrate from Moment.js to Temporal with GMT

Checked against Moment.js 2.31.0 and moment-timezone 0.6.5 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.

Moment.jsGMTNote
moment(s, moment.ISO_8601, true)
isValidDate@northguild/gmt/plain/validate
isValidDateTime@northguild/gmt/plain/validate
isValidZonedDateTime@northguild/gmt/zoned/validate
The string is the value; check it with a validator. Strict ISO mode rejects a string with a [zone]. Measured in M10.
moment(s, "DD/MM/YYYY", true)
parseDateWithPattern@northguild/gmt/plain/parse
Rewrite the tokens to dd/MM/yyyy. Measured in M9d.
moment(s, "YYYY MMM", locale)
parseYearMonthWithPattern@northguild/gmt/plain/parse
Rewrite the tokens to yyyy MMM. The result is YYYY-MM, with no day.
.isValid()
isValidDate@northguild/gmt/plain/validate
.format("LL")
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.
moment(), moment.tz(z)
getUtcNow@northguild/gmt/utc/get
getZonedNow@northguild/gmt/zoned/get
.clone()noneNot needed: a string cannot change.
.add(1, "day")
addDate@northguild/gmt/plain/calculate
addZoned@northguild/gmt/zoned/calculate
Moment changes the object and returns it; GMT returns a new string. The Berlin gap result is the same. 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, "days")
diffDate@northguild/gmt/plain/calculate
The arguments are in the other order: earlier first.
b.diff(a, "months")
diffDate@northguild/gmt/plain/calculate
From 2024-01-31 to 2024-02-29 Moment counts 1 month and GMT counts 0. Measured in M8.
.startOf("month")
startOfDate@northguild/gmt/plain/calculate
.endOf("month")
endOfDate@northguild/gmt/plain/calculate
moment.tz(s, z).startOf("day")
startOfZoned@northguild/gmt/zoned/calculate
The Santiago result is the same. Measured in M6.
.isBefore(b), .isAfter(b)
isBeforeDate@northguild/gmt/plain/compare
isAfterDate@northguild/gmt/plain/compare
isBeforeZoned@northguild/gmt/zoned/compare
.isSame(b)
areDatesEqual@northguild/gmt/plain/compare
areUtcEqual@northguild/gmt/utc/compare
Measured in M3b.
.isSame(b, "day")
areDatesEqualBy@northguild/gmt/plain/compare
areZonedEqualBy@northguild/gmt/zoned/compare
.isBetween(a, b)
isBetweenDate@northguild/gmt/plain/compare
Moment excludes both ends by default; pass { inclusiveStart: false, inclusiveEnd: false }.
moment.min(…), moment.max(…)
minDate@northguild/gmt/plain/calculate
maxDate@northguild/gmt/plain/calculate
.daysInMonth(), .isLeapYear()
getDaysInMonth@northguild/gmt/plain/calculate
getDaysInYearMonth@northguild/gmt/plain/calculate
isLeapYear@northguild/gmt/plain/validate
.isoWeek(), .isoWeekYear(), .isoWeeksInYear()
getIsoWeekDate@northguild/gmt/calendar/calculate
getWeeksInYear@northguild/gmt/plain/calculate
.week() is a locale week. Measured in M12.
moment.tz(local, z), .tz(z)
convertPlainDateTimeToZoned@northguild/gmt/zoned/convert
convertZonedToZoned@northguild/gmt/zoned/convert
Moment has no disambiguation option; GMT takes disambiguation. Measured in M4, M4b, M16.
.fromNow(), .calendar()
formatRelativeZoned@northguild/gmt/zoned/format
formatCalendar@northguild/gmt/plain/format
moment.duration(s).humanize()
parseDuration@northguild/gmt/duration/parse
formatDuration@northguild/gmt/duration/format
moment.unix(sec), .unix()
convertUnixToUtc@northguild/gmt/unix/convert
convertUtcToUnix@northguild/gmt/utc/convert
Pass { epochUnit: "seconds" }.
.isDST(), .utcOffset(), moment.tz.zone(z)
isInDaylightSaving@northguild/gmt/zoned/compare
getZonedOffsetAs@northguild/gmt/zoned/parse
isValidTimeZone@northguild/gmt/zoned/validate
  • Moment objects are mutable: a.add(1, "day") changes a and returns it. GMT returns a new string and never changes its input.
  • 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 [].
  • Time zones come from the companion package moment-timezone.
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.

  • M8 Whole months between January 31 and February 29

    Input
    2024-01-31 until 2024-02-29
    Library returns
    1
    Temporal returns
    0
  • 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
Moment.jsGMTNote
.quarter()
getQuarterForDate@northguild/gmt/plain/calculate
.month(1)
setDate@northguild/gmt/plain/calculate
month() counts from 0; GMT counts from 1.
.dayOfYear()
getDayOfYear@northguild/gmt/plain/calculate

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.