Bug 1428172 - Align mozIntl with Intl when working with constructors. r?nalexander draft
authorZibi Braniecki <zbraniecki@mozilla.com>
Thu, 04 Jan 2018 13:01:43 -0800
changeset 716028 0cd7209afc30ff840234e7420b8a108fcb9a3d3c
parent 715917 b602b19745e33f26c196dc6fadb01ce9fa2b66a4
child 744929 3ba285b9b674cf1de9ee8621ec718ab7c2c0b688
push id94306
push userbmo:gandalf@aviary.pl
push dateFri, 05 Jan 2018 00:24:40 +0000
reviewersnalexander
bugs1428172
milestone59.0a1
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
@@ -1435,17 +1435,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");