
开发工具【免费下载链接】luxon⏱ A library for working with dates and times in JS项目地址https://gitcode.com/gh_mirrors/lu/luxon点击查看免费下载Luxon 是一款面向 JavaScript 的日期时间处理库其解析能力覆盖两大类场景一类是 ISO 8601、RFC 2822、HTTP 头、SQL 与 Unix 时间戳等技术格式的直接解析另一类是通过fromFormat按自定义 token 模板进行的临时解析。本文以官方文档 docs/parsing.md 为骨架结合 src/datetime.js、src/impl/regexParser.js、src/impl/tokenParser.js 等源码实现系统讲解 Luxon 的解析 API、行为细节、局限性以及调试方法读完即可在项目中正确选用解析入口并解决解析结果无效的问题。Luxon 解析的定位与总体能力Luxon 官方文档开篇即明确其定位Luxon is not an NLP tool and isnt suitable for all date parsing jobs. But it can do some parsing.Luxon 不是 NLP 工具并不适合所有日期解析任务但它确实能做一部分解析。具体包含两类技术格式解析对若干广为人知的格式提供直接支持其中覆盖了绝大多数合法 ISO 8601 格式临时解析ad-hoc parsing针对特定自定义格式按格式串进行逐 token 解析。从源码结构看这两条路径的实现是分离的技术格式解析集中在 src/impl/regexParser.js通过正则 提取器extractor逐条尝试匹配而自定义格式解析则由 src/impl/tokenParser.js 中的TokenParser类把格式串编译为正则后执行匹配。理解这一点有助于判断何时选用哪一类 API。解析技术格式ISO 8601DateTime.fromISODateTime.fromISO是使用频率最高的解析入口其实现位于 src/datetime.js内部先调用parseISODate定义于 src/impl/regexParser.js完成字符串到字段值的转换再交给parseDataToDateTime组装为DateTime实例DateTime.fromISO(2016-05-25);以下字符串格式均可由fromISO解析2016 2016-05 201605 2016-05-25 20160525 2016-05-25T09 2016-05-25T09:24 2016-05-25T09:24:15 2016-05-25T09:24:15.123 2016-05-25T0924 2016-05-25T092415 2016-05-25T092415.123 2016-05-25T09:24:15,123 2016-W21-3 2016W213 2016-W21-3T09:24:15.123 2016W213T09:24:15.123 2016-200 2016200 2016-200T09:24:15.123 09:24 09:24:15 09:24:15.123 09:24:15,123可以看到fromISO不仅支持标准的年-月-日与时分秒还支持压缩格式如20160525、2016W213、ISO 周历2016-W21-3即 2016 年第 21 周的星期三、序数日期2016-200即 2016 年的第 200 天以及只含时间部分的字符串。从 src/impl/regexParser.js 的正则定义可以看出parseISODate依次尝试年月日时间扩展周历时间扩展序数日期时间扩展纯时间四组模式匹配顺序即优先级。使用时有三个必须记住的行为约定所有时间都支持偏移参数例如ZUTC和06:00。底层正则offsetRegexsrc/impl/regexParser.js同时接受Z/z与±hh:mm或±hhmm形式。缺失的低阶值一律取最小值fromISO总是解析成一个完整的DateTime。例如2016-05-25解析为该日午夜2016-05解析为该月 1 日零点。这由提取器中的默认值逻辑保证如extractISOYmd中缺失的月份和日期默认取 1src/impl/regexParser.jsextractISOTime中时分秒默认取 0src/impl/regexParser.js。未指定偏移时按本地时间解析但可以通过 options 调整。fromISO支持的选项见 src/datetime.js包括zone默认local当字符串本身未含偏移时使用该时区解释时间并会把结果转换到该时区setZone默认false为true时若字符串本身指定了偏移则结果使用该固定偏移时区而非转换到zonelocale设置结果实例的 localeoutputCalendar、numberingSystem、weekSettings分别控制输出日历、数字系统和周设置。时区相关的更多细节可参考 docs/zones.md。HTTP 与 RFC 2822Luxon 还提供针对 RFC 2822 与 HTTP 头日期规范RFC 850 和 RFC 1123的解析DateTime.fromRFC2822(Tue, 01 Nov 2016 13:23:12 0630); DateTime.fromHTTP(Sunday, 06-Nov-94 08:49:37 GMT); DateTime.fromHTTP(Sun, 06 Nov 1994 08:49:37 GMT);DateTime.fromRFC2822src/datetime.js内部调用parseRFC2822Date。其底层正则rfc2822要求可选星期缩写、日、英文月份缩写、2~4 位年份、时:分(:秒)以及UT/GMT/[ECMP][SD]T缩写、Z或±hhmm数值偏移之一src/impl/regexParser.js。解析前还会做预处理去掉注释与折叠空白、将连续多个空格合并为单个空格src/impl/regexParser.js。DateTime.fromHTTPsrc/datetime.js内部调用parseHTTPDate依次尝试 RFC 1123Sun, 06 Nov 1994 08:49:37 GMT、RFC 850Sunday, 06-Nov-94 08:49:37 GMT与 asctimeSun Nov 6 08:49:37 1994三种形式src/impl/regexParser.js。由于 HTTP 日期总是 UTC解析结果会被赋予FixedOffsetZone.utcInstance。这两个方法的opts与fromISO类似因为字符串中总是携带偏移zone选项只影响结果表达所在的时区不影响时间本身的解释setZone对 HTTP 日期而言等效于把zone设为utc。SQLDateTime.fromSQLfromSQL用于解析 SQL 日期、时间与日期时间同样可以携带毫秒、偏移或 IANA 时区名DateTime.fromSQL(2017-05-15); DateTime.fromSQL(2017-05-15 09:24:15); DateTime.fromSQL(09:24:15);其行为与fromISO高度相似因此缺失值取最小值无偏移按本地时间等约定同样适用。从源码看parseSQLsrc/impl/regexParser.js使用了比 ISO 更严格的日期正则sqlYmdRegex /(\d{4})-(\d\d)-(\d\d)/必须补零的简化版 ISOsrc/impl/regexParser.js同时允许时间部分后跟空格 偏移或 IANA 时区名。fromSQL的完整示例还包括带毫秒与带时区的形式DateTime.fromSQL(2017-05-15 09:12:34.34206:00); DateTime.fromSQL(2017-05-15 09:12:34.342 America/Los_Angeles); DateTime.fromSQL(2017-05-15 09:12:34.342, { zone: America/Los_Angeles });Unix 时间戳Luxon 可直接解析数值型 Unix 时间戳自 1970-01-01 00:00:00 UTC 起经过的毫秒或秒DateTime.fromMillis(1542674993410); DateTime.fromSeconds(1542674993);两个方法接受相同的一组选项zone、locale、outputCalendar、numberingSystem、weekSettings见 src/datetime.js 与 src/datetime.js。实现细节上fromMillis会校验入参必须是数字且绝对值不得超过内部常量MAX_DATE否则返回invalid(Timestamp out of range)src/datetime.jsfromSeconds在内部把秒乘以 1000 后当作毫秒时间戳处理src/datetime.js。原生 JS Date 对象原生Date实例可以借助DateTime.fromJSDate转换为DateTimeconst dt DateTime.fromJSDate(new Date());可选参数zone用于设置结果对象所处的时区src/datetime.js。实现上它会校验入参必须是Date否则返回invalid(invalid input)随后取date.valueOf()作为时间戳并应用normalizeZone(options.zone, Settings.defaultZone)归一化时区。Ad-hoc 解析自定义格式先考虑替代方案文档强调一般情况下不应该用 Luxon 解析任意格式的日期字符串原因有二如果字符串是程序生成、供程序读取的应优先使用 ISO 8601 这类标准格式然后交给DateTime.fromISO如果字符串是人类手工输入的它很可能不符合你指定的格式——Luxon 对格式必须与字符串严格匹配这一点非常严格。但现实中你有时会从遗留系统拿到某种糟糕的临时格式字符串此时就需要fromFormat这类临时解析手段。fromFormat按格式串解析fromFormat的方法签名以 src/datetime.js 为准基本用法如下DateTime.fromFormat(May 25 1982, LLLL dd yyyy);其调用链是先通过Locale.fromOpts确定 locale默认en-US与系统 locale 无关然后调用parseFromTokenssrc/impl/tokenParser.js把格式串编译为正则并执行匹配最后同样经由parseDataToDateTime生成实例。若text或fmt缺失会抛出InvalidArgumentError。需要注意传入格式串中的普通字符会被当作字面量匹配token 解析器会对其做正则转义见escapeTokensrc/impl/tokenParser.js也可以用单引号...显式包裹一段非 token 文本旧版本中的DateTime.fromString已标记为 deprecated等价于fromFormatsrc/datetime.js若把h12 小时制与H24 小时制混用会抛出ConflictingSpecificationError使用h的同时若指定了ameridiem小时必须落在 [1, 12] 区间内否则结果为无效相关校验见 src/impl/tokenParser.js并有对应测试用例位于 test/datetime/tokenParse.test.js。Intl 国际化解析Luxon 支持解析国际化字符串例如用法语解析月份名DateTime.fromFormat(mai 25 1982, LLLL dd yyyy, { locale: fr });这里有一个必须理解的机制Luxon 通过内省运行环境的 Intl 实现来推导LLLL这类 token 可匹配的字符串列表及其含义对应源码中unitForToken对MMMM/LLLL调用loc.months(...)src/impl/tokenParser.jsoneOf辅助函数会把本地化名称列表拼装成正则src/impl/tokenParser.js。因此具体能匹配到哪些字符串在部分环境下可能与环境相关目标平台必须提供 Intl API参见 docs/matrix.md 中的支持矩阵。解析器的局限性并非所有DateTime#toFormat支持的 token 都能用于解析例如不存在ZZZZ如 PST和ZZZZZ如 Pacific Standard Timetoken。文档给出了三条理由源码注释src/impl/tokenParser.js与之一致方向性限制Luxon 依赖原生能力该能力只提供单向映射——可以问当前命名偏移是什么得到 Eastern Standard Time却无法反向询问 Eastern Standard Time 最可能指什么。歧义问题世界上有多个不同国家的 Eastern Standard Time在缺少额外信息如America/New_York这样的 IANA 时区时无法确定含义同理适合日历图形展示的单字母月份/星期格式EEEEE也因歧义无法解析。连锁限制由于上述原因Luxon 也不支持包含偏移名称的宏 token如ttt与FFFF。可以从 src/impl/formatter.js 的macroTokenToFormatOpts表看到宏 token 的展开逻辑D/DD/DDD/DDDD、t/tt/T/TT、f/ff/F/FF等可以展开为普通 token 组合从而参与解析但凡是会展开出ZZZZ/ZZZZZttt、TTTT、fff、FFFF等的宏 token在解析时会因无法反向映射而被拒绝。解析两位年份当用yy或 ISO 周历年kk解析两位数字年份时必须依赖一个分界年cutoff year大于分界年的两位数字被解释为上世纪末小于等于分界年的被解释为本世纪初。默认分界年为 60即60解析为 2060 年61解析为 1961 年。分界年可通过Settings.twoDigitCutoffYear配置定义于 src/settings.jsSettings.twoDigitCutoffYear 50; // 49 - 2049; 50 - 1950 Settings.twoDigitCutoffYear 0; // 所有 yy 都被解释为 20 世纪 Settings.twoDigitCutoffYear 99; // 所有 yy 都被解释为 21 世纪源码细节值得注意setter 会做cutoffYear % 100取模src/settings.js因此传入1950或2050都会被当作50处理真正应用分界年的函数是untruncateYearsrc/impl/util.js逻辑为year Settings.twoDigitCutoffYear ? 1900 year : 2000 year即严格大于分界年的数字归属 19xx小于等于的归属 20xxyy还接受 4 位输入从源码看yy走twoToFour正则2~4 位数字若输入本身已是 4 位则不再做世纪换算。测试 test/datetime/tokenParse.test.js 验证了默认分界年与自定义分界年的行为。调试fromFormatExplain解析出错通常有两种原因a) token 用错格式串与字符串不匹配b) 字符串解析出的信息不是合法日期。为帮助定位Luxon 提供fromFormatExplain——它接受与fromFormat相同的参数但返回解析过程的信息地图实现见 src/datetime.js核心逻辑explainFromTokens在 src/impl/tokenParser.js。场景一token 用错。下面代码在需要MMM的地方用了MMMM可以看到 Luxon 生成的正则以及什么都没匹配上的事实 DateTime.fromFormatExplain(Aug 6 1982, MMMM d yyyy) { input: Aug 6 1982, tokens: [ { literal: false, val: MMMM }, { literal: false, val: }, { literal: false, val: d }, { literal: false, val: }, { literal: false, val: yyyy } ], regex: (January|February|March|April|May|June|July|August|September|October|November|December)( )(\\d\\d?)( )(\\d{4}), matches: {}, result: {}, zone: null }matches为空对象说明字符串没有命中正则August才能命中MMMM而Aug不行。场景二解析成功但日期非法。例如尝试解析不存在的 8 月 32 日var d DateTime.fromFormat(August 32 1982, MMMM d yyyy); d.isValid; // false d.invalidReason; // day out of range此时再运行fromFormatExplain输出要丰富得多可以看到 day 字段确实被解析成了 32 DateTime.fromFormatExplain(August 32 1982, MMMM d yyyy) { input: August 32 1982, tokens: [ { literal: false, val: MMMM }, { literal: false, val: }, { literal: false, val: d }, { literal: false, val: }, { literal: false, val: yyyy } ], regex: (January|February|March|April|May|June|July|August|September|October|November|December)( )(\\d\\d?)( )(\\d{4}), matches: { M: 8, d: 32, y: 1982 }, result: { month: 8, day: 32, year: 1982 }, zone: null }结合上面的invalidReason: day out of range问题一目了然字符串本身合法、token 也正确是日期值超出范围。关于有效性validity的更全面排查技巧参见 docs/validity.md。进阶解析性能优化。与调试相关的还有两个较新的 API见 src/datetime.jsDateTime.buildFormatParser(fmt, options)可预先为某格式编译一个TokenParser实例DateTime.fromFormatParser(text, formatParser, opts)复用该实例批量解析大量同格式字符串从而避免重复编译正则适合日志清洗等高频解析场景。Token 对照表下表给出fromFormat支持的解析 token示例取值基于2014-08-06T13:07:04.054按America/New_York本地时间考虑。注意格式化器formatter支持的大量 token 解析器并不支持具体差异以本表为准。格式化侧的完整 token 说明见 docs/formatting.md。Standalone tokenFormat tokenDescriptionExampleSmillisecond, no padding54SSSmillisecond, padded to 3054ufractional seconds, (5 is a half second, 54 is slightly more)54uufractional seconds, (one or two digits)05uuufractional seconds, (only one digit)5ssecond, no padding4sssecond, padded to 2 padding04mminute, no padding7mmminute, padded to 207hhour in 12-hour time, no padding1hhhour in 12-hour time, padded to 201Hhour in 24-hour time, no padding13HHhour in 24-hour time, padded to 213Znarrow offset5ZZshort offset05:00ZZZtechie offset0500zIANA zoneAmerica/New_YorkameridiemAMdday of the month, no padding6ddday of the month, padded to 206cEday of the week, as number from 1-7 (Monday is 1, Sunday is 7)3cccEEEday of the week, as an abbreviate localized stringWedccccEEEEday of the week, as an unabbreviated localized stringWednesdayLMmonth as an unpadded number8LLMMmonth as an padded number08LLLMMMmonth as an abbreviated localized stringAugLLLLMMMMmonth as an unabbreviated localized stringAugustyyear, 1-6 digits, very literally2014yytwo-digit year, interpreted as 1960 by default (also accepts 4)14yyyyfour-digit year2014yyyyyfour- to six-digit years10340yyyyyysix-digit years010340Gabbreviated localized eraADGGunabbreviated localized eraAnno DominiGGGGGone-letter localized eraAkkISO week year, unpadded17kkkkISO week year, padded to 42014WISO week number, unpadded32WWISO week number, padded to 232oordinal (day of year), unpadded218oooordinal (day of year), padded to 3218qquarter, no padding3Dlocalized numeric date9/6/2014DDlocalized date with abbreviated monthAug 6, 2014DDDlocalized date with full monthAugust 6, 2014DDDDlocalized date with full month and weekdayWednesday, August 6, 2014tlocalized time1:07 AMttlocalized time with seconds1:07:04 PMTlocalized 24-hour time13:07TTlocalized 24-hour time with seconds13:07:04fshort localized date and time8/6/2014, 1:07 PMffless short localized date and timeAug 6, 2014, 1:07 PMFshort localized date and time with seconds8/6/2014, 1:07:04 PMFFless short localized date and time with secondsAug 6, 2014, 1:07:04 PMliteral start/end, characters between are not tokenizedT几点补充说明均可从 src/impl/tokenParser.js 的unitForToken实现得到印证S/SSS/u/uu/uuu都用于毫秒与秒的小数部分u系列按简单字符串捕获simpleuuu只允许一位数字S支持 1~3 位SSS强制 3 位偏移 token 中Z/ZZ匹配±hh(:mm)?形式ZZZ匹配±hhmm形式z则按 IANA 时区名的正则捕获/[a-z_-/]{1,256}?/i解析结果中若同时出现zIANA 时区会优先采用仅出现Z时使用FixedOffsetZone见dateTimeFromMatchessrc/impl/tokenParser.jsq季度token 在解析后会换算为起始月份(q-1)*31src/impl/tokenParser.js形如D、t、f、F等宏 token 会先经expandMacroTokens展开成普通 token 序列再匹配src/impl/tokenParser.js。小结Luxon 的解析体系可以总结为两条路径、一个原则两条路径技术格式ISO 8601 / RFC 2822 / HTTP / SQL / Unix 时间戳 / JS Date走fromISO、fromRFC2822、fromHTTP、fromSQL、fromMillis、fromSeconds、fromJSDate等专用入口内部由 src/impl/regexParser.js 的正则提取器驱动自定义格式走fromFormat内部由 src/impl/tokenParser.js 的TokenParser编译执行。一个原则能用标准格式就用标准格式非用自定义格式不可时牢记严格匹配token 支持范围有限两位年份受Settings.twoDigitCutoffYear控制并用fromFormatExplain快速定位 token 错误与非法日期两类问题。理解了这些行为约定与底层机制后无论面对日志时间戳、HTTP 响应头还是遗留系统的古怪字符串你都能为解析任务选对入口、写对格式串、查清无效原因。赞分享开发工具【免费下载链接】luxon⏱ A library for working with dates and times in JS项目地址https://gitcode.com/gh_mirrors/lu/luxon点击查看免费下载相关推荐Angular 自定义元素实战用 angular/elements 将组件打包为 Web ComponentsAngular 自定义元素实战用 angular/elements 将组件打包为 Web Components angular/elements 实现了开发工具Classic Shell 开始菜单自定义完整指南免费开源三分钟找回经典操作手感Classic Shell 开始菜单自定义完整指南免费开源三分钟找回经典操作手感 把工作电脑升级到 Windows 10 的第一天我花了将近一分钟才在开始Luxon日期时间格式化全指南从基础到高级应用Luxon日期时间格式化全指南从基础到高级应用 一、格式化概述 在Luxon日期时间库中格式化功能是将DateTime对象转换为可读字符串的核心能力。根据使开发工具上一篇CANN/asc-devkit atanhf函数文档下一篇Tornado httputil 模块深入解析HTTP 头部与 URL 操作实用工具全指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考