diff options
Diffstat (limited to 'browser/components/urlbar/unitconverters/UnitConverterTimezone.sys.mjs')
-rw-r--r-- | browser/components/urlbar/unitconverters/UnitConverterTimezone.sys.mjs | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/browser/components/urlbar/unitconverters/UnitConverterTimezone.sys.mjs b/browser/components/urlbar/unitconverters/UnitConverterTimezone.sys.mjs new file mode 100644 index 0000000000..50ba924bed --- /dev/null +++ b/browser/components/urlbar/unitconverters/UnitConverterTimezone.sys.mjs @@ -0,0 +1,148 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const TIMEZONES = { + IDLW: -12, + NT: -11, + HST: -10, + AKST: -9, + PST: -8, + AKDT: -8, + MST: -7, + PDT: -7, + CST: -6, + MDT: -6, + EST: -5, + CDT: -5, + EDT: -4, + AST: -4, + GUY: -3, + ADT: -3, + AT: -2, + UTC: 0, + GMT: 0, + Z: 0, + WET: 0, + WEST: 1, + CET: 1, + BST: 1, + IST: 1, + CEST: 2, + EET: 2, + EEST: 3, + MSK: 3, + MSD: 4, + ZP4: 4, + ZP5: 5, + ZP6: 6, + WAST: 7, + AWST: 8, + WST: 8, + JST: 9, + ACST: 9.5, + ACDT: 10.5, + AEST: 10, + AEDT: 11, + NZST: 12, + IDLE: 12, + NZD: 13, +}; + +const TIME_REGEX = "([0-2]?[0-9])(:([0-5][0-9]))?\\s*([ap]m)?"; +const TIMEZONE_REGEX = "\\w+"; + +// NOTE: This regex need to be localized upon supporting multi locales +// since it supports en-US input format only. +const QUERY_REGEX = new RegExp( + `^(${TIME_REGEX}|now)\\s*(${TIMEZONE_REGEX})?(?:\\s+in\\s+|\\s+to\\s+|\\s*=\\s*)(${TIMEZONE_REGEX}|here)`, + "i" +); + +const KEYWORD_HERE = "HERE"; +const KEYWORD_NOW = "NOW"; + +/** + * This module converts timezone. + */ +export class UnitConverterTimezone { + /** + * Convert the given search string. + * + * @param {string} searchString + * The string to be converted + * @returns {string} conversion result. + */ + convert(searchString) { + const regexResult = QUERY_REGEX.exec(searchString); + if (!regexResult) { + return null; + } + + const inputTime = regexResult[1].toUpperCase(); + const inputTimezone = regexResult[6]?.toUpperCase(); + let outputTimezone = regexResult[7].toUpperCase(); + + if ( + (inputTimezone && + inputTimezone !== KEYWORD_NOW && + !(inputTimezone in TIMEZONES)) || + (outputTimezone !== KEYWORD_HERE && !(outputTimezone in TIMEZONES)) + ) { + return null; + } + + const inputDate = new Date(); + let isMeridiemNeeded = false; + if (inputTime === KEYWORD_NOW) { + inputDate.setUTCHours(inputDate.getHours()); + inputDate.setUTCMinutes(inputDate.getMinutes()); + } else { + // If the input was given as AM/PM, we need to convert it to 24h. + // 12AM is converted to 00, and for PM times we add 12 to the hour value except for 12PM. + // 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. + const inputAMPM = regexResult[5]?.toLowerCase() || ""; + const inputHours = + regexResult[2] === "12" && inputAMPM === "am" + ? 0 + : Number(regexResult[2]); + const inputMinutes = regexResult[4] ? Number(regexResult[4]) : 0; + const inputMeridianHourShift = + inputAMPM === "pm" && inputHours < 12 ? 12 : 0; + inputDate.setUTCHours(inputHours + inputMeridianHourShift); + inputDate.setUTCMinutes(inputMinutes); + isMeridiemNeeded = !!inputAMPM; + } + + const inputOffset = inputTimezone + ? TIMEZONES[inputTimezone] * 60 + : -inputDate.getTimezoneOffset(); + let outputOffset; + if (outputTimezone === KEYWORD_HERE) { + outputOffset = -inputDate.getTimezoneOffset(); + const sign = -inputDate.getTimezoneOffset() > 0 ? "+" : "-"; + const hours = parseInt(Math.abs(outputOffset) / 60); + const minutes = formatMinutes((outputOffset % 60) * 60); + outputTimezone = `UTC${sign}${hours}${minutes}`; + } else { + outputOffset = TIMEZONES[outputTimezone] * 60; + } + + const outputDate = new Date(inputDate.getTime()); + outputDate.setUTCMinutes( + outputDate.getUTCMinutes() - inputOffset + outputOffset + ); + + const time = new Intl.DateTimeFormat("en-US", { + timeStyle: "short", + hour12: isMeridiemNeeded, + timeZone: "UTC", + }).format(outputDate); + + return `${time} ${outputTimezone}`; + } +} + +function formatMinutes(minutes) { + return minutes.toString().padStart(2, "0"); +} |