tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

consistent-dates.js (13969B)


      1 // |reftest| skip-if(!this.hasOwnProperty("Temporal")||!this.hasOwnProperty("Intl"))
      2 
      3 // Ensure Intl.DateTimeFormat and Temporal return consistent year-month-day values
      4 // for reasonable dates.
      5 
      6 const weekdays = [
      7  "Monday",
      8  "Tuesday",
      9  "Wednesday",
     10  "Thursday",
     11  "Friday",
     12  "Saturday",
     13  "Sunday",
     14 ];
     15 
     16 const months = [
     17  "January",
     18  "February",
     19  "March",
     20  "April",
     21  "May",
     22  "June",
     23  "July",
     24  "August",
     25  "September",
     26  "October",
     27  "November",
     28  "December",
     29 ];
     30 
     31 // Map Hebrew months to their corresponding month code.
     32 const hebrewMonths = {
     33  "Tishri": "M01",
     34  "Heshvan": "M02",
     35  "Kislev": "M03",
     36  "Tevet": "M04",
     37  "Shevat": "M05",
     38  "Adar I": "M05L",
     39  "Adar II": "M06",
     40  "Adar": "M06",
     41  "Nisan": "M07",
     42  "Iyar": "M08",
     43  "Sivan": "M09",
     44  "Tamuz": "M10",
     45  "Av": "M11",
     46  "Elul": "M12",
     47 };
     48 
     49 // Extract date information from a to parts formatted date.
     50 function dateFromParts(parts) {
     51  let relatedYear = undefined;
     52  let year = undefined;
     53  let monthCode = "";
     54  let day = 0;
     55  let dayOfWeek = -1;
     56 
     57  for (let {type, value} of parts) {
     58    switch (type) {
     59      case "weekday":
     60        dayOfWeek = weekdays.indexOf(value);
     61        break;
     62      case "year":
     63        year = Number(value);
     64        break;
     65      case "relatedYear":
     66        relatedYear = Number(value);
     67        break;
     68      case "month": {
     69        if (months.includes(value)) {
     70          monthCode = "M" + String(months.indexOf(value) + 1).padStart(2, "0");
     71        } else if (value in hebrewMonths) {
     72          monthCode = hebrewMonths[value];
     73        } else {
     74          // Chinese/Dangi leap months end with "bis", from Latin "bis" = "twice".
     75          let leapMonth = value.endsWith("bis");
     76          if (leapMonth) {
     77            value = value.slice(0, -"bis".length);
     78          }
     79          monthCode = "M" + value.padStart(2, "0") + (leapMonth ? "L" : "");
     80        }
     81        break;
     82      }
     83      case "day":
     84        day = Number(value);
     85        break;
     86      case "era":
     87      case "literal":
     88        continue;
     89      default: throw new Error("bad part: " + type);
     90    }
     91  }
     92  assertEq(dayOfWeek >= 0, true);
     93  assertEq(monthCode.length > 0, true, JSON.stringify(parts));
     94  assertEq(day > 0, true);
     95 
     96  dayOfWeek += 1;
     97 
     98  return {
     99    relatedYear,
    100    year,
    101    monthCode,
    102    day,
    103    dayOfWeek,
    104  };
    105 }
    106 
    107 const tests = {
    108  buddhist: [
    109    // Date ranges in 1500..2500 where ICU4C and ICU4X compute different results.
    110    //
    111    // NOTE: These are dates before the Gregorian change date October 15, 1582.
    112    {
    113      start: {iso: "1500-01-01", year: 2043, monthCode: "M01", day: 1},
    114      end:   {iso: "1582-10-14", year: 2125, monthCode: "M10", day: 14},
    115    },
    116  ],
    117  chinese: [
    118    // Date ranges in 1900..2100 where ICU4C and ICU4X compute different results.
    119    {
    120      start: {iso: "1906-04-23", relatedYear: 1906, monthCode: "M04", day: 1},
    121      end:   {iso: "1906-05-22", relatedYear: 1906, monthCode: "M04", day: 30},
    122    },
    123    {
    124      start: {iso: "1917-03-23", relatedYear: 1917, monthCode: "M02L", day: 1},
    125      end:   {iso: "1917-05-20", relatedYear: 1917, monthCode: "M03", day: 30},
    126    },
    127    {
    128      start: {iso: "1922-06-25", relatedYear: 1922, monthCode: "M05L", day: 1},
    129      end:   {iso: "1922-08-22", relatedYear: 1922, monthCode: "M06", day: 30},
    130    },
    131    {
    132      start: {iso: "1954-02-03", relatedYear: 1954, monthCode: "M01", day: 1},
    133      end:   {iso: "1954-03-04", relatedYear: 1954, monthCode: "M01", day: 30},
    134    },
    135    {
    136      start: {iso: "1955-02-22", relatedYear: 1955, monthCode: "M02", day: 1},
    137      end:   {iso: "1955-03-23", relatedYear: 1955, monthCode: "M02", day: 30},
    138    },
    139    {
    140      start: {iso: "1987-07-26", relatedYear: 1987, monthCode: "M06L", day: 1},
    141      end:   {iso: "1987-09-22", relatedYear: 1987, monthCode: "M07", day: 30},
    142    },
    143    {
    144      start: {iso: "1999-01-17", relatedYear: 1998, monthCode: "M12", day: 1},
    145      end:   {iso: "1999-02-15", relatedYear: 1998, monthCode: "M12", day: 30},
    146    },
    147    {
    148      start: {iso: "2012-08-17", relatedYear: 2012, monthCode: "M07", day: 1},
    149      end:   {iso: "2012-09-15", relatedYear: 2012, monthCode: "M07", day: 30},
    150    },
    151    {
    152      start: {iso: "2018-11-07", relatedYear: 2018, monthCode: "M09", day: 30},
    153      end:   {iso: "2018-12-06", relatedYear: 2018, monthCode: "M10", day: 29},
    154    },
    155    {
    156      start: {iso: "2027-02-06", relatedYear: 2027, monthCode: "M01", day: 1},
    157      end:   {iso: "2027-03-07", relatedYear: 2027, monthCode: "M01", day: 30},
    158    },
    159    {
    160      start: {iso: "2030-02-02", relatedYear: 2029, monthCode: "M12", day: 30},
    161      end:   {iso: "2030-03-03", relatedYear: 2030, monthCode: "M01", day: 29},
    162    },
    163    {
    164      start: {iso: "2057-09-28", relatedYear: 2057, monthCode: "M09", day: 1},
    165      end:   {iso: "2057-10-27", relatedYear: 2057, monthCode: "M09", day: 30},
    166    },
    167    {
    168      start: {iso: "2070-03-12", relatedYear: 2070, monthCode: "M02", day: 1},
    169      end:   {iso: "2070-04-10", relatedYear: 2070, monthCode: "M02", day: 30},
    170    },
    171  ],
    172  dangi: [
    173    // Date ranges in 1900..2100 where ICU4C and ICU4X compute different results.
    174    {
    175      start: {iso: "1904-01-17", relatedYear: 1903, monthCode: "M11", day: 30},
    176      end:   {iso: "1904-02-15", relatedYear: 1903, monthCode: "M12", day: 29},
    177    },
    178    {
    179      start: {iso: "1904-11-07", relatedYear: 1904, monthCode: "M09", day: 30},
    180      end:   {iso: "1904-12-06", relatedYear: 1904, monthCode: "M10", day: 29},
    181    },
    182    {
    183      start: {iso: "1905-05-04", relatedYear: 1905, monthCode: "M03", day: 30},
    184      end:   {iso: "1905-06-02", relatedYear: 1905, monthCode: "M04", day: 29},
    185    },
    186    {
    187      start: {iso: "1908-04-30", relatedYear: 1908, monthCode: "M03", day: 30},
    188      end:   {iso: "1908-05-29", relatedYear: 1908, monthCode: "M04", day: 29},
    189    },
    190    {
    191      start: {iso: "1911-12-20", relatedYear: 1911, monthCode: "M10", day: 30},
    192      end:   {iso: "1912-01-18", relatedYear: 1911, monthCode: "M11", day: 29},
    193    },
    194    {
    195      start: {iso: "2017-02-26", relatedYear: 2017, monthCode: "M02", day: 1},
    196      end:   {iso: "2017-03-27", relatedYear: 2017, monthCode: "M02", day: 30},
    197    },
    198    {
    199      start: {iso: "2051-08-06", relatedYear: 2051, monthCode: "M06", day: 30},
    200      end:   {iso: "2051-09-04", relatedYear: 2051, monthCode: "M07", day: 29},
    201    },
    202    {
    203      start: {iso: "2051-11-03", relatedYear: 2051, monthCode: "M10", day: 1},
    204      end:   {iso: "2051-12-02", relatedYear: 2051, monthCode: "M10", day: 30},
    205    },
    206    {
    207      start: {iso: "2097-01-13", relatedYear: 2096, monthCode: "M12", day: 1},
    208      end:   {iso: "2097-02-11", relatedYear: 2096, monthCode: "M12", day: 30},
    209    },
    210  ],
    211  hebrew: [
    212    // Date ranges in 1500..2500 where ICU4C and ICU4X compute different results.
    213    // ICU bug report: <https://unicode-org.atlassian.net/browse/ICU-23069>.
    214    {
    215      start: {iso: "1700-11-12", year: 5461, monthCode: "M03", day: 1},
    216      end:   {iso: "1701-12-01", year: 5462, monthCode: "M02", day: 30},
    217    },
    218    {
    219      start: {iso: "1798-11-09", year: 5559, monthCode: "M03", day: 1},
    220      end:   {iso: "1799-11-28", year: 5560, monthCode: "M02", day: 30},
    221    },
    222    {
    223      start: {iso: "2045-11-10", year: 5806, monthCode: "M03", day: 1},
    224      end:   {iso: "2046-11-29", year: 5807, monthCode: "M02", day: 30},
    225    },
    226    {
    227      start: {iso: "2292-11-11", year: 6053, monthCode: "M03", day: 1},
    228      end:   {iso: "2293-11-30", year: 6054, monthCode: "M02", day: 30},
    229    },
    230  ],
    231  "islamic-umalqura": [
    232    // TODO: Not yet supported.
    233 
    234    // Date ranges in 2000..2030 where ICU4C and ICU4X compute different results.
    235    // {
    236    //   start: {iso: "2000-02-06", year: 1420, monthCode: "M11", day: 1},
    237    //   end:   {iso: "2000-03-06", year: 1420, monthCode: "M11", day: 30},
    238    // },
    239    // {
    240    //   start: {iso: "2000-09-28", year: 1421, monthCode: "M06", day: 30},
    241    //   end:   {iso: "2000-10-27", year: 1421, monthCode: "M07", day: 29},
    242    // },
    243    // {
    244    //   start: {iso: "2001-10-17", year: 1422, monthCode: "M07", day: 30},
    245    //   end:   {iso: "2001-11-15", year: 1422, monthCode: "M08", day: 29},
    246    // },
    247    // {
    248    //   start: {iso: "2006-06-26", year: 1427, monthCode: "M06", day: 1},
    249    //   end:   {iso: "2006-07-25", year: 1427, monthCode: "M06", day: 30},
    250    // },
    251    // {
    252    //   start: {iso: "2024-12-02", year: 1446, monthCode: "M05", day: 30},
    253    //   end:   {iso: "2024-12-31", year: 1446, monthCode: "M06", day: 29},
    254    // },
    255    // {
    256    //   start: {iso: "2025-01-30", year: 1446, monthCode: "M08", day: 1},
    257    //   end:   {iso: "2025-02-28", year: 1446, monthCode: "M08", day: 30},
    258    // },
    259    // {
    260    //   start: {iso: "2029-08-11", year: 1451, monthCode: "M04", day: 1},
    261    //   end:   {iso: "2029-09-09", year: 1451, monthCode: "M04", day: 30},
    262    // },
    263    // {
    264    //   start: {iso: "2029-11-07", year: 1451, monthCode: "M07", day: 1},
    265    //   end:   {iso: "2029-12-06", year: 1451, monthCode: "M07", day: 30},
    266    // },
    267  ],
    268  japanese: [
    269    // Date ranges in 1500..2500 where ICU4C and ICU4X compute different results.
    270    //
    271    // NOTE: These are dates before the Gregorian change date October 15, 1582.
    272    {
    273      start: {iso: "1500-01-01", monthCode: "M01", day: 1},
    274      end:   {iso: "1582-10-14", monthCode: "M10", day: 14},
    275    },
    276  ],
    277  persian: [
    278    // Date ranges in 1500..2500 where ICU4C and ICU4X compute different results.
    279    // More info: https://github.com/unicode-org/icu4x/issues/4713
    280    {
    281      start: {iso: "2124-03-20", year: 1503, monthCode: "M01", day: 1},
    282      end:   {iso: "2125-03-20", year: 1503, monthCode: "M12", day: 30},
    283    },
    284    {
    285      start: {iso: "2223-03-21", year: 1602, monthCode: "M01", day: 1},
    286      end:   {iso: "2224-03-20", year: 1602, monthCode: "M12", day: 30},
    287    },
    288    {
    289      start: {iso: "2256-03-20", year: 1635, monthCode: "M01", day: 1},
    290      end:   {iso: "2257-03-20", year: 1635, monthCode: "M12", day: 30},
    291    },
    292    {
    293      start: {iso: "2289-03-20", year: 1668, monthCode: "M01", day: 1},
    294      end:   {iso: "2290-03-20", year: 1668, monthCode: "M12", day: 30},
    295    },
    296    {
    297      start: {iso: "2322-03-21", year: 1701, monthCode: "M01", day: 1},
    298      end:   {iso: "2323-03-21", year: 1701, monthCode: "M12", day: 30},
    299    },
    300    {
    301      start: {iso: "2355-03-21", year: 1734, monthCode: "M01", day: 1},
    302      end:   {iso: "2356-03-20", year: 1734, monthCode: "M12", day: 30},
    303    },
    304    {
    305      start: {iso: "2388-03-20", year: 1767, monthCode: "M01", day: 1},
    306      end:   {iso: "2389-03-20", year: 1767, monthCode: "M12", day: 30},
    307    },
    308    {
    309      start: {iso: "2421-03-20", year: 1800, monthCode: "M01", day: 1},
    310      end:   {iso: "2422-03-20", year: 1800, monthCode: "M12", day: 30},
    311    },
    312    {
    313      start: {iso: "2454-03-20", year: 1833, monthCode: "M01", day: 1},
    314      end:   {iso: "2455-03-20", year: 1833, monthCode: "M12", day: 30},
    315    },
    316    {
    317      start: {iso: "2487-03-20", year: 1866, monthCode: "M01", day: 1},
    318      end:   {iso: "2488-03-19", year: 1866, monthCode: "M12", day: 30},
    319    },
    320  ],
    321  roc: [
    322    // Date ranges in 1500..2500 where ICU4C and ICU4X compute different results.
    323    //
    324    // NOTE: These are dates before the Gregorian change date October 15, 1582.
    325    {
    326      start: {iso: "1500-01-01", eraYear: 412, monthCode: "M01", day: 1},
    327      end:   {iso: "1582-10-14", eraYear: 330, monthCode: "M10", day: 14},
    328    },
    329  ],
    330 };
    331 
    332 for (let [calendar, dates] of Object.entries(tests)) {
    333  let dtf = new Intl.DateTimeFormat("en", {
    334    timeZone: "UTC",
    335    calendar,
    336    year: "numeric",
    337    month: "numeric",
    338    day: "numeric",
    339    weekday: "long",
    340  });
    341 
    342  for (let {start, end} of dates) {
    343    // Compute from start date.
    344    let isoStartDate = Temporal.PlainDate.from(start.iso);
    345    let startDate = isoStartDate.withCalendar(calendar);
    346    let startDateParts = dtf.formatToParts(startDate);
    347 
    348    // Compute from end date.
    349    let isoEndDate = Temporal.PlainDate.from(end.iso);
    350    let endDate = isoEndDate.withCalendar(calendar);
    351    let endDateParts = dtf.formatToParts(endDate);
    352 
    353    // Compute from ranges.
    354    let rangeParts = dtf.formatRangeToParts(startDate, endDate);
    355    let startRangeDateParts = rangeParts.filter(({source}) => source !== "endRange");
    356    let endRangeDateParts = rangeParts.filter(({source}) => source !== "startRange");
    357 
    358    // Entries to check.
    359    let entries = [
    360      {
    361        date: startDate,
    362        parts: startDateParts,
    363        expected: start,
    364      },
    365      {
    366        date: endDate,
    367        parts: endDateParts,
    368        expected: end,
    369      },
    370      {
    371        date: startDate,
    372        parts: startRangeDateParts,
    373        expected: start,
    374      },
    375      {
    376        date: endDate,
    377        parts: endRangeDateParts,
    378        expected: end,
    379      },
    380    ];
    381 
    382    for (let {date, parts, expected} of entries) {
    383      // Ensure Temporal matches |expected|.
    384      if (expected.year !== undefined) {
    385        assertEq(date.year, expected.year);
    386      }
    387      if (expected.eraYear !== undefined) {
    388        assertEq(date.eraYear, expected.eraYear);
    389      }
    390      if (expected.relatedYear !== undefined) {
    391        assertEq(date.with({month: 1}).withCalendar("iso8601").year, expected.relatedYear);
    392      }
    393      assertEq(date.monthCode, expected.monthCode);
    394      assertEq(date.day, expected.day);
    395 
    396      // Ensure Intl.DateTimeFormat matches |expected|.
    397      let partsDate = dateFromParts(parts);
    398 
    399      if (expected.year !== undefined) {
    400        assertEq(partsDate.year, expected.year);
    401      }
    402      if (expected.eraYear !== undefined) {
    403        assertEq(partsDate.year, expected.eraYear);
    404      }
    405      if (partsDate.relatedYear !== undefined) {
    406        // NB: relatedYear isn't used for range formats with chinese/dangi calendars.
    407        assertEq(partsDate.relatedYear, expected.relatedYear);
    408      }
    409      assertEq(partsDate.monthCode, expected.monthCode);
    410      assertEq(partsDate.day, expected.day);
    411    }
    412  }
    413 }
    414 
    415 if (typeof reportCompare === "function")
    416  reportCompare(true, true);