Skip to content

tweak(database): replace moment-timezone with date-fns so browser bundles don't ship the timezone database - #6900

Open
jaskfla wants to merge 1 commit into
devfrom
database-drop-moment
Open

jaskfla wants to merge 1 commit into
devfrom
database-drop-moment

Conversation

@jaskfla

@jaskfla jaskfla commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Summary

Part 2 of the DataTrak startup-JS series. Fully independent of the other PRs.

@tupaia/database's browser entry pulls in every model, so moment-timezone (and its ~800 KB timezone database) shipped to every DataTrak user. There were three import paths, all now replaced with the date-fns/date-fns-tz equivalents that are already dependencies:

  • SurveyResponse/saveToDatabase.jsmomentTimezone(value).tz(tz).format() → the existing formatDateInTimezone(value, tz) helper from @tupaia/utils, whose default format produces byte-identical output (verified below).
  • OneTimeLogin.jsmoment().subtract(1, 'h').isAfter(...)isAfter(subHours(new Date(), 1), ...).
  • FeedItem.jsmoment(...).format('Y-MM-DD HH:mm:ss.SSSZZ')format(..., 'yyyy-MM-dd HH:mm:ss.SSSxx').
  • tsutils/datetime.tsgetTimezoneNameFromTimestamp was itself implemented with momentTimezone.tz.names(); reimplemented with Intl.supportedValuesOf('timeZone') + getTimezoneOffset from date-fns-tz. Same contract (first zone name whose current offset matches the timestamp's offset); the zone list source changes from moment's tzdb to the runtime's ICU data, so the exact name picked can differ in edge cases, but any matching name was always acceptable here.
  • utils/addExportDateAndOriginInExcelExportData.js — the last moment-timezone import reachable from the @tupaia/utils barrel; converted to format/formatInTimeZone.

moment-timezone is removed from the database, utils and tsutils dependency lists (plain moment remains, it's still used elsewhere).

This is the one PR in the series that changes server behaviour toosaveToDatabase.js is on the central-server survey response write path.

Output equivalence (old vs new, byte-for-byte)

momentTimezone(ts).tz(tz).format()  ==  formatDateInTimezone(ts, tz)   for +13:00, Z/UTC, +05:30, -04:00
moment ZZ ('+1300')                 ==  date-fns xx ('+1300')
moment 'Do MMM YYYY' ('31st Jul')   ==  date-fns 'do MMM yyyy'
moment 'DD/MM/YY'                   ==  date-fns 'dd/MM/yy'

Measured effect on packages/datatrak-web/dist (raw, pre-gzip)

The 846 KB momentTimezone chunk is gone entirely; the entry chunk is marginally smaller (8,402 → 8,368 KB). About −880 KB.

Test plan

  • yarn workspace @tupaia/tsutils test (includes the getTimezoneNameFromTimestamp test) — 17 passed
  • yarn workspace @tupaia/utils test — 512 passed
  • yarn workspace @tupaia/database test — could not complete locally (dev RDS test database is currently broken: table entity_parent_child_relation missing); needs CI
  • central-server survey response tests in CI

@jaskfla
jaskfla force-pushed the database-drop-moment branch from dbcedc2 to 87cfef1 Compare August 26, 2026 00:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant