Bug 1428172 - Align mozIntl with Intl when working with constructors. r=nalexander
authorZibi Braniecki <zbraniecki@mozilla.com>
Thu, 04 Jan 2018 13:01:43 -0800
changeset 397886 94788650b26b7ca42d839a5989266e522837711a
parent 397885 e4bba88811c07450019d179338af382066be3ce2
child 397887 5c67e70c3a3e4f654d11c86c1b68ed8c4e2de48e
push id33193
push usertoros@mozilla.com
push dateFri, 05 Jan 2018 09:57:05 +0000
treeherdermozilla-central@df1519b33fe0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnalexander
bugs1428172
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1428172 - Align mozIntl with Intl when working with constructors. r=nalexander MozReview-Commit-ID: 5jGk1jXKkay
browser/base/content/content.js
browser/base/content/pageinfo/pageInfo.js
browser/base/content/test/about/browser_aboutCertError.js
browser/components/feeds/FeedWriter.js
browser/components/places/content/places.js
browser/components/places/content/treeView.js
browser/components/places/tests/chrome/test_treeview_date.xul
browser/components/preferences/cookies.js
toolkit/components/mozintl/mozIMozIntl.idl
toolkit/components/mozintl/mozIntl.js
toolkit/components/mozintl/test/test_mozintl.js
toolkit/components/passwordmgr/LoginManagerContent.jsm
toolkit/components/passwordmgr/LoginManagerContextMenu.jsm
toolkit/components/passwordmgr/content/passwordManager.js
toolkit/components/passwordmgr/test/mochitest/test_password_field_autocomplete.html
toolkit/components/passwordmgr/test/unit/test_context_menu.js
toolkit/components/passwordmgr/test/unit/test_user_autocomplete_result.js
toolkit/content/aboutTelemetry.js
toolkit/crashreporter/content/crashes.js
toolkit/mozapps/downloads/DownloadUtils.jsm
toolkit/mozapps/downloads/tests/unit/test_DownloadUtils.js
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -309,17 +309,17 @@ var AboutNetAndCertErrorListener = {
         let now = Date.now();
         let certRange = this._getCertValidityRange();
 
         let approximateDate = now - difference * 1000;
         // If the difference is more than a day, we last fetched the date in the last 5 days,
         // and adjusting the date per the interval would make the cert valid, warn the user:
         if (Math.abs(difference) > 60 * 60 * 24 && (now - lastFetched) <= 60 * 60 * 24 * 5 &&
             certRange.notBefore < approximateDate && certRange.notAfter > approximateDate) {
-          let formatter = Services.intl.createDateTimeFormat(undefined, {
+          let formatter = new Services.intl.DateTimeFormat(undefined, {
             dateStyle: "short"
           });
           let systemDate = formatter.format(new Date());
           // negative difference means local time is behind server time
           approximateDate = formatter.format(new Date(approximateDate));
 
           content.document.getElementById("wrongSystemTime_URL")
             .textContent = content.document.location.hostname;
@@ -345,17 +345,17 @@ var AboutNetAndCertErrorListener = {
           let buildDate = new Date(year, month, day);
           let systemDate = new Date();
 
           // We don't check the notBefore of the cert with the build date,
           // as it is of course almost certain that it is now later than the build date,
           // so we shouldn't exclude the possibility that the cert has become valid
           // since the build date.
           if (buildDate > systemDate && new Date(certRange.notAfter) > buildDate) {
-            let formatter = Services.intl.createDateTimeFormat(undefined, {
+            let formatter = new Services.intl.DateTimeFormat(undefined, {
               dateStyle: "short"
             });
 
             content.document.getElementById("wrongSystemTimeWithoutReference_URL")
               .textContent = content.document.location.hostname;
             content.document.getElementById("wrongSystemTimeWithoutReference_systemDate")
               .textContent = formatter.format(systemDate);
 
--- a/browser/base/content/pageinfo/pageInfo.js
+++ b/browser/base/content/pageinfo/pageInfo.js
@@ -1011,17 +1011,17 @@ function formatNumber(number) {
   return (+number).toLocaleString(); // coerce number to a numeric value before calling toLocaleString()
 }
 
 function formatDate(datestr, unknown) {
   var date = new Date(datestr);
   if (!date.valueOf())
     return unknown;
 
-  const dateTimeFormatter = Services.intl.createDateTimeFormat(undefined, {
+  const dateTimeFormatter = new Services.intl.DateTimeFormat(undefined, {
     dateStyle: "long", timeStyle: "long"
   });
   return dateTimeFormatter.format(date);
 }
 
 function doCopy() {
   if (!gClipboardHelper)
     return;
--- a/browser/base/content/test/about/browser_aboutCertError.js
+++ b/browser/base/content/test/about/browser_aboutCertError.js
@@ -146,17 +146,17 @@ add_task(async function checkWrongSystem
         text: div.textContent,
         systemDate: systemDateDiv.textContent,
         actualDate: actualDateDiv.textContent,
         learnMoreLink: learnMoreLink.href
       };
     });
   }
 
-  let formatter = Services.intl.createDateTimeFormat(undefined, {
+  let formatter = new Services.intl.DateTimeFormat(undefined, {
     dateStyle: "short"
   });
 
   // pretend we have a positively skewed (ahead) system time
   let serverDate = new Date("2015/10/27");
   let serverDateFmt = formatter.format(serverDate);
   let localDateFmt = formatter.format(new Date());
 
--- a/browser/components/feeds/FeedWriter.js
+++ b/browser/components/feeds/FeedWriter.js
@@ -187,17 +187,17 @@ FeedWriter.prototype = {
 
   __dateFormatter: null,
   get _dateFormatter() {
     if (!this.__dateFormatter) {
       const dtOptions = {
         timeStyle: "short",
         dateStyle: "long"
       };
-      this.__dateFormatter = Services.intl.createDateTimeFormat(undefined, dtOptions);
+      this.__dateFormatter = new Services.intl.DateTimeFormat(undefined, dtOptions);
     }
     return this.__dateFormatter;
   },
 
   /**
    * Returns the feed type.
    */
   __feedType: null,
--- a/browser/components/places/content/places.js
+++ b/browser/components/places/content/places.js
@@ -408,17 +408,17 @@ var PlacesOrganizer = {
    * Populates the restore menu with the dates of the backups available.
    */
   populateRestoreMenu: function PO_populateRestoreMenu() {
     let restorePopup = document.getElementById("fileRestorePopup");
 
     const dtOptions = {
       dateStyle: "long"
     };
-    let dateFormatter = Services.intl.createDateTimeFormat(undefined, dtOptions);
+    let dateFormatter = new Services.intl.DateTimeFormat(undefined, dtOptions);
 
     // Remove existing menu items.  Last item is the restoreFromFile item.
     while (restorePopup.childNodes.length > 1)
       restorePopup.firstChild.remove();
 
     (async function() {
       let backupFiles = await PlacesBackups.getBackupFiles();
       if (backupFiles.length == 0)
--- a/browser/components/places/content/treeView.js
+++ b/browser/components/places/content/treeView.js
@@ -551,29 +551,29 @@ PlacesTreeView.prototype = {
   },
 
   // We use a different formatter for times within the current day,
   // so we cache both a "today" formatter and a general date formatter.
   __todayFormatter: null,
   get _todayFormatter() {
     if (!this.__todayFormatter) {
       const dtOptions = { timeStyle: "short" };
-      this.__todayFormatter = Services.intl.createDateTimeFormat(undefined, dtOptions);
+      this.__todayFormatter = new Services.intl.DateTimeFormat(undefined, dtOptions);
     }
     return this.__todayFormatter;
   },
 
   __dateFormatter: null,
   get _dateFormatter() {
     if (!this.__dateFormatter) {
       const dtOptions = {
         dateStyle: "short",
         timeStyle: "short"
       };
-      this.__dateFormatter = Services.intl.createDateTimeFormat(undefined, dtOptions);
+      this.__dateFormatter = new Services.intl.DateTimeFormat(undefined, dtOptions);
     }
     return this.__dateFormatter;
   },
 
   COLUMN_TYPE_UNKNOWN: 0,
   COLUMN_TYPE_TITLE: 1,
   COLUMN_TYPE_URI: 2,
   COLUMN_TYPE_DATE: 3,
--- a/browser/components/places/tests/chrome/test_treeview_date.xul
+++ b/browser/components/places/tests/chrome/test_treeview_date.xul
@@ -133,17 +133,17 @@
                 if (node.uri == "http://at.midnight.com/" ||
                     node.uri == "http://after.midnight.com/") {
                   dtOptions.dateStyle = undefined;
                 } else if (node.uri != "http://before.midnight.com/") {
                   // Avoid to test spurious uris, due to how the test works
                   // a redirecting uri could be put in the tree while we test.
                   break;
                 }
-                let timeStr = Services.intl.createDateTimeFormat(undefined, dtOptions).format(timeObj);
+                let timeStr = new Services.intl.DateTimeFormat(undefined, dtOptions).format(timeObj);
 
                 is(text, timeStr, "Date format is correct");
                 break;
               case "visitCount":
                 is(text, 1, "Visit count is correct");
                 break;
             }
           }
--- a/browser/components/preferences/cookies.js
+++ b/browser/components/preferences/cookies.js
@@ -486,17 +486,17 @@ var gCookiesWindow = {
         break;
     }
     this._view._rowCount = hostCount.value;
   },
 
   formatExpiresString(aExpires) {
     if (aExpires) {
       var date = new Date(1000 * aExpires);
-      const dateTimeFormatter = Services.intl.createDateTimeFormat(undefined, {
+      const dateTimeFormatter = new Services.intl.DateTimeFormat(undefined, {
         dateStyle: "long", timeStyle: "long"
       });
       return dateTimeFormatter.format(date);
     }
     return this._bundle.getString("expireAtEndOfSession");
   },
 
   _getUserContextString(aUserContextId) {
--- a/toolkit/components/mozintl/mozIMozIntl.idl
+++ b/toolkit/components/mozintl/mozIMozIntl.idl
@@ -36,10 +36,10 @@
  */
 [scriptable, uuid(7f63279a-1a29-4ae6-9e7a-dc9684a23530)]
 interface mozIMozIntl : nsISupports
 {
   jsval getCalendarInfo([optional] in jsval locales);
   jsval getDisplayNames([optional] in jsval locales, [optional] in jsval options);
   jsval getLocaleInfo([optional] in jsval locales);
 
-  jsval createDateTimeFormat([optional] in jsval locales, [optional] in jsval options);
+  readonly attribute jsval DateTimeFormat;
 };
--- a/toolkit/components/mozintl/mozIntl.js
+++ b/toolkit/components/mozintl/mozIntl.js
@@ -64,37 +64,41 @@ class MozIntl {
   getLocaleInfo(locales, ...args) {
     if (!this._cache.hasOwnProperty("getLocaleInfo")) {
       mozIntlHelper.addGetLocaleInfo(this._cache);
     }
 
     return this._cache.getLocaleInfo(getLocales(locales), ...args);
   }
 
-  createDateTimeFormat(locales, options, ...args) {
+  get DateTimeFormat() {
     if (!this._cache.hasOwnProperty("DateTimeFormat")) {
       mozIntlHelper.addDateTimeFormatConstructor(this._cache);
     }
 
-    let resolvedLocales =
-      this._cache.DateTimeFormat.supportedLocalesOf(getLocales(locales));
+    let DateTimeFormat = this._cache.DateTimeFormat;
 
-    if (options) {
-      if (options.dateStyle || options.timeStyle) {
-        options.pattern = osPrefs.getDateTimePattern(
-          getDateTimePatternStyle(options.dateStyle),
-          getDateTimePatternStyle(options.timeStyle),
-          resolvedLocales[0]);
-      } else {
-        // make sure that user doesn't pass a pattern explicitly
-        options.pattern = undefined;
+    class MozDateTimeFormat extends this._cache.DateTimeFormat {
+      constructor(locales, options, ...args) {
+        let resolvedLocales = DateTimeFormat.supportedLocalesOf(getLocales(locales));
+        if (options) {
+          if (options.dateStyle || options.timeStyle) {
+            options.pattern = osPrefs.getDateTimePattern(
+              getDateTimePatternStyle(options.dateStyle),
+              getDateTimePatternStyle(options.timeStyle),
+              resolvedLocales[0]);
+          } else {
+            // make sure that user doesn't pass a pattern explicitly
+            options.pattern = undefined;
+          }
+        }
+        super(resolvedLocales, options, ...args);
       }
     }
-
-    return new this._cache.DateTimeFormat(resolvedLocales, options, ...args);
+    return MozDateTimeFormat;
   }
 }
 
 MozIntl.prototype.classID = Components.ID("{35ec195a-e8d0-4300-83af-c8a2cc84b4a3}");
 MozIntl.prototype.QueryInterface = XPCOMUtils.generateQI([Ci.mozIMozIntl, Ci.nsISupports]);
 
 var components = [MozIntl];
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
--- a/toolkit/components/mozintl/test/test_mozintl.js
+++ b/toolkit/components/mozintl/test/test_mozintl.js
@@ -1,26 +1,48 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 function run_test() {
   test_methods_presence();
   test_methods_calling();
+  test_constructors();
 
   ok(true);
 }
 
 function test_methods_presence() {
   equal(Services.intl.getCalendarInfo instanceof Function, true);
   equal(Services.intl.getDisplayNames instanceof Function, true);
   equal(Services.intl.getLocaleInfo instanceof Function, true);
-  equal(Services.intl.createDateTimeFormat instanceof Function, true);
+  equal(Services.intl.getLocaleInfo instanceof Object, true);
 }
 
 function test_methods_calling() {
   Services.intl.getCalendarInfo("pl");
   Services.intl.getDisplayNames("ar");
   Services.intl.getLocaleInfo("de");
-  Services.intl.createDateTimeFormat("fr");
+  new Services.intl.DateTimeFormat("fr");
   ok(true);
 }
+
+function test_constructors() {
+  let dtf = new Intl.DateTimeFormat();
+  let dtf2 = new Services.intl.DateTimeFormat();
+
+  equal(typeof dtf, typeof dtf2);
+
+  Assert.throws(() => {
+    // This is an observable difference between Intl and mozIntl.
+    //
+    // Old ECMA402 APIs (edition 1 and 2) allowed for constructors to be called
+    // as functions.
+    // Starting from ed.3 all new constructors are throwing when called without |new|.
+    //
+    // All MozIntl APIs do not implement the legacy behavior and throw
+    // when called without |new|.
+    //
+    // For more information see https://github.com/tc39/ecma402/pull/84 .
+    Services.intl.DateTimeFormat();
+  }, /class constructors must be invoked with |new|/);
+}
--- a/toolkit/components/passwordmgr/LoginManagerContent.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm
@@ -1443,17 +1443,17 @@ function UserAutoCompleteResult(aSearchS
   }
 
   this._showInsecureFieldWarning = (!isSecure && LoginHelper.showInsecureFieldWarning) ? 1 : 0;
   this.searchString = aSearchString;
   this.logins = matchingLogins.sort(loginSort);
   this.matchCount = matchingLogins.length + this._showInsecureFieldWarning;
   this._messageManager = messageManager;
   this._stringBundle = Services.strings.createBundle("chrome://passwordmgr/locale/passwordmgr.properties");
-  this._dateAndTimeFormatter = Services.intl.createDateTimeFormat(undefined, { dateStyle: "medium" });
+  this._dateAndTimeFormatter = new Services.intl.DateTimeFormat(undefined, { dateStyle: "medium" });
 
   this._isPasswordField = isPasswordField;
 
   this._duplicateUsernames = findDuplicates(matchingLogins);
 
   if (this.matchCount > 0) {
     this.searchResult = Ci.nsIAutoCompleteResult.RESULT_SUCCESS;
     this.defaultIndex = 0;
--- a/toolkit/components/passwordmgr/LoginManagerContextMenu.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerContextMenu.jsm
@@ -186,12 +186,12 @@ var LoginManagerContextMenu = {
 };
 
 XPCOMUtils.defineLazyGetter(LoginManagerContextMenu, "_stringBundle", function() {
   return Services.strings.
          createBundle("chrome://passwordmgr/locale/passwordmgr.properties");
 });
 
 XPCOMUtils.defineLazyGetter(LoginManagerContextMenu, "dateAndTimeFormatter", function() {
-  return Services.intl.createDateTimeFormat(undefined, {
+  return new Services.intl.DateTimeFormat(undefined, {
     dateStyle: "medium"
   });
 });
--- a/toolkit/components/passwordmgr/content/passwordManager.js
+++ b/toolkit/components/passwordmgr/content/passwordManager.js
@@ -55,19 +55,19 @@ let signonReloadDisplay = {
           break;
       }
       Services.obs.notifyObservers(null, "passwordmgr-dialog-updated");
     }
   }
 };
 
 // Formatter for localization.
-let dateFormatter = Services.intl.createDateTimeFormat(undefined,
+let dateFormatter = new Services.intl.DateTimeFormat(undefined,
                       { dateStyle: "medium" });
-let dateAndTimeFormatter = Services.intl.createDateTimeFormat(undefined,
+let dateAndTimeFormatter = new Services.intl.DateTimeFormat(undefined,
                              { dateStyle: "medium",
                                timeStyle: "short" });
 
 function Startup() {
   // be prepared to reload the display if anything changes
   Services.obs.addObserver(signonReloadDisplay, "passwordmgr-storage-changed");
 
   signonsTree = document.getElementById("signonsTree");
--- a/toolkit/components/passwordmgr/test/mochitest/test_password_field_autocomplete.html
+++ b/toolkit/components/passwordmgr/test/mochitest/test_password_field_autocomplete.html
@@ -129,17 +129,17 @@ async function reinitializeForm(index) {
   uname = $_(index, "uname");
   pword = $_(index, "pword");
   uname.value = "";
   pword.value = "";
   pword.focus();
 }
 
 function generateDateString(date) {
-  let dateAndTimeFormatter = Services.intl.createDateTimeFormat(undefined,
+  let dateAndTimeFormatter = new Services.intl.DateTimeFormat(undefined,
                              { dateStyle: "medium" });
   return dateAndTimeFormatter.format(date);
 }
 
 const DATE_NOW_STRING = generateDateString(new Date());
 
 // Check for expected username/password in form.
 function checkACFormPasswordField(expectedPassword) {
--- a/toolkit/components/passwordmgr/test/unit/test_context_menu.js
+++ b/toolkit/components/passwordmgr/test/unit/test_context_menu.js
@@ -97,17 +97,17 @@ function checkLoginItems(logins, items) 
         duplicates.add(login.username);
       }
       seen.add(login.username);
     }
     return duplicates;
   }
   let duplicates = findDuplicates(logins);
 
-  let dateAndTimeFormatter = Services.intl.createDateTimeFormat(undefined,
+  let dateAndTimeFormatter = new Services.intl.DateTimeFormat(undefined,
                              { dateStyle: "medium" });
   for (let login of logins) {
     if (login.username && !duplicates.has(login.username)) {
       // If login is not duplicate and we can't find an item for it, fail.
       if (!items.find(item => item.label == login.username)) {
         return false;
       }
       continue;
--- a/toolkit/components/passwordmgr/test/unit/test_user_autocomplete_result.js
+++ b/toolkit/components/passwordmgr/test/unit/test_user_autocomplete_result.js
@@ -19,17 +19,17 @@ matchingLogins.push(new nsLoginInfo("htt
 
 matchingLogins.push(new nsLoginInfo("http://mochi.test:8888", "http://autocomplete:8888", null,
                                     "testuser3", "testpass3", "uname", "pword"));
 
 matchingLogins.push(new nsLoginInfo("http://mochi.test:8888", "http://autocomplete:8888", null,
                                     "zzzuser4", "zzzpass4", "uname", "pword"));
 
 let meta = matchingLogins[0].QueryInterface(Ci.nsILoginMetaInfo);
-let dateAndTimeFormatter = Services.intl.createDateTimeFormat(undefined,
+let dateAndTimeFormatter = new Services.intl.DateTimeFormat(undefined,
                             { dateStyle: "medium" });
 let time = dateAndTimeFormatter.format(new Date(meta.timePasswordChanged));
 const LABEL_NO_USERNAME = "No username (" + time + ")";
 
 let expectedResults = [
   {
     insecureFieldWarningEnabled: true,
     insecureAutoFillFormsEnabled: true,
--- a/toolkit/content/aboutTelemetry.js
+++ b/toolkit/content/aboutTelemetry.js
@@ -419,17 +419,17 @@ var PingPicker = {
     const today = new Date();
     today.setHours(0, 0, 0, 0);
     const yesterday = new Date(today);
     yesterday.setDate(today.getDate() - 1);
 
     for (let p of this._archivedPings) {
       pingTypes.add(p.type);
       const pingDate = new Date(p.timestampCreated);
-      const datetimeText = Services.intl.createDateTimeFormat(undefined, {
+      const datetimeText = new Services.intl.DateTimeFormat(undefined, {
           dateStyle: "short",
           timeStyle: "medium"
         }).format(pingDate);
       const pingName = `${datetimeText}, ${p.type}`;
 
       let option = document.createElement("option");
       let content = document.createTextNode(pingName);
       option.appendChild(content);
--- a/toolkit/crashreporter/content/crashes.js
+++ b/toolkit/crashreporter/content/crashes.js
@@ -68,18 +68,18 @@ function populateReportList() {
     document.getElementById("reportList").style.display = "none";
     document.getElementById("noReports").style.display = "block";
     return;
   }
 
   var dateFormatter;
   var timeFormatter;
   try {
-    dateFormatter = Services.intl.createDateTimeFormat(undefined, { dateStyle: "short" });
-    timeFormatter = Services.intl.createDateTimeFormat(undefined, { timeStyle: "short" });
+    dateFormatter = new Services.intl.DateTimeFormat(undefined, { dateStyle: "short" });
+    timeFormatter = new Services.intl.DateTimeFormat(undefined, { timeStyle: "short" });
   } catch (e) {
     // XXX Fallback to be removed once bug 1215247 is complete
     // and the Intl API is available on all platforms.
     dateFormatter = {
       format(date) {
         return date.toLocaleDateString();
       }
     };
--- a/toolkit/mozapps/downloads/DownloadUtils.jsm
+++ b/toolkit/mozapps/downloads/DownloadUtils.jsm
@@ -344,17 +344,17 @@ this.DownloadUtils = {
     // Figure out when today begins
     let today = new Date(aNow.getFullYear(), aNow.getMonth(), aNow.getDate());
 
     let dateTimeCompact;
     let dateTimeFull;
 
     // Figure out if the time is from today, yesterday, this week, etc.
     if (aDate >= today) {
-      let dts = Services.intl.createDateTimeFormat(undefined, {
+      let dts = new Services.intl.DateTimeFormat(undefined, {
         timeStyle: "short"
       });
       dateTimeCompact = dts.format(aDate);
     } else if (today - aDate < (MS_PER_DAY)) {
       // After yesterday started, show yesterday
       dateTimeCompact = gBundle.GetStringFromName(gStr.yesterday);
     } else if (today - aDate < (6 * MS_PER_DAY)) {
       // After last week started, show day of week
@@ -364,17 +364,17 @@ this.DownloadUtils = {
       dateTimeCompact = aDate.toLocaleString(undefined, {
                           month: "long",
                           day: "numeric"
       });
     }
 
     const dtOptions = { dateStyle: "long", timeStyle: "short" };
     dateTimeFull =
-      Services.intl.createDateTimeFormat(undefined, dtOptions).format(aDate);
+      new Services.intl.DateTimeFormat(undefined, dtOptions).format(aDate);
 
     return [dateTimeCompact, dateTimeFull];
   },
 
   /**
    * Get the appropriate display host string for a URI string depending on if
    * the URI has an eTLD + 1, is an IP address, a local file, or other protocol
    *
--- a/toolkit/mozapps/downloads/tests/unit/test_DownloadUtils.js
+++ b/toolkit/mozapps/downloads/tests/unit/test_DownloadUtils.js
@@ -73,37 +73,37 @@ function testAllGetReadableDates() {
   const today_11_30     = new Date(2000, 11, 31, 11, 30, 15);
   const today_12_30     = new Date(2000, 11, 31, 12, 30, 15);
   const yesterday_11_30 = new Date(2000, 11, 30, 11, 30, 15);
   const yesterday_12_30 = new Date(2000, 11, 30, 12, 30, 15);
   const twodaysago      = new Date(2000, 11, 29, 11, 30, 15);
   const sixdaysago      = new Date(2000, 11, 25, 11, 30, 15);
   const sevendaysago    = new Date(2000, 11, 24, 11, 30, 15);
 
-  let cDtf = Services.intl.createDateTimeFormat;
+  let cDtf = Services.intl.DateTimeFormat;
 
   testGetReadableDates(today_11_30,
-                       cDtf(undefined, {timeStyle: "short"}).format(today_11_30));
+                       (new cDtf(undefined, {timeStyle: "short"})).format(today_11_30));
   testGetReadableDates(today_12_30,
-                       cDtf(undefined, {timeStyle: "short"}).format(today_12_30));
+                       (new cDtf(undefined, {timeStyle: "short"})).format(today_12_30));
 
   testGetReadableDates(yesterday_11_30, "Yesterday");
   testGetReadableDates(yesterday_12_30, "Yesterday");
   testGetReadableDates(twodaysago,
                        twodaysago.toLocaleDateString(undefined, { weekday: "long" }));
   testGetReadableDates(sixdaysago,
                        sixdaysago.toLocaleDateString(undefined, { weekday: "long" }));
   testGetReadableDates(sevendaysago,
                        sevendaysago.toLocaleDateString(undefined, { month: "long" }) + " " +
                        sevendaysago.getDate().toString().padStart(2, "0"));
 
   let [, dateTimeFull] = DownloadUtils.getReadableDates(today_11_30);
 
   const dtOptions = { dateStyle: "long", timeStyle: "short" };
-  Assert.equal(dateTimeFull, cDtf(undefined, dtOptions).format(today_11_30));
+  Assert.equal(dateTimeFull, (new cDtf(undefined, dtOptions)).format(today_11_30));
 }
 
 function run_test() {
   testConvertByteUnits(-1, "-1", "bytes");
   testConvertByteUnits(1, _("1"), "bytes");
   testConvertByteUnits(42, _("42"), "bytes");
   testConvertByteUnits(123, _("123"), "bytes");
   testConvertByteUnits(1024, _("1.0"), "KB");