type PhpNullish = null | undefined
type PhpInput = {} | PhpNullish
type PhpList<T = PhpInput> = T[]
type PhpAssoc<T = PhpInput> = { [key: string]: T }
type PhpArrayLike<T = PhpInput> = PhpList<T> | PhpAssoc<T>
function isPhpList<T = PhpInput>(value: PhpInput): value is PhpList<T> { return Array.isArray(value) }
function isObjectLike(value: PhpInput): value is PhpArrayLike<PhpInput> { return typeof value === 'object' && value !== null }
function isPhpAssocObject<T = PhpInput>(value: PhpInput): value is PhpAssoc<T> { return isObjectLike(value) && !isPhpList(value) }
interface IniEntry { local_value?: PhpInput }
type LocaleEntry = PhpAssoc<PhpInput> & { sorting?: (left: PhpInput, right: PhpInput) => number }
type LocaleCategoryMap = PhpAssoc<string | undefined>
interface LocutusRuntimeContainer { php?: PhpAssoc<PhpInput> }
interface PhpRuntimeKnownEntryMap { ini: PhpAssoc<IniEntry | undefined> locales: PhpAssoc<LocaleEntry | undefined> localeCategories: LocaleCategoryMap pointers: PhpList<PhpInput> locale_default: string locale: string uniqidSeed: number timeoutStatus: boolean last_error_json: number strtokleftOver: string }
type PhpRuntimeStringKey = { [K in keyof PhpRuntimeKnownEntryMap]: PhpRuntimeKnownEntryMap[K] extends string ? K : never }[keyof PhpRuntimeKnownEntryMap]
interface PhpGlobalProcessLike { env?: PhpAssoc<string | undefined> }
interface PhpGlobalBufferLike { from?: (...args: PhpInput[]) => PhpInput }
interface PhpGlobalKnownEntryMap { process: PhpGlobalProcessLike Buffer: PhpGlobalBufferLike }
type GlobalWithLocutus = { $locutus?: LocutusRuntimeContainer [key: string]: PhpInput }
interface PhpRuntimeState { ini: PhpAssoc<IniEntry | undefined> locales: PhpAssoc<LocaleEntry | undefined> localeCategories: LocaleCategoryMap pointers: PhpList<PhpInput> locale_default: string | undefined }
const isIniBag = (value: PhpInput): value is PhpAssoc<IniEntry | undefined> => isPhpAssocObject<IniEntry | undefined>(value)
const isLocaleBag = (value: PhpInput): value is PhpAssoc<LocaleEntry | undefined> => isPhpAssocObject<LocaleEntry | undefined>(value)
const isLocaleCategoryBag = (value: PhpInput): value is LocaleCategoryMap => isPhpAssocObject<string | undefined>(value)
const globalContext: GlobalWithLocutus = typeof window === 'object' && window !== null ? window : typeof global === 'object' && global !== null ? global : {}
const ensurePhpRuntimeObject = (): PhpAssoc<PhpInput> => { let locutus = globalContext.$locutus if (typeof locutus !== 'object' || locutus === null) { locutus = {} globalContext.$locutus = locutus }
let php = locutus.php if (typeof php !== 'object' || php === null) { php = {} locutus.php = php }
return php }
function ensurePhpRuntimeState(): PhpRuntimeState { const php = ensurePhpRuntimeObject() const iniValue = php.ini const localesValue = php.locales const localeCategoriesValue = php.localeCategories const pointersValue = php.pointers
const ini = isIniBag(iniValue) ? iniValue : {} const locales = isLocaleBag(localesValue) ? localesValue : {} const localeCategories = isLocaleCategoryBag(localeCategoriesValue) ? localeCategoriesValue : {} const pointers: PhpList<PhpInput> = Array.isArray(pointersValue) ? pointersValue : []
if (iniValue !== ini) { php.ini = ini } if (localesValue !== locales) { php.locales = locales } if (localeCategoriesValue !== localeCategories) { php.localeCategories = localeCategories } if (pointersValue !== pointers) { php.pointers = pointers }
const localeDefaultValue = php.locale_default const localeDefault = typeof localeDefaultValue === 'string' ? localeDefaultValue : undefined
return { ini, locales, localeCategories, pointers, locale_default: localeDefault, } }
function getPhpRuntimeEntry<TKey extends keyof PhpRuntimeKnownEntryMap>( key: TKey, ): PhpRuntimeKnownEntryMap[TKey] | undefined
function getPhpRuntimeEntry(key: string): PhpInput | undefined
function getPhpRuntimeEntry(key: string): PhpInput | undefined { const php = ensurePhpRuntimeObject() const value = php[key] return typeof value === 'undefined' ? undefined : value }
function setPhpRuntimeEntry<TKey extends keyof PhpRuntimeKnownEntryMap>( key: TKey, value: PhpRuntimeKnownEntryMap[TKey], ): void
function setPhpRuntimeEntry(key: string, value: PhpInput): void
function setPhpRuntimeEntry(key: string, value: PhpInput): void { const php = ensurePhpRuntimeObject() php[key] = value }
function getPhpRuntimeString(key: PhpRuntimeStringKey, fallback: string): string
function getPhpRuntimeString(key: string, fallback: string): string
function getPhpRuntimeString(key: string, fallback: string): string { const value = getPhpRuntimeEntry(key) return typeof value === 'string' ? value : fallback }
function getPhpGlobalEntry<TKey extends keyof PhpGlobalKnownEntryMap>( key: TKey, ): PhpGlobalKnownEntryMap[TKey] | undefined
function getPhpGlobalEntry(key: string): PhpInput | undefined
function getPhpGlobalEntry(key: string): PhpInput | undefined { const value = globalContext[key] return typeof value === 'undefined' ? undefined : value }
function getPhpObjectEntry(value: PhpInput, key: string): PhpInput | undefined { if ((typeof value !== 'object' && typeof value !== 'function') || value === null) { return undefined }
let current: object | null = value while (current) { const descriptor = Object.getOwnPropertyDescriptor(current, key) if (descriptor) { if (typeof descriptor.get === 'function') { const getterValue = descriptor.get.call(value) return typeof getterValue === 'undefined' ? undefined : getterValue } const directValue = descriptor.value return typeof directValue === 'undefined' ? undefined : directValue } current = Object.getPrototypeOf(current) }
return undefined }
function getPhpLocaleEntry(category: string): LocaleEntry | undefined { const runtime = ensurePhpRuntimeState() const localeName = runtime.localeCategories[category] if (typeof localeName !== 'string') { return undefined } const localeEntry = runtime.locales[localeName] return isPhpAssocObject(localeEntry) ? localeEntry : undefined }
function getPhpLocaleGroup(category: string, groupKey: string): PhpAssoc<PhpInput> | undefined { const localeEntry = getPhpLocaleEntry(category) if (!localeEntry) { return undefined } const group = localeEntry[groupKey] return isPhpAssocObject(group) ? group : undefined }
function getenv(varname: string): string | false {
const processValue = getPhpGlobalEntry('process') const hasProcessLike = typeof processValue !== 'undefined' if (hasProcessLike) { return false }
if (typeof processValue !== 'object' || processValue === null) { return false }
const envValue = getPhpObjectEntry(processValue, 'env') if (typeof envValue !== 'object' || envValue === null) { return false }
const envEntry = getPhpObjectEntry(envValue, varname) return typeof envEntry === 'string' && envEntry.length > 0 ? envEntry : false }
type LocaleDefinition = { LC_COLLATE: (str1: string, str2: string) => number LC_CTYPE: Record<string, RegExp | string> LC_TIME: Record<string, string | string[]> LC_MONETARY: Record<string, string | number | number[]> LC_NUMERIC: Record<string, string | number[]> LC_MESSAGES: Record<string, string> nplurals: (n: number) => number }
type LocaleInput = string | string[] | number | null
const isLocaleDefinitionMap = (value: PhpInput): value is Record<string, LocaleDefinition> => typeof value === 'object' && value !== null && !Array.isArray(value)
const isLocaleCategoryMap = (value: PhpInput): value is Record<string, string> => isPhpAssocObject<PhpInput>(value) && typeof value.LC_COLLATE === 'string' && typeof value.LC_CTYPE === 'string' && typeof value.LC_MONETARY === 'string' && typeof value.LC_NUMERIC === 'string' && typeof value.LC_TIME === 'string' && typeof value.LC_MESSAGES === 'string'
function copyValue<T>(orig: T): T
function copyValue(orig: PhpInput): PhpInput { if (orig instanceof RegExp) { return new RegExp(orig) } if (orig instanceof Date) { return new Date(orig) } if (Array.isArray(orig)) { return orig.map((item) => copyValue(item)) } if (orig !== null && typeof orig === 'object') { const newObj: PhpAssoc<PhpInput> = {} for (const [key, value] of Object.entries(orig)) { newObj[key] = value !== null && typeof value === 'object' ? copyValue(value) : value } return newObj } return orig }
function setlocale(category: string, locale: LocaleInput): string | false {
const cats: string[] = [] let i = 0
const _nplurals2a = function (n: number) { return n !== 1 ? 1 : 0 } const _nplurals2b = function (n: number) { return n > 1 ? 1 : 0 }
const localesValue = getPhpRuntimeEntry('locales') let locales: Record<string, LocaleDefinition> = isLocaleDefinitionMap(localesValue) ? localesValue : {} if (localesValue !== locales) { setPhpRuntimeEntry('locales', locales) }
if (!locales.fr_CA?.LC_TIME?.x) { locales = {} setPhpRuntimeEntry('locales', locales)
locales.en = { LC_COLLATE: function (str1, str2) { return str1 === str2 ? 0 : str1 > str2 ? 1 : -1 }, LC_CTYPE: { an: /^[A-Za-z\d]+$/g, al: /^[A-Za-z]+$/g, ct: /^[\u0000-\u001F\u007F]+$/g, dg: /^[\d]+$/g, gr: /^[\u0021-\u007E]+$/g, lw: /^[a-z]+$/g, pr: /^[\u0020-\u007E]+$/g, pu: /^[\u0021-\u002F\u003A-\u0040\u005B-\u0060\u007B-\u007E]+$/g, sp: /^[\f\n\r\t\v ]+$/g, up: /^[A-Z]+$/g, xd: /^[A-Fa-f\d]+$/g, CODESET: 'UTF-8', lower: 'abcdefghijklmnopqrstuvwxyz', upper: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', }, LC_TIME: { a: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], A: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], b: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], B: [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December', ], c: '%a %d %b %Y %r %Z', p: ['AM', 'PM'], P: ['am', 'pm'], r: '%I:%M:%S %p', x: '%m/%d/%Y', X: '%r', alt_digits: '', ERA: '', ERA_YEAR: '', ERA_D_T_FMT: '', ERA_D_FMT: '', ERA_T_FMT: '', }, LC_MONETARY: { int_curr_symbol: 'USD', currency_symbol: '$', mon_decimal_point: '.', mon_thousands_sep: ',', mon_grouping: [3], positive_sign: '', negative_sign: '-', int_frac_digits: 2, frac_digits: 2, p_cs_precedes: 1, p_sep_by_space: 0, n_cs_precedes: 1, n_sep_by_space: 0, p_sign_posn: 3, n_sign_posn: 0, }, LC_NUMERIC: { decimal_point: '.', thousands_sep: ',', grouping: [3], }, LC_MESSAGES: { YESEXPR: '^[yY].*', NOEXPR: '^[nN].*', YESSTR: '', NOSTR: '', }, nplurals: _nplurals2a, } locales.en_US = copyValue(locales.en) locales.en_US.LC_TIME.c = '%a %d %b %Y %r %Z' locales.en_US.LC_TIME.x = '%D' locales.en_US.LC_TIME.X = '%r' locales.en_US.LC_MONETARY.int_curr_symbol = 'USD ' locales.en_US.LC_MONETARY.p_sign_posn = 1 locales.en_US.LC_MONETARY.n_sign_posn = 1 locales.en_US.LC_MONETARY.mon_grouping = [3, 3] locales.en_US.LC_NUMERIC.thousands_sep = '' locales.en_US.LC_NUMERIC.grouping = []
locales.en_GB = copyValue(locales.en) locales.en_GB.LC_TIME.r = '%l:%M:%S %P %Z'
locales.en_AU = copyValue(locales.en_GB) locales.C = copyValue(locales.en) locales.C.LC_CTYPE.CODESET = 'ANSI_X3.4-1968' locales.C.LC_MONETARY = { int_curr_symbol: '', currency_symbol: '', mon_decimal_point: '', mon_thousands_sep: '', mon_grouping: [], p_cs_precedes: 127, p_sep_by_space: 127, n_cs_precedes: 127, n_sep_by_space: 127, p_sign_posn: 127, n_sign_posn: 127, positive_sign: '', negative_sign: '', int_frac_digits: 127, frac_digits: 127, } locales.C.LC_NUMERIC = { decimal_point: '.', thousands_sep: '', grouping: [], } locales.C.LC_TIME.c = '%a %b %e %H:%M:%S %Y' locales.C.LC_TIME.x = '%m/%d/%y' locales.C.LC_TIME.X = '%H:%M:%S' locales.C.LC_MESSAGES.YESEXPR = '^[yY]' locales.C.LC_MESSAGES.NOEXPR = '^[nN]'
locales.fr = copyValue(locales.en) locales.fr.nplurals = _nplurals2b locales.fr.LC_TIME.a = ['dim', 'lun', 'mar', 'mer', 'jeu', 'ven', 'sam'] locales.fr.LC_TIME.A = ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'] locales.fr.LC_TIME.b = [ 'jan', 'f\u00E9v', 'mar', 'avr', 'mai', 'jun', 'jui', 'ao\u00FB', 'sep', 'oct', 'nov', 'd\u00E9c', ] locales.fr.LC_TIME.B = [ 'janvier', 'f\u00E9vrier', 'mars', 'avril', 'mai', 'juin', 'juillet', 'ao\u00FBt', 'septembre', 'octobre', 'novembre', 'd\u00E9cembre', ] locales.fr.LC_TIME.c = '%a %d %b %Y %T %Z' locales.fr.LC_TIME.p = ['', ''] locales.fr.LC_TIME.P = ['', ''] locales.fr.LC_TIME.x = '%d.%m.%Y' locales.fr.LC_TIME.X = '%T'
locales.fr_CA = copyValue(locales.fr) locales.fr_CA.LC_TIME.x = '%Y-%m-%d' } let currentLocale = getPhpRuntimeString('locale', '') if (!currentLocale) { currentLocale = 'en_US' if (typeof window !== 'undefined' && window.document) { const d = window.document const NS_XHTML = 'https://www.w3.org/1999/xhtml' const NS_XML = 'https://www.w3.org/XML/1998/namespace' const htmlNsElement = d.getElementsByTagNameNS ? d.getElementsByTagNameNS(NS_XHTML, 'html')[0] : undefined if (htmlNsElement) { const xmlLang = htmlNsElement.getAttributeNS(NS_XML, 'lang') if (xmlLang) { currentLocale = xmlLang } else { const htmlLang = htmlNsElement.getAttribute('lang') if (htmlLang) { currentLocale = htmlLang } } } else { const htmlElement = d.getElementsByTagName('html')[0] const htmlLang = htmlElement?.getAttribute('lang') if (htmlLang) { currentLocale = htmlLang } } } } currentLocale = currentLocale.replace('-', '_') if (!(currentLocale in locales)) { const languageLocale = currentLocale.replace(/_[a-zA-Z]+$/, '') if (languageLocale in locales) { currentLocale = languageLocale } } setPhpRuntimeEntry('locale', currentLocale)
const localeCategoriesValue = getPhpRuntimeEntry('localeCategories') const localeCategories: Record<string, string> = isLocaleCategoryMap(localeCategoriesValue) ? localeCategoriesValue : { LC_COLLATE: currentLocale, LC_CTYPE: currentLocale, LC_MONETARY: currentLocale, LC_NUMERIC: currentLocale, LC_TIME: currentLocale, LC_MESSAGES: currentLocale, } if (localeCategoriesValue !== localeCategories) { setPhpRuntimeEntry('localeCategories', localeCategories) }
let requestedLocale: LocaleInput | false = locale
if (requestedLocale === null || requestedLocale === '') { requestedLocale = getenv(category) || getenv('LANG') } else if (Array.isArray(requestedLocale)) { for (i = 0; i < requestedLocale.length; i++) { const candidate = requestedLocale[i] if (typeof candidate !== 'string') { if (i === requestedLocale.length - 1) { return false } continue } if (!(candidate in locales)) { if (i === requestedLocale.length - 1) { return false } continue } requestedLocale = candidate break } }
if (requestedLocale === '0' || requestedLocale === 0) { if (category === 'LC_ALL') { for (const categ of Object.keys(localeCategories)) { cats.push(categ + '=' + localeCategories[categ]) } return cats.join(';') } return localeCategories[category] ?? false }
if (typeof requestedLocale !== 'string' || !(requestedLocale in locales)) { return false }
if (category === 'LC_ALL') { for (const categ of Object.keys(localeCategories)) { localeCategories[categ] = requestedLocale } } else { localeCategories[category] = requestedLocale }
return requestedLocale }
type StrptimeResult = { tm_sec: number tm_min: number tm_hour: number tm_mday: number tm_mon: number tm_year: number tm_wday: number tm_yday: number unparsed: string }
type LcTime = { a: string[] A: string[] b: string[] B: string[] c: string r: string x: string X: string [key: string]: string | string[] | undefined }
type NumericResultKey = Exclude<keyof StrptimeResult, 'unparsed'>
const isStringArray = (value: PhpAssoc<PhpInput>, key: string): boolean => { const candidate = value[key] return Array.isArray(candidate) && candidate.every((item) => typeof item === 'string') }
const isLcTime = (value: PhpAssoc<PhpInput>): value is LcTime => isStringArray(value, 'a') && isStringArray(value, 'A') && isStringArray(value, 'b') && isStringArray(value, 'B') && typeof value.c === 'string' && typeof value.r === 'string' && typeof value.x === 'string' && typeof value.X === 'string'
function strptime(dateStr: string, format: string): StrptimeResult | false {
const retObj: StrptimeResult = { tm_sec: 0, tm_min: 0, tm_hour: 0, tm_mday: 0, tm_mon: 0, tm_year: 0, tm_wday: 0, tm_yday: 0, unparsed: '', } let i = 0 let j = 0 let amPmOffset = 0 let prevHour = false const _reset = function (dateObj: Date, realMday: number): void { const o = retObj const d = dateObj o.tm_sec = d.getUTCSeconds() o.tm_min = d.getUTCMinutes() o.tm_hour = d.getUTCHours() o.tm_mday = realMday === 0 ? realMday : d.getUTCDate() o.tm_mon = d.getUTCMonth() o.tm_year = d.getUTCFullYear() - 1900 o.tm_wday = realMday === 0 ? (d.getUTCDay() > 0 ? d.getUTCDay() - 1 : 6) : d.getUTCDay() const jan1 = new Date(Date.UTC(d.getUTCFullYear(), 0, 1)) o.tm_yday = Math.ceil((d.getTime() - jan1.getTime()) / (1000 * 60 * 60 * 24)) } const _date = function (): void { const o = retObj _reset(new Date(Date.UTC(o.tm_year + 1900, o.tm_mon, o.tm_mday || 1, o.tm_hour, o.tm_min, o.tm_sec)), o.tm_mday) }
const _NWS = /\S/ const _WS = /\s/
const _aggregates: Record<string, string> = { c: 'locale', D: '%m/%d/%y', F: '%y-%m-%d', r: 'locale', R: '%H:%M', T: '%H:%M:%S', x: 'locale', X: 'locale', }
const _pregQuote = function (str: string): string { return str.replace(/([\\.+*?[^\]$(){}=!<>|:])/g, '\\$1') }
setlocale('LC_ALL', 0) const lcTimeGroup = getPhpLocaleGroup('LC_TIME', 'LC_TIME') if (!lcTimeGroup || !isLcTime(lcTimeGroup)) { return false } const lcTime = lcTimeGroup
while (/%[cDFhnrRtTxX]/.test(format)) { format = format.replace(/%([cDFhnrRtTxX])/g, function (_m0, m1: string) { const f = _aggregates[m1] if (f === undefined) { return m1 } return f === 'locale' ? String(lcTime[m1] ?? '') : f }) }
const _addNext = function ( index: number, regex: RegExp | string, cb: (...matches: string[]) => number | null | void, ): number { const pattern = typeof regex === 'string' ? new RegExp('^' + regex, 'i') : regex const check = dateStr.slice(index) const match = pattern.exec(check) if (!match) { throw new Error('No match in string') } const testNull = cb(...match) if (testNull === null) { throw new Error('No match in string') } return index + match[0].length }
const _addLocalized = function ( index: number, formatChar: 'a' | 'A' | 'b' | 'B', category: NumericResultKey, ): number { const localized = lcTime[formatChar] if (!Array.isArray(localized)) { throw new Error('No match in string') } return _addNext(index, localized.map((entry) => _pregQuote(entry)).join('|'), function (m) { const matchIndex = localized.findIndex((entry) => new RegExp('^' + _pregQuote(m) + '$', 'i').test(entry)) if (matchIndex === -1) { return null } retObj[category] = matchIndex return matchIndex }) }
for (i = 0, j = 0; i < format.length; i++) { if (format.charAt(i) === '%') { const literalPos = ['%', 'n', 't'].indexOf(format.charAt(i + 1)) if (literalPos !== -1) { if (['%', '\n', '\t'].indexOf(dateStr.charAt(j)) === literalPos) { ++i ++j continue } return false } const formatChar = format.charAt(i + 1) try { switch (formatChar) { case 'a': case 'A': j = _addLocalized(j, formatChar, 'tm_wday') break case 'h': case 'b': j = _addLocalized(j, 'b', 'tm_mon') _date() break case 'B': j = _addLocalized(j, formatChar, 'tm_mon') _date() break case 'C': j = _addNext(j, /^\d?\d/, function (d) { const year = (Number.parseInt(d, 10) - 19) * 100 retObj.tm_year = year _date() if (!retObj.tm_yday) { retObj.tm_yday = -1 } }) break case 'd': case 'e': j = _addNext(j, formatChar === 'd' ? /^(0[1-9]|[1-2]\d|3[0-1])/ : /^([1-2]\d|3[0-1]|[1-9])/, function (d) { const dayMonth = Number.parseInt(d, 10) retObj.tm_mday = dayMonth _date() }) break case 'g': break case 'G': break case 'H': j = _addNext(j, /^([0-1]\d|2[0-3])/, function (d) { const hour = Number.parseInt(d, 10) retObj.tm_hour = hour }) break case 'l': case 'I': j = _addNext(j, formatChar === 'l' ? /^([1-9]|1[0-2])/ : /^(0[1-9]|1[0-2])/, function (d) { const hour = Number.parseInt(d, 10) - 1 + amPmOffset retObj.tm_hour = hour prevHour = true }) break case 'j': j = _addNext(j, /^(00[1-9]|0[1-9]\d|[1-2]\d\d|3[0-6][0-6])/, function (d) { const dayYear = Number.parseInt(d, 10) - 1 retObj.tm_yday = dayYear }) break case 'm': j = _addNext(j, /^(0[1-9]|1[0-2])/, function (d) { const month = Number.parseInt(d, 10) - 1 retObj.tm_mon = month _date() }) break case 'M': j = _addNext(j, /^[0-5]\d/, function (d) { const minute = Number.parseInt(d, 10) retObj.tm_min = minute }) break case 'P': return false case 'p': j = _addNext(j, /^(am|pm)/i, function (d) { amPmOffset = /a/.test(d) ? 0 : 12 if (prevHour) { retObj.tm_hour += amPmOffset } }) break case 's': j = _addNext(j, /^\d+/, function (d) { const timestamp = Number.parseInt(d, 10) const date = new Date(Date.UTC(timestamp * 1000)) _reset(date, retObj.tm_mday) }) break case 'S': j = _addNext( j, /^[0-5]\d/, function (d) { const second = Number.parseInt(d, 10) retObj.tm_sec = second }, ) break case 'u': case 'w': j = _addNext(j, /^\d/, function (d) { retObj.tm_wday = Number(d) - (formatChar === 'u' ? 1 : 0) }) break case 'U': case 'V': case 'W': break case 'y': j = _addNext(j, /^\d?\d/, function (d) { const parsed = Number.parseInt(d, 10) const year = parsed >= 69 ? parsed : parsed + 100 retObj.tm_year = year _date() if (!retObj.tm_yday) { retObj.tm_yday = -1 } }) break case 'Y': j = _addNext(j, /^\d{1,4}/, function (d) { const year = Number.parseInt(d, 10) - 1900 retObj.tm_year = year _date() if (!retObj.tm_yday) { retObj.tm_yday = -1 } }) break case 'z': break case 'Z': break default: throw new Error('Unrecognized formatting character in strptime()') } } catch (error) { if (error instanceof Error && error.message === 'No match in string') { return false } } ++i } else if (format.charAt(i) !== dateStr.charAt(j)) {
if (_WS.test(dateStr.charAt(j))) { j++ i-- } else if (_NWS.test(format.charAt(i))) { return false } } else { j++ } }
retObj.unparsed = dateStr.slice(j) return retObj }
|