tor-browser

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

UnitConverterTimezone.sys.mjs (3927B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 const TIMEZONES = {
      6  IDLW: -12,
      7  NT: -11,
      8  HST: -10,
      9  AKST: -9,
     10  PST: -8,
     11  AKDT: -8,
     12  MST: -7,
     13  PDT: -7,
     14  CST: -6,
     15  MDT: -6,
     16  EST: -5,
     17  CDT: -5,
     18  EDT: -4,
     19  AST: -4,
     20  GUY: -3,
     21  ADT: -3,
     22  AT: -2,
     23  UTC: 0,
     24  GMT: 0,
     25  Z: 0,
     26  WET: 0,
     27  WEST: 1,
     28  CET: 1,
     29  BST: 1,
     30  IST: 1,
     31  CEST: 2,
     32  EET: 2,
     33  EEST: 3,
     34  MSK: 3,
     35  MSD: 4,
     36  ZP4: 4,
     37  ZP5: 5,
     38  ZP6: 6,
     39  WAST: 7,
     40  AWST: 8,
     41  WST: 8,
     42  JST: 9,
     43  ACST: 9.5,
     44  ACDT: 10.5,
     45  AEST: 10,
     46  AEDT: 11,
     47  NZST: 12,
     48  IDLE: 12,
     49  NZD: 13,
     50 };
     51 
     52 const TIME_REGEX = "([0-2]?[0-9])(:([0-5][0-9]))?\\s*([ap]m)?";
     53 const TIMEZONE_REGEX = "\\w+";
     54 
     55 // NOTE: This regex need to be localized upon supporting multi locales
     56 //       since it supports en-US input format only.
     57 const QUERY_REGEX = new RegExp(
     58  `^(${TIME_REGEX}|now)\\s*(${TIMEZONE_REGEX})?(?:\\s+in\\s+|\\s+to\\s+|\\s*=\\s*)(${TIMEZONE_REGEX}|here)`,
     59  "i"
     60 );
     61 
     62 const KEYWORD_HERE = "HERE";
     63 const KEYWORD_NOW = "NOW";
     64 
     65 /**
     66 * This module converts timezone.
     67 */
     68 export class UnitConverterTimezone {
     69  /**
     70   * Convert the given search string.
     71   *
     72   * @param {string} searchString
     73   *   The string to be converted
     74   * @returns {string} conversion result.
     75   */
     76  convert(searchString) {
     77    const regexResult = QUERY_REGEX.exec(searchString);
     78    if (!regexResult) {
     79      return null;
     80    }
     81 
     82    const inputTime = regexResult[1].toUpperCase();
     83    const inputTimezone = regexResult[6]?.toUpperCase();
     84    let outputTimezone = regexResult[7].toUpperCase();
     85 
     86    if (
     87      (inputTimezone &&
     88        inputTimezone !== KEYWORD_NOW &&
     89        !(inputTimezone in TIMEZONES)) ||
     90      (outputTimezone !== KEYWORD_HERE && !(outputTimezone in TIMEZONES))
     91    ) {
     92      return null;
     93    }
     94 
     95    const inputDate = new Date();
     96    let isMeridiemNeeded = false;
     97    if (inputTime === KEYWORD_NOW) {
     98      inputDate.setUTCHours(inputDate.getHours());
     99      inputDate.setUTCMinutes(inputDate.getMinutes());
    100    } else {
    101      // If the input was given as AM/PM, we need to convert it to 24h.
    102      // 12AM is converted to 00, and for PM times we add 12 to the hour value except for 12PM.
    103      // If the input is for example 23PM, we use 23 as the hour - we don't add 12 as this would result in a date increment.
    104      const inputAMPM = regexResult[5]?.toLowerCase() || "";
    105      const inputHours =
    106        regexResult[2] === "12" && inputAMPM === "am"
    107          ? 0
    108          : Number(regexResult[2]);
    109      const inputMinutes = regexResult[4] ? Number(regexResult[4]) : 0;
    110      const inputMeridianHourShift =
    111        inputAMPM === "pm" && inputHours < 12 ? 12 : 0;
    112      inputDate.setUTCHours(inputHours + inputMeridianHourShift);
    113      inputDate.setUTCMinutes(inputMinutes);
    114      isMeridiemNeeded = !!inputAMPM;
    115    }
    116 
    117    const inputOffset = inputTimezone
    118      ? TIMEZONES[inputTimezone] * 60
    119      : -inputDate.getTimezoneOffset();
    120    let outputOffset;
    121    if (outputTimezone === KEYWORD_HERE) {
    122      outputOffset = -inputDate.getTimezoneOffset();
    123      const sign = -inputDate.getTimezoneOffset() > 0 ? "+" : "-";
    124      const hours = Math.floor(Math.abs(outputOffset) / 60);
    125      const minutes = formatMinutes((outputOffset % 60) * 60);
    126      outputTimezone = `UTC${sign}${hours}${minutes}`;
    127    } else {
    128      outputOffset = TIMEZONES[outputTimezone] * 60;
    129    }
    130 
    131    const outputDate = new Date(inputDate.getTime());
    132    outputDate.setUTCMinutes(
    133      outputDate.getUTCMinutes() - inputOffset + outputOffset
    134    );
    135 
    136    const time = new Intl.DateTimeFormat("en-US", {
    137      timeStyle: "short",
    138      hour12: isMeridiemNeeded,
    139      timeZone: "UTC",
    140    }).format(outputDate);
    141 
    142    return `${time} ${outputTimezone}`;
    143  }
    144 }
    145 
    146 function formatMinutes(minutes) {
    147  return minutes.toString().padStart(2, "0");
    148 }