aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>2025-04-07 14:10:31 +0000
committerGerrit Code Review <gerrit@wikimedia.org>2025-04-07 14:10:31 +0000
commit2133f2e9ff3a88ffb0e5b534187fd955c6370429 (patch)
tree8adbdb6ed392c9b690e3477b3f4ee3ae4a1cb209
parentd69b6214aded61fcc794367184e8b125067f6264 (diff)
parentbb9f7a62c807b4c186a22fc111de780ddc1de8a9 (diff)
downloadmediawikicore-2133f2e9ff3a88ffb0e5b534187fd955c6370429.tar.gz
mediawikicore-2133f2e9ff3a88ffb0e5b534187fd955c6370429.zip
Merge "DateFormatter: Fix exception if user date option is not available"
-rw-r--r--resources/src/mediawiki.DateFormatter/DateFormatter.js33
-rw-r--r--tests/qunit/resources/mediawiki.DateFormatter/DateFormatter.test.js62
2 files changed, 79 insertions, 16 deletions
diff --git a/resources/src/mediawiki.DateFormatter/DateFormatter.js b/resources/src/mediawiki.DateFormatter/DateFormatter.js
index 4281a1e0163c..f67ba0cca381 100644
--- a/resources/src/mediawiki.DateFormatter/DateFormatter.js
+++ b/resources/src/mediawiki.DateFormatter/DateFormatter.js
@@ -595,7 +595,7 @@ class DateFormatter {
* @return {string}
*/
formatInternal( style, type, date ) {
- const formatName = style ? `${ style } ${ type }` : type;
+ const formatName = this.makeValidFormatName( style, type );
const formatter = this.getIntlFormatInternal( formatName );
const pattern = this.formats[ formatName ].pattern;
if ( pattern ) {
@@ -614,6 +614,35 @@ class DateFormatter {
}
/**
+ * Validate a style/type and combine them into a single string, falling
+ * back to the default style if the user style is not available with the
+ * specified type.
+ *
+ * @internal
+ * @ignore
+ *
+ * @param {string|null} style
+ * @param {string} type
+ * @return {string}
+ */
+ makeValidFormatName( style, type ) {
+ if ( !style ) {
+ return type;
+ }
+ // Try the specified style, then the site default style, then "dmy", a
+ // final fallback which should always exist, because localised date
+ // format arrays are merged with English, which has "dmy".
+ for ( const tryStyle of [ style, config.defaultStyle, 'dmy' ] ) {
+ const name = `${ tryStyle } ${ type }`;
+ if ( name in this.formats ) {
+ return name;
+ }
+ }
+ // Perhaps an invalid type, or bad config?
+ throw new Error( `Unable to find a valid date format for "${ style } ${ type }"` );
+ }
+
+ /**
* Format a time/date range with a specified style
*
* @internal
@@ -626,7 +655,7 @@ class DateFormatter {
* @return {string}
*/
formatRangeInternal( style, type, date1, date2 ) {
- const formatName = style ? `${ style } ${ type }` : type;
+ const formatName = this.makeValidFormatName( style, type );
const formatter = this.getIntlFormatInternal( formatName );
const pattern = this.formats[ formatName ].rangePattern;
if ( pattern ) {
diff --git a/tests/qunit/resources/mediawiki.DateFormatter/DateFormatter.test.js b/tests/qunit/resources/mediawiki.DateFormatter/DateFormatter.test.js
index be6efbf412b6..a0cda3528b20 100644
--- a/tests/qunit/resources/mediawiki.DateFormatter/DateFormatter.test.js
+++ b/tests/qunit/resources/mediawiki.DateFormatter/DateFormatter.test.js
@@ -3,17 +3,19 @@ const midnightZulu = new Date( '2025-01-01T00:00:00Z' );
const oneZulu = new Date( '2025-01-01T01:00:00Z' );
const nextDay = new Date( '2025-01-02T00:00:00Z' );
-function fakeOptionsGet( key, fallback ) {
- const options = {
- timecorrection: 'Offset|60'
- };
- return key in options ? options[ key ] : fallback;
-}
-
QUnit.module( 'mediawiki.DateFormatter static functions', ( hooks ) => {
+ let userOptions;
+
+ function fakeOptionsGet( key, fallback ) {
+ return key in userOptions ? userOptions[ key ] : fallback;
+ }
hooks.beforeEach( function () {
+ userOptions = {
+ timecorrection: 'Offset|60'
+ };
this.sandbox.stub( mw.user.options, 'get', fakeOptionsGet );
+ DateFormatter.clearInstanceCache();
} );
QUnit.test( 'forUser', ( assert ) => {
@@ -41,13 +43,36 @@ QUnit.module( 'mediawiki.DateFormatter static functions', ( hooks ) => {
assert.strictEqual( instance.formatTime( midnightZulu ), '04:00' );
} );
- QUnit.test( 'formatTimeAndDate', ( assert ) => {
- const { formatTimeAndDate } = DateFormatter;
- assert.strictEqual(
- formatTimeAndDate( midnightZulu ),
- '01:00, 1 (january) 2025'
- );
- } );
+ const formatTimeAndDateCases = [
+ {
+ title: 'null',
+ dateOption: null,
+ expected: '01:00, 1 (january) 2025'
+ },
+ {
+ title: 'mdy',
+ dateOption: 'mdy',
+ expected: '01:00, (january) 1, 2025'
+ },
+ {
+ title: 'bad option',
+ dateOption: 'bad',
+ expected: '01:00, 1 (january) 2025'
+ }
+ ];
+
+ QUnit.test.each(
+ 'formatTimeAndDate',
+ formatTimeAndDateCases,
+ ( assert, { dateOption, expected } ) => {
+ userOptions.date = dateOption;
+ const { formatTimeAndDate } = DateFormatter;
+ assert.strictEqual(
+ formatTimeAndDate( midnightZulu ),
+ expected
+ );
+ }
+ );
QUnit.test( 'formatTime', ( assert ) => {
const { formatTime } = DateFormatter;
@@ -188,9 +213,18 @@ QUnit.module( 'mediawiki.DateFormatter static functions', ( hooks ) => {
} );
QUnit.module( 'mediawiki.DateFormatter instance methods', ( hooks ) => {
+ let userOptions;
+
+ function fakeOptionsGet( key, fallback ) {
+ userOptions = {
+ timecorrection: 'Offset|60'
+ };
+ return key in userOptions ? userOptions[ key ] : fallback;
+ }
hooks.beforeEach( function () {
this.sandbox.stub( mw.user.options, 'get', fakeOptionsGet );
+ DateFormatter.clearInstanceCache();
} );
function getInstance() {