UNPKG

nhb-toolbox

Version:

A versatile collection of smart, efficient, and reusable utility functions, classes and types for everyday development needs.

157 lines (156 loc) 5.23 kB
import { isDate, isObjectWithKeys, isValidArray } from '../guards/non-primitives.js'; import { isNonEmptyString, isString } from '../guards/primitives.js'; import { isDateString } from '../guards/specials.js'; import { getOrdinal } from '../number/utilities.js'; import { BN_MONTH_TABLES, BN_SEASONS, BN_YEAR_OFFSET, DAYS, MONTHS, MS_PER_DAY, SORTED_TIME_FORMATS, } from './constants.js'; import { isLeapYear, isValidUTCOffset } from './guards.js'; export function _formatDateCore(format, dateComponents) { const tokenRegex = new RegExp(`^(${SORTED_TIME_FORMATS.join('|')})`); let result = ''; let i = 0; while (i < format.length) { if (format[i] === '[') { const end = format.indexOf(']', i); if (end !== -1) { result += format.slice(i + 1, end); i = end + 1; continue; } } const match = tokenRegex.exec(format.slice(i)); if (match) { result += dateComponents[match[0]] ?? match[0]; i += match[0].length; } else { result += format[i]; i++; } } return result; } export function _formatDate(format, year, month, day, date, hours, minutes, seconds, milliseconds, offset) { const paddedYear = _padZero(year, 4); const dateComponents = { YYYY: paddedYear, YY: paddedYear.slice(-2), yyyy: paddedYear, yy: paddedYear.slice(-2), M: String(month + 1), MM: _padZero(month + 1), mmm: MONTHS[month].slice(0, 3), mmmm: MONTHS[month], d: DAYS[day].slice(0, 2), dd: DAYS[day].slice(0, 3), ddd: DAYS[day], D: String(date), DD: _padZero(date), Do: getOrdinal(date), H: String(hours), HH: _padZero(hours), h: String(hours % 12 || 12), hh: _padZero(hours % 12 || 12), m: String(minutes), mm: _padZero(minutes), s: String(seconds), ss: _padZero(seconds), ms: String(milliseconds), mss: _padZero(milliseconds, 3), a: hours < 12 ? 'am' : 'pm', A: hours < 12 ? 'AM' : 'PM', Z: offset, ZZ: offset, }; return _formatDateCore(format, dateComponents); } export function _normalizeOffset(timeStr) { return timeStr.replace(/([+-]\d{2})(?!:)/, '$1:00'); } export const _toSeconds = (ms) => Math.floor(ms / 1000); export const _secToDate = (sec) => new Date(sec * 1000); export function _resolveNativeTzName(tzId, type, date) { try { const parts = new Intl.DateTimeFormat('en', { timeZone: tzId, timeZoneName: type, }).formatToParts(date); return parts.find((p) => p.type === 'timeZoneName')?.value; } catch { return undefined; } } export function _gmtToUtcOffset(gmt) { return gmt === 'GMT' ? 'UTC+00:00' : gmt?.replace(/^GMT/, 'UTC'); } export function _getBnSeason(month, locale) { const season = BN_SEASONS[Math.floor(month / 2)]; return (locale === 'en' ? season.en : season.bn); } export function _isBnLeapYear(by, gy, v) { return v === 'revised-1966' ? by % 4 === 2 : isLeapYear(gy); } export function _extractDateUnits(date) { const month = date.getMonth(); return { gy: date.getFullYear(), $gm: month, gm: (month + 1), gd: date.getDate(), wd: date.getDay(), }; } export function _getGregBaseYear(date) { const { gy, gm, gd } = _extractDateUnits(date); return gm < 4 || (gm === 4 && gd < 14) ? gy - 1 : gy; } export function _getBnYear(date) { return _getGregBaseYear(date) - BN_YEAR_OFFSET; } export function _getUtcTs(date) { const { gy, $gm, gd } = _extractDateUnits(date); return Date.UTC(gy, $gm, gd); } export function _getElapsedDays(date) { return Math.floor((_getUtcTs(date) - Date.UTC(_getGregBaseYear(date), 3, 14)) / MS_PER_DAY); } export function _bnDaysMonthIdx(date, variant) { const v = variant ?? 'revised-2019'; const table = _isBnLeapYear(_getBnYear(date), date.getFullYear(), v) ? BN_MONTH_TABLES?.[v].leap : BN_MONTH_TABLES?.[v].normal; let days = _getElapsedDays(date); let monthIdx = 0; while (days >= table[monthIdx]) { days -= table[monthIdx]; monthIdx++; } return { days, monthIdx }; } export function _padZero(value, length = 2) { return String(value).padStart(length, '0'); } export function _padShunno(str, length = 2) { return str.padStart(length, '০'); } export function _dateArgsToDate(value) { return new Date(isDate(value) ? value : isString(value) ? value.replace(/['"]/g, '') : (value ?? Date.now())); } export function _hasChronosProperties(value) { return (isObjectWithKeys(value, [ 'origin', 'native', 'utcOffset', 'timeZoneName', 'timeZoneId', ]) && isNonEmptyString(value.origin) && (isDate(value.native) || isDateString(value.native)) && isValidUTCOffset(value.utcOffset) && isNonEmptyString(value.timeZoneName) && (isNonEmptyString(value.timeZoneId) || isValidArray(value.timeZoneId))); }