Migrate from date-fns to Temporal with GMT
Migrate to Temporal with GMT explains the one change that applies to every call below: GMT takes strings in and gives strings out.
Call by call
Section titled “Call by call”| date-fns | GMT | Note |
|---|---|---|
parseISO(s) | isValidDate@northguild/isValidDateTime@northguild/isValidZonedDateTime@northguild/isValidUtc@northguild/ | The string is the value, so there is nothing to parse; check it with a validator. parseISO drops the offset before a [zone] and then reads the wall time as UTC (03:30Z). Temporal reads the basic format 20240212; GMT rejects it on purpose and follows the extended format of RFC 3339 §5.6. Measured in M9c, M10. |
parse(s, "dd/ | parseDateWithPattern@northguild/ | yyyy is four digits in GMT. date-fns reads 2-12-12 as year 2. Measured in M9d. |
parse(s, "yyyy MMMM", ref) | parseYearMonthWithPattern@northguild/ | A year and a month with no day, returned as YYYY-MM. |
isValid(d) | isValidDate@northguild/ | GMT rejects 2024-02-30 and basic format. Measured in M9b, M9c. |
format(d, "d MMMM yyyy") | formatDate@northguild/ | GMT has no token formatter; pass a locale and dateStyle. |
formatISO(d) | none | None for a GMT string, which is already ISO 8601. formatISO writes the host offset. Measured in M14. |
| The current time, from the built-in date object | getUtcNow@northguild/getZonedNow@northguild/ | |
startOfToday() | getToday@northguild/getZonedToday@northguild/ | |
addDays(d, n) | addDate@northguild/addZoned@northguild/ | date-fns works in the host zone, so a day is a calendar day of the host, and the result depends on the host zone. GMT takes the zone from the value. Measured in M1, M2. |
addMonths(d, n) | addDate@northguild/ | The day is clamped to the month length. { overflow: "reject" } returns "". Measured in M7. |
subDays(d, n), subMonths(d, n) | subtractDate@northguild/ | |
addHours(d, n) | addZoned@northguild/addUtc@northguild/ | Hours are exact time. |
differenceInCalendarDays(later, earlier) | diffDate@northguild/ | The arguments are in the other order: earlier first. |
differenceInMonths(later, earlier) | diffDate@northguild/ | From 2024-01-31 to 2024-02-29 date-fns counts 1 month and GMT counts 0. Measured in M8. |
intervalToDuration({ start, end }) | diffDate@northguild/ | Pass the units you want, for example ["years", "months", "days"]. |
startOfMonth(d) | startOfDate@northguild/ | |
endOfMonth(d) | endOfDate@northguild/ | |
startOfDay(d, { in: tz(z) }) | startOfZoned@northguild/ | The first instant of the day, which is not always 00:00. Measured in M6. |
isBefore(a, b), isAfter(a, b) | isBeforeDate@northguild/isAfterDate@northguild/isBeforeZoned@northguild/ | |
isEqual(a, b) | areDatesEqual@northguild/areUtcEqual@northguild/areZonedEqual@northguild/ | areZonedEqual follows ZonedDateTime.prototype.equals. Measured in M3b, M13b, M13c. |
isSameDay(a, b) | areDatesEqualBy@northguild/areZonedEqualBy@northguild/ | |
isWithinInterval(d, { start, end }) | isBetweenDate@northguild/ | Both ends are inclusive by default. |
areIntervalsOverlapping(a, b) | intervalsOverlapDate@northguild/ | |
min(ds), max(ds) | minDate@northguild/maxDate@northguild/ | |
getDaysInMonth(d), isLeapYear(d) | getDaysInMonth@northguild/getDaysInYearMonth@northguild/isLeapYear@northguild/ | |
getISOWeek(d), getISOWeekYear(d) | getIsoWeekDate@northguild/ | One call returns year, week and weekday. getWeek is a locale week. Measured in M12. |
getISOWeeksInYear(d) | getWeeksInYear@northguild/ | |
isWeekend(d), addBusinessDays(d, n), differenceInBusinessDays(a, b) | isWeekend@northguild/addBusinessDays@northguild/businessDaysBetween@northguild/ | date-fns fixes the weekend to Saturday and Sunday. isWeekend in GMT takes a locale. addBusinessDays takes an optional calendar and counts Monday to Friday without one. businessDaysBetween requires a calendar and reads the weekend from calendar.weekend. Measured in M15. |
formatDistance(d, base), formatRelative(d, base) | formatRelativeDate@northguild/formatRelativeZoned@northguild/ | The wording comes from Intl.RelativeTimeFormat. |
What changes
Section titled “What changes”- date-fns takes and returns
Dateobjects, orTZDatefrom@date-fns/tz. GMT takes and returns strings. getMonthcounts months from 0. GMT counts them from 1 to 12, as Temporal does.- The difference functions take the later date first, as in
differenceInCalendarDays(later, earlier).diffDatetakes the earlier date first. - Invalid input gives an
Invalid Date, andformatthrows aRangeError. GMT returns"",null,falseor[]instead of throwing.
import { diffDate } from "@northguild/gmt/plain/calculate";
diffDate("2024-03-01", "2024-03-15", "days"); // 14Basic-format dates
Section titled “Basic-format dates”parseISO reads 20240212, as Temporal does. GMT’s validators and parsers accept only the extended format, 2024-02-12, which is the format of RFC 3339 §5.6, so isValidDate("20240212") returns false. This is deliberate. Convert a basic-format string before you pass it on. The behaviour matrix shows the library’s result in case M9c.
Where date-fns differs from Temporal
Section titled “Where date-fns differs from Temporal”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
Asia/Kolkata host: 2024-03-31T03:30:00.000+02:00, Europe/London host: 2024-03-31T01:30:00.000+01:00, Australia/Sydney host: 2024-03-31T03:30:00.000+02:00, America/Santiago host: 2024-03-31T03:30:00.000+02:00- Temporal returns
2024-03-31T03:30:00+02:00[Europe/Berlin]
M3 Add one day into a repeated hour
- Input
- 2024-10-26T02:30:00+02:00[Europe/Berlin], plus 1 day (02:30 happens twice on 2024-10-27)
- Library returns
Asia/Kolkata host: 2024-10-27T02:30:00.000+02:00, Europe/London host: 2024-10-27T02:30:00.000+01:00, Australia/Sydney host: 2024-10-27T02:30:00.000+02:00, America/Santiago host: 2024-10-27T02:30:00.000+01:00- Temporal returns
2024-10-27T02:30:00+02:00[Europe/Berlin]
M4 Resolve a wall time that does not exist
- Input
- 2024-03-31T02:30:00 in Europe/Berlin (the clocks skip from 02:00 to 03:00)
- Library returns
Asia/Kolkata host: 2024-03-31T01:30:00.000+00:00, Europe/London host: 2024-03-31T00:30:00.000+00:00, Australia/Sydney host: 2024-03-31T01:30:00.000+00:00, America/Santiago host: 2024-03-31T01:30:00.000+00:00- Temporal returns
2024-03-31T01:30:00Z
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:45:00.000+11:00, Europe/London host: 2024-10-06T02:45:00.000+11:00, Australia/Sydney host: 2024-10-06T03:15:00.000+11:00, America/Santiago host: 2024-10-06T02:45:00.000+11:00- Temporal returns
2024-10-06T02:45:00+11:00[Australia/Lord_Howe]
M8 Whole months between January 31 and February 29
- Input
- 2024-01-31 until 2024-02-29
- Library returns
1- Temporal returns
0
M9d Read a year of one digit with a pattern
- Input
- "2-12-12" read with the pattern year-month-day
- Library returns
0002-12-12- Stated result
rejected
UTS #35 Date Format Patterns · date-fns/date-fns#942 · date-fns/date-fns#1569 · Matrix row
M10 Read a string with a bracketed time zone
- Input
- 2024-03-31T03:30:00+02:00[Europe/Berlin]
- Library returns
2024-03-31T03:30:00.000Z- 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
accepted, reads 2024-03-31T03:30:00Z- Temporal returns
accepted
M10d Read a string whose offset does not match its time zone
- Input
- 2022-07-08T00:14:07+01:00[Europe/Paris] (Paris is at +02:00 on that date)
- Library returns
2022-07-08T00:14:07.000Z- Temporal returns
rejected
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
Temporal.Instant.prototype.toString (8.3.11) · date-fns/date-fns#2151 · Matrix row
More calls
Section titled “More calls”| date-fns | GMT | Note |
|---|---|---|
getQuarter(d) | getQuarterForDate@northguild/ | |
set(d, { month: 1 }) | setDate@northguild/ | Months are 1 to 12 in GMT. |
fromUnixTime(sec) | convertUnixToUtc@northguild/ | Pass { epochUnit: "seconds" }. |
getUnixTime(d) | convertUtcToUnix@northguild/ | Pass { epochUnit: "seconds" }. |
eachDayOfInterval({ start, end }) | mapDatesInRange@northguild/ | The end date is included. |
getDayOfYear(d) | getDayOfYear@northguild/ | |
formatDuration(d) | formatDuration@northguild/ | |
new TZDate(…, z) | convertUtcToZoned@northguild/convertPlainDateTimeToZoned@northguild/ |
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.