d3 时间格式化完全指南:d3-time-format 的 strftime/strptime 指令、解析器与 Locale 定制

发布时间:2026/9/7 17:40:33
d3 时间格式化完全指南:d3-time-format 的 strftime/strptime 指令、解析器与 Locale 定制 d3 时间格式化完全指南d3-time-format 的 strftime/strptime 指令、解析器与 Locale 定制【免费下载链接】d3Bring data to life with SVG, Canvas and HTML. :bar_chart::chart_with_upwards_trend::tada:项目地址: https://gitcode.com/GitHub_Trending/d3/d3本篇基于 D3 官方文档 d3-time-format 模块说明 展开系统讲解该模块提供的 strftime/strptime 近似实现如何用d3.timeFormat/d3.timeParse/d3.utcFormat/d3.utcParse在日期对象与字符串之间双向转换如何完整掌握 30 余种格式指令与填充修饰符以及如何通过d3.timeFormatLocale/d3.timeFormatDefaultLocale定制国际化时间表示。读完后你既能写出多尺度自适应时间格式D3 时间轴刻度标签的底层原理也能为图表配置自定义语言环境下的日期解析。模块定位JavaScript 中的 strftime 与 strptimed3-time-format 是 D3 生态中负责时间 ↔ 字符串转换的独立模块它的目标是提供 C 标准库中久经考验的 strptime 和 strftime 函数的 JavaScript 近似实现支持将 Date 对象格式化为各种本地化locale-specific的字符串表示以及反向从字符串解析出日期。在当前 D3 仓库d37.9.0见 package.json中d3-time-format以^4.1.0版本作为独立依赖声明并由聚合入口 src/index.js 通过export * from d3-time-format统一导出因此d3.timeFormat、d3.utcParse、d3.isoFormat等 API 均可直接在全局d3命名空间下使用。使用模式分为两条基本链路格式化format从格式指令串创建格式化器传入 Date 得到字符串解析parse从同一指令串创建解析器传入字符串得到 Date 或null。// 格式化Date - 字符串 const formatTime d3.utcFormat(%B %d, %Y); formatTime(new Date()); // May 31, 2023 // 解析字符串 - Date const parseTime d3.utcParse(%B %d, %Y); parseTime(June 30, 2015); // 2023-05-31值得注意的是模块内区分timeFormat本地时区与utcFormatUTC 时区两套对称 API。由于浏览器本地时区不可控官方在 d3-scale 时间刻度文档中建议尽可能优先使用 UTC 变体——UTC 下每一天恒为 24 小时且行为不依赖浏览器时区结果更可预测。这与 d3-time 模块文档中本模块仅工作在本地时区与 UTC 之下的设计边界是一致的。四大顶层 APItimeFormat、timeParse、utcFormat、utcParse文档将四个顶层函数定义为对默认 locale上对应方法的别名aliasAPI等价于时区语义d3.timeFormat(specifier)locale.format本地时间d3.timeParse(specifier)locale.parse本地时间d3.utcFormat(specifier)locale.utcFormatUTC 时间d3.utcParse(specifier)locale.utcParseUTC 时间d3.timeFormat(%b %d) // 本地时间格式化器 d3.timeParse(%b %d) // 本地时间解析器 d3.utcFormat(%b %d) // UTC 格式化器 d3.utcParse(%b %d) // UTC 解析器四个函数共享同一套格式指令下文详述差别仅在于各指令解释 Date 时使用的时区本地时间版本调用date.getMonth()、date.getHours()等本地 getterUTC 版本则调用getUTCMonth()、getUTCHours()等。因此对同一 Date 对象%d、%H、%m等指令在本地版本与 UTC 版本下可能产出不同字符串尤其是跨越时区边界时。*locale*.utcFormat与*locale*.utcParse的语义在文档中明确为与本地版本等价只是所有指令按协调世界时UTC而非本地时间解释。这意味着指令串本身在本地/UTC 两套 API 间完全通用切换 API 即可切换时区语义无需改动 specifier。完整格式指令参考表locale.formatlocale.format(specifier)返回一个新的格式化函数specifier 是包含以%开头的指令directive的字符串。以下是文档给出的完整指令表其中带*的指令会受 locale 定义影响指令含义%a*星期缩写abbreviated weekday name%A*星期全称full weekday name%b*月份缩写abbreviated month name%B*月份全称full month name%c*该 locale 的日期与时间组合格式如%x, %X%d月份中的日零填充十进制[01,31]%e月份中的日空格填充[ 1,31]等价于%_d%f微秒十进制[000000, 999999]%gISO 8601 周纪年不带世纪十进制[00,99]%GISO 8601 周纪年带世纪十进制%H小时24 小时制十进制[00,23]%I小时12 小时制十进制[01,12]%j年中的第几天十进制[001,366]%m月份十进制[01,12]%M分钟十进制[00,59]%L毫秒十进制[000, 999]%p*AM 或 PM%q年第几季度十进制[1,4]%Q自 UNIX 纪元起经过的毫秒数%s自 UNIX 纪元起经过的秒数%S秒十进制[00,61]含闰秒上限%u以周一为首ISO 8601的星期十进制[1,7]%U以周日为首的周序号十进制[00,53]%VISO 8601 周序号十进制[01, 53]%w以周日为首的星期十进制[0,6]%W以周一为首的周序号十进制[00,53]%x*该 locale 的日期格式如%-m/%-d/%Y%X*该 locale 的时间格式如%-I:%M:%S %p%y年份不带世纪十进制[00,99]%Y年份带世纪如1999%Z时区偏移如-0700、-07:00、-07或Z%%字面量百分号%周序号的三种口径%U / %W / %V文档对周序号的边界规则做了专门说明%U以周日为周首。新年中第一个周日之前的所有天都算第 0 周%W以周一为周首。新年中第一个周一之前的所有天都算第 0 周两者的周号计算均基于 d3-time 的interval.count。举例2015-52 与 2016-00 同时指向 2015 年 12 月 28 日周一而 2015-53 与 2016-01 指向 2016 年 1 月 4 日周一%V / %g / %G则遵循 strftime man page 的 ISO 周定义在该系统中周从周一开始编号从第一周的 01 直到最后一周的 52 或 53。第 1 周是新年中首个满足至少 4 天落在新年内的周同义表述第 1 周是包含星期四的第一个周或等价于包含 1 月 4 日的那一周。若 ISO 周号归属于上一年或下一年则使用那一年作为年份。也就是说%V的周号与%g/%G的周纪年是配套的%V给出周号时%G/%g给出该 ISO 周所属的年份可能与%Y不同。仓库的 CHANGES.md 记录了这一特性的引入历史%G与%gISO 8601 week year是在 5.0 版本中为 d3-time-format 新增的指令。填充修饰符0、_、-%指示符后可以紧跟一个填充修饰符修饰符含义0零填充zero-padding_空格填充space-padding-禁用填充disable padding若不指定修饰符默认是所有指令默认为0零填充唯一例外是%e默认_空格填充。文档同时指出部分 strftime/strptime 实现支持字段宽度或精度参数但 d3-time-format 尚未实现该特性。locale.format的返回值是格式化函数接收一个 Date 并返回对应字符串const formatMonth d3.timeFormat(%B), formatDay d3.timeFormat(%A), date new Date(2014, 4, 1); // Thu May 01 2014 00:00:00 GMT-0700 (PDT) formatMonth(date); // May formatDay(date); // Thursdaylocale.parse严格解析与 null 语义locale.parse(specifier)返回一个解析器接受字符串返回对应的 Date若字符串无法按该 specifier 精确匹配则返回null。几个关键规则解析时可使用与locale.format相同的指令集%d与%e在解析时被视为等价一个接受零填充、一个接受空格填充解析端不做区分解析是严格的字符串必须与 specifier 精确匹配。以%Y-%m-%dT%H:%M:%SZ为例2011-07-01T19:15:28Z→ 正常解析注意这里的Z是指令串中的字面字符与%Z指令不同2011-07-01T19:15:28、2011-07-01 19:15:28、2011-07-01→ 均返回null。如果需要更宽松的解析策略官方建议的顺序是依次尝试多个格式直到某个返回非 null 值try multiple formats sequentially。这是典型的多格式回退解析模式适用于来源格式不统一的 CSV/JSON 数据。ISO 8601 快捷通道isoFormat 与 isoParse除了通用指令系统模块还提供了一对完整的 ISO 8601 UTC 快捷方法d3.isoFormat(new Date()); // 2023-05-31T18:17:36.788Z d3.isoParse(2023-05-31T18:17:36.788Z); // Date 对象d3.isoFormat是完整 ISO 8601 UTC 格式化器可用时会走Date.toISOString快路径d3.isoParse是完整 ISO 8601 UTC 解析器可用时会直接交给 Date 构造函数。需要特别注意的是d3.isoParse不保证严格的 ISO 8601 校验——它可能接受一些不符合规范的输入。文档明确指出如果你依赖严格校验应自行构造 UTC 解析器const strictIsoParse d3.utcParse(%Y-%m-%dT%H:%M:%S.%LZ);实战多尺度自适应时间格式multi-scale time format文档给出的进阶用法是条件时间格式根据日期落在哪个时间粒度边界上选择不同的指令串。这是 D3 时间刻度默认刻度标签生成逻辑的同款模式时间刻度文档 中*time*.tickFormat的默认行为正是按 %Y / %B / %b %d / %a %d / %I %p / %I:%M / :%S / .%L 逐级选择。实现上多尺度格式组合了 d3-time 的时间区间intervalAPId3-time 文档 中的 d3.utcSecond、d3.utcMinute 等interval(date) date表示该区间边界早于 date即 date 携带了比该粒度更细的时间信息。const formatMillisecond d3.utcFormat(.%L), formatSecond d3.utcFormat(:%S), formatMinute d3.utcFormat(%I:%M), formatHour d3.utcFormat(%I %p), formatDay d3.utcFormat(%a %d), formatWeek d3.utcFormat(%b %d), formatMonth d3.utcFormat(%B), formatYear d3.utcFormat(%Y); function multiFormat(date) { return (d3.utcSecond(date) date ? formatMillisecond : d3.utcMinute(date) date ? formatSecond : d3.utcHour(date) date ? formatMinute : d3.utcDay(date) date ? formatHour : d3.utcMonth(date) date ? (d3.utcWeek(date) date ? formatDay : formatWeek) : d3.utcYear(date) date ? formatMonth : formatYear)(date); }这段代码的判定链自下而上逐级检查d3.utcSecond(date) date→ 秒内有毫秒成分 → 用.%L毫秒d3.utcMinute(date) date→ 分钟内有秒成分 → 用:%Sd3.utcHour(date) date→ 小时内有分钟成分 → 用%I:%Md3.utcDay(date) date→ 日内有时分成分 → 用%I %pd3.utcMonth(date) date且d3.utcWeek(date) date→ 落在周边界上 → 用%b %d周粒度否则落在日边界上 → 用%a %dd3.utcYear(date) date→ 落在月边界 → 用%B其余 → 落在年边界 → 用%Y。这种局部 全局上下文兼得的表示方式正是 D3 时间轴的招牌风格连续刻度被格式化为[11 PM, Mon 07, 01 AM]时读者能同时看到小时、星期和日期信息而不是三个孤立的小时[11 PM, 12 AM, 01 AM]。d3-scale 时间刻度文档明确推荐若想自建这种条件格式请参考 d3-time-format——即本文主题模块。在 D3 生态中的角色时间刻度的刻度标签来源d3-time-format 并不是孤立模块它在 D3 渲染管线中承担刻度标签文本生成的职责时间刻度d3.scaleTime/d3.scaleUtc生成ticks后由*time*.tickFormat产出一个合适的格式化器用于轴标签。当显式传入 specifier 时tickFormat等价于本文的locale.format不传时则返回上述默认多尺度格式时间刻度文档坐标轴d3.axisBottom等在tickFormat缺省时会调用*scale*.tickFormat文档明确引导如需创建格式化器参见 d3-format 与 d3-time-format见 d3-axis 文档。从源码组织看D3 主仓库本仓库本身不直接包含 d3-time-format 的实现文件它通过 package.json 中的依赖d3-time-format: ^4.1.0引入并由 src/index.js 统一 re-export文档则由 VitePress 站点维护docs:dev/docs:build脚本见 package.json且 test/docs-test.js 中的测试会爬取docs/下所有 Markdown校验文档内部链接指向存在的锚点——这解释了本文档中大量{#anchor}显式锚点的存在意义也是文档内锚点链接如本文引用的各小节能够稳定跳转的原因。Locale 定制timeFormatLocale 与 timeFormatDefaultLocale带*的指令%a、%A、%b、%B、%c、%p、%x、%X依赖 locale 定义。d3.timeFormatLocale(definition)接收一个定义对象返回一个 locale 对象该对象暴露format、parse、utcFormat、utcParse四个方法。definition必须包含以下 8 个属性属性含义dateTime日期与时间%c的格式 specifier如%a %b %e %X %Ydate日期%x的格式 specifier如%m/%d/%Ytime时间%X的格式 specifier如%H:%M:%Speriods上午/下午标记如[AM, PM]days星期全称数组从周日开始shortDays星期缩写数组从周日开始months月份全称数组从 January 开始shortMonths月份缩写数组从 January 开始完整示例美式英语 localeconst enUs d3.timeFormatLocale({ dateTime: %x, %X, date: %-m/%-d/%Y, time: %-I:%M:%S %p, periods: [AM, PM], days: [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday], shortDays: [Sun, Mon, Tue, Wed, Thu, Fri, Sat], months: [January, February, March, April, May, June, July, August, September, October, November, December], shortMonths: [Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec] });之后调用enUs.format(%a %b %e)、enUs.utcParse(%B %d, %Y)等即可得到基于该语言环境的格式化器/解析器。关键区别timeFormatLocale只返回一个独立的 locale 对象不影响全局而d3.timeFormatDefaultLocale(definition)与之等价但会额外重定义全局的d3.timeFormat、d3.timeParse、d3.utcFormat、d3.utcParse为新 locale 的对应方法const enUs d3.timeFormatDefaultLocale({ dateTime: %x, %X, date: %-m/%-d/%Y, time: %-I:%M:%S %p, periods: [AM, PM], days: [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday], shortDays: [Sun, Mon, Tue, Wed, Thu, Fri, Sat], months: [January, February, March, April, May, June, July, August, September, October, November, December], shortMonths: [Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec] });若不显式设置默认 localed3.timeFormat等顶层 API 默认使用美式英语locale文档注明其来源为 d3-time-format 仓库中的locale/en-US.json。因此对于非英文界面推荐做法是数据解析端用timeFormatLocale定义目标 locale 的parse方法避免污染全局仅当整站统一语言时再用timeFormatDefaultLocale。速查与常见陷阱小结场景推荐用法展示本地时区日期d3.timeFormat(%Y-%m-%d)展示/解析 UTC 日期d3.utcFormat/d3.utcParse行为更可预测不依赖浏览器时区序列化/交换 ISO 8601d3.isoFormat/d3.isoParse严格 ISO 校验解析d3.utcParse(%Y-%m-%dT%H:%M:%S.%LZ)解析格式不统一的来源数据依次尝试多个parse取首个非null结果时间轴刻度标签参考多尺度格式或直接使用scaleUtc().tickFormat()默认行为多语言界面d3.timeFormatLocale定义独立 locale全站统一时再用d3.timeFormatDefaultLocale常见陷阱与文档明示的规则对照%d/%e解析等价格式化端二者输出不同零填充 vs 空格填充但解析端视为同一指令严格解析parse要求字符串与 specifier 精确匹配差一个字符即返回null不存在尽力而为模式字面量Z≠%Z%Y-%m-%dT%H:%M:%SZ末尾的Z是指令串中的普通字符周号三口径不可混用%U周日起始零周规则、%W周一起始零周规则、%VISO 周配%G/%g周纪年三者对同一日期可能给出不同结果字段宽度/精度参数未实现部分 strftime 实现支持%05d之类的宽度语法d3-time-format 目前不支持。参考文档索引模块完整 API 文档docs/d3-time-format.md时间区间 API多尺度格式依赖docs/d3-time.md时间刻度与默认刻度格式docs/d3-scale/time.md坐标轴刻度格式化入口docs/d3-axis.md聚合导出入口src/index.js依赖版本与文档站点脚本package.json版本变更历史%G/%g新增等CHANGES.md文档链接完整性测试test/docs-test.js【免费下载链接】d3Bring data to life with SVG, Canvas and HTML. :bar_chart::chart_with_upwards_trend::tada:项目地址: https://gitcode.com/GitHub_Trending/d3/d3创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考