UNPKG

@neo4j-ndl/react

Version:

React implementation of Neo4j Design System

262 lines 10.2 kB
"use strict"; /** * * Copyright (c) "Neo4j" * Neo4j Sweden AB [http://neo4j.com] * * This file is part of Neo4j. * * Neo4j is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.formatTimeZone = exports.isValidUTCFormat = exports.parseCustomUTCOffset = exports.getUserTimeZone = exports.generateTimeZoneOptions = exports.generateUTCTimeZoneOptions = void 0; /** * Gets the offset in minutes for a timezone at a specific date */ const getOffsetMinutes = (timezone, date) => { try { // Create dates in UTC and in the target timezone const utcDate = new Date(date.toLocaleString('en-US', { timeZone: 'UTC' })); const tzDate = new Date(date.toLocaleString('en-US', { timeZone: timezone })); // Calculate the difference in minutes const diffMs = tzDate.getTime() - utcDate.getTime(); return Math.round(diffMs / (1000 * 60)); } catch (_a) { return 0; } }; /** * Formats a UTC offset using the Intl API for consistent formatting * @param offsetHours - The offset in hours (can be fractional) * @returns Formatted UTC offset string (e.g., "UTC+5:30", "UTC-3") */ const formatUTCOffset = (offsetHours) => { if (offsetHours === 0) { return 'UTC'; } const sign = offsetHours >= 0 ? '+' : '-'; const absHours = Math.abs(offsetHours); const hours = Math.floor(absHours); const minutes = Math.round((absHours - hours) * 60); // Use Intl.NumberFormat for consistent number formatting const numberFormatter = new Intl.NumberFormat('en-US', { maximumFractionDigits: 0, minimumIntegerDigits: 1, }); const formattedHours = numberFormatter.format(hours); const formattedMinutes = minutes > 0 ? `:${String(minutes).padStart(2, '0')}` : ''; return `UTC${sign}${formattedHours}${formattedMinutes}`; }; /** * Extracts unique UTC offsets from all supported timezones using the Intl API * @param referenceDate - The date to use for calculating timezone offsets (defaults to current date) * @returns Set of unique offset values in minutes */ const getUniqueOffsetsFromAPI = (referenceDate) => { const uniqueOffsets = new Set(); const now = referenceDate || new Date(); try { // Get all supported timezones from the Intl API const timezones = Intl.supportedValuesOf('timeZone'); // Extract unique offsets from each timezone for (const tz of timezones) { try { const offsetMinutes = getOffsetMinutes(tz, now); uniqueOffsets.add(offsetMinutes); } catch (_a) { // Skip timezones that can't be processed continue; } } } catch (_b) { // Fallback to empty set if API is not available } // Always include UTC (offset 0) uniqueOffsets.add(0); return uniqueOffsets; }; /** * Generates UTC-only timezone options derived from the Intl API * Uses the Intl API to discover which UTC offsets are actually used by supported timezones * @param referenceDate - The date to use for calculating timezone offsets (defaults to current date) */ const generateUTCTimeZoneOptions = (referenceDate) => { // Get unique offsets from all supported timezones via the Intl API const uniqueOffsets = getUniqueOffsetsFromAPI(referenceDate); // Convert offset minutes to hours (can be fractional) const offsetHours = Array.from(uniqueOffsets) .map((minutes) => minutes / 60) .sort((a, b) => a - b); // Convert to TimeZoneOption format const options = offsetHours.map((offsetHours) => { const offsetStr = formatUTCOffset(offsetHours); return { label: offsetStr, offset: offsetStr, offsetMinutes: Math.round(offsetHours * 60), value: offsetStr, }; }); return options; }; exports.generateUTCTimeZoneOptions = generateUTCTimeZoneOptions; /** * Generates a list of common timezone options with their UTC offsets * @param referenceDate - The date to use for calculating timezone offsets (defaults to current date) * @param excludeUTC - Whether to exclude the UTC timezone from the list (useful when combining with UTC-only options) */ const generateTimeZoneOptions = (referenceDate, excludeUTC = false) => { // Common timezones with their IANA identifiers const timezones = Intl.supportedValuesOf('timeZone'); const now = referenceDate || new Date(); // Filter out UTC if requested const filteredTimezones = excludeUTC ? timezones.filter((tz) => tz !== 'UTC') : timezones; return filteredTimezones .map((tz) => { var _a, _b, _c; try { // Get the offset for this timezone const formatter = new Intl.DateTimeFormat('en-US', { timeZone: tz, timeZoneName: 'shortOffset', }); const parts = formatter.formatToParts(now); const offsetPart = parts.find((part) => part.type === 'timeZoneName'); const offset = (_a = offsetPart === null || offsetPart === void 0 ? void 0 : offsetPart.value) !== null && _a !== void 0 ? _a : ''; // Calculate offset in minutes for proper sorting const offsetMinutes = getOffsetMinutes(tz, now); // Format the label const cityName = (_c = (_b = tz.split('/').pop()) === null || _b === void 0 ? void 0 : _b.replace(/_/g, ' ')) !== null && _c !== void 0 ? _c : tz; const label = `${cityName} (${offset})`; return { label, offset, offsetMinutes, value: tz, }; } catch (_d) { // Fallback if timezone is not supported return { label: tz.replace(/_/g, ' '), offset: '', offsetMinutes: 0, value: tz, }; } }) .sort((a, b) => { // Sort by offset (negative to positive), then by label if (a.offsetMinutes !== b.offsetMinutes) { return a.offsetMinutes - b.offsetMinutes; } return a.label.localeCompare(b.label); }); }; exports.generateTimeZoneOptions = generateTimeZoneOptions; /** * Gets the user's current timezone */ const getUserTimeZone = () => { try { return Intl.DateTimeFormat().resolvedOptions().timeZone; } catch (_a) { return 'UTC'; } }; exports.getUserTimeZone = getUserTimeZone; /** * Parses a custom UTC offset string (e.g., "UTC+5:30", "UTC-3:45") * @param input - The input string to parse * @returns The parsed timezone value or null if invalid */ const parseCustomUTCOffset = (input) => { // Match patterns like: UTC+5:30, UTC-3:45, UTC+1, UTC-12, etc. // Also accepts single digit minutes which will be padded const utcPattern = /^UTC([+-])?(\d{1,2})(?::(\d{1,2}))?$/i; const match = input.trim().match(utcPattern); if (!match) { return null; } const sign = match[1] === '-' ? '-' : '+'; const hours = parseInt(match[2], 10); const minutes = match[3] ? parseInt(match[3], 10) : 0; // Validate ranges based on sign if (sign === '+') { if (hours < 0 || hours > 14) { return null; } if (hours === 14 && minutes > 0) { return null; } // UTC+14 is max } else { // sign === '-' if (hours < 0 || hours > 12) { return null; } // UTC-12 is min if (hours === 12 && minutes > 0) { return null; } // UTC-12 is min } if (minutes < 0 || minutes > 59) { return null; } return `UTC${sign}${hours}${minutes > 0 ? `:${String(minutes).padStart(2, '0')}` : ''}`; }; exports.parseCustomUTCOffset = parseCustomUTCOffset; /** * Validates if a string is a valid UTC timezone format * @param input - The input string to validate * @returns True if valid UTC timezone format */ const isValidUTCFormat = (input) => { return (0, exports.parseCustomUTCOffset)(input) !== null || input.toUpperCase() === 'UTC'; }; exports.isValidUTCFormat = isValidUTCFormat; /** * Formats a timezone for display * @param timezone - The IANA timezone identifier or UTC offset * @param referenceDate - The date to use for calculating the offset (defaults to current date) */ const formatTimeZone = (timezone, referenceDate) => { var _a, _b, _c; // If it's already a UTC format, return as-is if (timezone.toUpperCase().startsWith('UTC')) { return timezone; } try { const now = referenceDate || new Date(); const formatter = new Intl.DateTimeFormat('en-US', { timeZone: timezone, timeZoneName: 'shortOffset', }); const parts = formatter.formatToParts(now); const offsetPart = parts.find((part) => part.type === 'timeZoneName'); const offset = (_a = offsetPart === null || offsetPart === void 0 ? void 0 : offsetPart.value) !== null && _a !== void 0 ? _a : ''; const cityName = (_c = (_b = timezone.split('/').pop()) === null || _b === void 0 ? void 0 : _b.replace(/_/g, ' ')) !== null && _c !== void 0 ? _c : timezone; return `${cityName} (${offset})`; } catch (_d) { return timezone.replace(/_/g, ' '); } }; exports.formatTimeZone = formatTimeZone; //# sourceMappingURL=generate-timezone-options.js.map