I am proposing a core library which wraps Intl.DateTimeFormat.
Some things that client-side code wants to do with dates are very specific to MediaWiki:
- Show a date/time in the user's preferred language, respecting uselang
- Respect the user's date formatting preference
- Adjust a date/time for the user's preferred timezone
We used to think that a port of a large amount of PHP code would be required to achieve this, but now with the availability of Intl, it would seem that these things can be done more cheaply.
Similar tasks:
- T21992: Support client-side date/time formatting for user's timezone, language, and preferred format (JavaScript): pretty much identical except very old and with questions instead of answers.
- T146798: Replace Moment.js in core with mediawiki.DateFormatter, JavaScript Temporal and Intl: old, predating Intl. Unhelpful title, I just want to write a library.
- T166625: OOUI aspect
- T342237: Use Intl instead of moment: aimed specifically at GrowthExperiments
- T323193: Pitfalls of client-side timezone user option parsing
Use case review
- Combined date/time formatting
- Special:Block Codex table display T388048
- CampaignEvents
- Date-only, time-only formatting
- CampaignEvents GetFormattedTimeHandler
- Short date formatting
- GrowthExperiments CScoreCards
- GrowthExperiments RecentActivity
- ISO-8601 formatter with timezone awareness
- Codex Special:Block expiration time control (datetime-local)
- MW 14-char formatter
- DiscussionTools ThreadItem
- CampaignEvents TimeZoneConverter
- Range formatting
- GrowthExperiments CScoreCards
- Duration formatting
- moment.duration() callers e.g. UploadWizard
- MobileFrontend time.js
- Core BlockLog.vue
Localisation scheme
- Locale: Intl supports a fallback array. We can pass the MW language code fallback array to it.
- Date formatting: MW has $dateFormats in Messages*.php. Add by analogy $jsDateFormats containing an array to pass to the Intl.DateTimeFormat() constructor.
- Supply only user language configuration. No language code parameters.
- Time zones: MW server has either IANA name or numeric offset, closely matching the JS data model. Try to use the name; if the client doesn't have it, fall back to numeric offset.
- Duration formatting: Intl.DurationFormat is "newly available", would need a fallback. Fallback would need a separate data bundle. Probably a separate module and task.
Synopsis
I reviewed Moment and its designated successors, looking at their API style. A lot of what they do is about managing complexity, but what we need is pretty simple. We don't need many options, because the point of it is to provide policy. So I'm suggesting a mostly functional interface with native Date objects as inputs.
The function names should be unambiguous so that they can be destructured into the local scope.
The following functions would all be implicitly localised in the user's language and use the user's timezone:
const DateFormatter = require( 'mediawiki.DateFormatter' ); const date = new Date(); DateFormatter.formatTimeAndDate( date ); // => 19:27, 18 March 2025 DateFormatter.formatTime( date ); // => 19:27 DateFormatter.formatDate( date ); // => 18 March 2025 DateFormatter.formatPrettyDate( date ); // => 18 March DateFormatter.formatIso( date ) // => 2025-03-18T19:27:58+11:00 DateFormatter.formatUnqualifiedIso( date ) // => 2025-03-18T19:27:58 const date2 = new Date( +date + 60 * 60 * 1000 ); DateFormatter.formatTimeAndDateRange( date, date2 ); // => 19:27–20:27, 18 March 2025
If something needs more options than that, then we could have factory methods providing a customised instance:
const utcFormatter = DateFormatter.forUtc(); utcFormatter.formatTime( date ); // => 08:27
MediaWiki 14-char timestamps are an annoying special case since they are conventionally in UTC. So they would have to be accessed with DateFormatter.forUtc().formatMw( date ).