date-fns 意大利语(it)locale 完整指南:format/parse 令牌、距离与时长格式化对照速查
【免费下载链接】date-fns⏳ Modern JavaScript date utility library ⌛️项目地址: https://gitcode.com/gh_mirrors/da/date-fns
本篇指南以 date-fns 仓库中 pkgs/core/src/locale/it/snapshot.md 为骨架,系统梳理意大利语 locale 在format、parse、formatDistance、formatDistanceStrict、formatRelative、formatDuration六大 API 下的全部本地化输出。读者可将其作为意大利语日期格式化的“预期行为对照表”,用于调试输出、编写测试断言,并理解 date-fns 多语言 locale 的数据组织方式与底层实现原理。
一、snapshot.md 是什么:locale 的“行为快照”
在 date-fns 仓库中,每个语言 locale 目录下都有一份snapshot.md文件。以意大利语为例,其路径为 pkgs/core/src/locale/it/snapshot.md,它由构建脚本 pkgs/core/scripts/build/localeSnapshots/index.ts 自动生成:脚本遍历所有 locale,对format/parse/formatDistance/formatDistanceStrict/formatRelative/formatDuration六个 API 分别渲染固定输入,把输出结果以 Markdown 表格的形式写入每个 locale 目录下的snapshot.md。该脚本支持generate(默认,重新生成快照)与test(比对磁盘快照与生成结果,不一致即报错)两种模式,并要求在TZ=utc环境下运行。
快照的用途在 pkgs/core/docs/i18nContributionGuide.md 中有明确说明:快照即 locale 的测试基准。新增或修改语言后,需运行pnpm run locale-snapshots重新生成快照,人工审查输出值是否符合该语言的语法习惯,再随代码一并提交。快照与实现不一致时,test模式会直接失败,从机制上防止本地化文案悄悄回归。
意大利语 locale 的入口为 pkgs/core/src/locale/it/index.ts,其导出对象由五个数据模块拼装而成:
export const it: Locale = { code: "it", formatDistance: formatDistance, formatLong: formatLong, formatRelative: formatRelative, localize: localize, match: match, options: { weekStartsOn: 1 /* Monday */, firstWeekContainsDate: 4, }, };其中options.weekStartsOn: 1表示意大利语一周从星期一开始,firstWeekContainsDate: 4表示每年的第一周包含当年 1 月 4 日(符合 ISO 8601 周历约定)。这两个选项直接影响快照中 “Local week-numbering year”“Local week of year”“Local day of week” 等令牌的计算结果。
二、format 与 parse:令牌到意大利语文本的完整映射
快照中format与parse两个 API 共用一张大表:左边输入固定的 UTC 时间戳,中间是令牌字符串,右边分别是format的输出与parse的输出。parse的结果会解析回“该文本所代表的当日起点/时段起点”,因此表中parse result常出现整点(如T00:00:00.000Z)或时段起始(如T04:00:00.000Z)。
2.1 年份与季度
| 标题 | 令牌 | format 示例 | 说明 |
|---|---|---|---|
| Calendar year(历年) | yo | 1987/5 | 序数形式,直接输出数字,无后缀 |
| Local week-numbering year | Yo | 1987/4 | 基于本地周历(周一起始、含 1 月 4 日)的年份 |
| Quarter(formatting) | Qo/QQQ/QQQQ/QQQQQ | 1、T1、1º trimestre、1 | 缩写用T1~T4,宽式用1º trimestre |
| Quarter(stand-alone) | qo/qqq/qqqq/qqqqq | 同 Q 系列 | 独立上下文(如列表)使用 |
从源码 pkgs/core/src/locale/it/_lib/localize/index.ts 可看到季度数据:
const quarterValues = { narrow: ["1", "2", "3", "4"], abbreviated: ["T1", "T2", "T3", "T4"], wide: ["1º trimestre", "2º trimestre", "3º trimestre", "4º trimestre"], };注意年份Yo的差异:1987-02-11在本地周历中仍属 1987 年,但0005-01-01(公历 1 月 1 日)在意大利周历中属于上一年的第 52 周,因此Yo输出为4,parse结果回退到0003-12-29。这是weekStartsOn: 1与firstWeekContainsDate: 4联合作用的典型表现。
2.2 月份:格式化的五种宽度
月份是本地化最丰富的部分,M(formatting)与L(stand-alone)各有五种宽度:
| 宽度 | 令牌 | 示例(1 月/5 月) | 对应数据 |
|---|---|---|---|
| 数字序数 | Mo/Lo | 1 | ordinalNumber |
| 缩写 | MMM/LLL | gen/mag | monthValues.abbreviated |
| 全称 | MMMM/LLLL | gennaio/maggio | monthValues.wide |
| 单个字母 | MMMMM/LLLLL | G/M | monthValues.narrow |
意大利语月份缩写全部取前三个字母(gen, feb, mar, apr, mag, giu, lug, ago, set, ott, nov, dic),与英文的Jan式缩写形成鲜明对比。窄式单字母存在歧义(M同时代表 marzo 和 maggio,A代表 aprile 和 agosto),快照中MMMMM对 5 月与 3 月都输出M即为此歧义的体现,这类歧义由 pkgs/core/src/locale/it/_lib/match/index.ts 中的解析正则处理(窄式按首字母匹配、any宽度按ge/f/mar/ap/mag/gi/l/ag/s/o/n/d前缀区分)。
2.3 星期:格式化、ISO 与本地三种体系
快照中星期相关令牌分三大类,每类五种宽度(o/E/i/e/c后缀的数字序数 + 三/四/五/六字母):
- Day of week(
E系列,格式化):EEE→lun,EEEE→lunedì,EEEEE→L(首字母,Lunedì 取L),EEEEEE→lun。 - ISO day of week(
i系列):io输出 1~7(周一=1),iiii→lunedì。 - Local day of week(
e/c系列):意大利语本地周从周一开始,因此eo对周一输出1;c系列为 stand-alone。
一个值得注意的细节:EEEEEE与iiiiii/eeeee/cccccc这类最短宽度的 parse 结果是Invalid Date。快照原样记录了该行为——三字母缩写lun同时对应“短格式”与“窄格式”数据(见源码dayValues.short与dayValues.abbreviated内容相同),解析器无法把lun唯一映射回某个宽度,故返回Invalid Date。这是快照作为“行为基准”最有价值的部分:它如实记录边界行为,而非掩盖。
2.4 一天中的时段:AM/PM、正午午夜与弹性时段
意大利语的时段表达相当讲究,快照覆盖三类令牌:
a/b系列(AM/PM 与 正午/午夜):宽式均为AM/PM(意大利语书面语直接使用拉丁缩写);窄式aaaaa/bbbbb输出m.与p.。快照显示m.可解析回当天T00:00:00.000Z,而p.的 parse 结果为Invalid Date(因为p.与日期的“前一天/后一天”判断存在歧义,解析器无法确定基准时刻)。B系列(Flexible day period,弹性时段):意大利语按一天四段表达:
| 时间点 | format 输出 | parse 结果 |
|---|---|---|
| 11:13 | di mattina(早上) | T04:00:00.000Z(凌晨 4 点起) |
| 14:13 | del pomeriggio(下午) | T12:00:00.000Z(正午起) |
| 19:13 | di sera(晚上) | T17:00:00.000Z(17 点起) |
| 02:13 | di notte(夜里) | T00:00:00.000Z(零点起) |
其数据源见 localize/index.ts 中的formattingDayPeriodValues(morning/afternoon/evening/night分别对应di mattina/del pomeriggio/di sera/di notte),解析端由 match/index.ts 的matchDayPeriodPatterns正则((di|del) (mattina|pomeriggio|sera|notte))负责回读。
2.5 小时、分钟、秒与序数
ho/Ho/Ko/ko四种小时制(1-12、0-23、0-11、1-24)、mo(分钟)、so(秒)均为序数令牌,意大利语序数输出即普通数字(ordinalNumber直接String(number),无º后缀——注意matchOrdinalNumberPattern虽允许º输入,但输出不带)。快照显示Ho对 23 点输出23,ho对 23 点输出11(12 小时制),Ko对 23 点输出11(0-11 制),ko对 23 点输出23(1-24 制)。
2.6 本地化长格式:P/p 系列组合
formatLong定义了意大利语的长格式模板,见 pkgs/core/src/locale/it/_lib/formatLong/index.ts:
const dateFormats = { full: "EEEE d MMMM y", long: "d MMMM y", medium: "d MMM y", short: "dd/MM/y", }; const timeFormats = { full: "HH:mm:ss zzzz", long: "HH:mm:ss z", medium: "HH:mm:ss", short: "HH:mm", };对应的快照输出:
P(短日期)→11/01/1987(日/月/年,意大利语顺序)PP(中日期)→11 gen 1987PPP(长日期)→11 gennaio 1987PPPP(完整日期)→domenica 11 gennaio 1987(含星期)p→12:13,pp→12:13:14ppp/pppp→12:13:14 GMT+0/12:13:14 GMT+00:00,其 parse 结果为Errored(带时区缩写/偏移的长时间无法被parse回读,快照如实标注)Pp→11/01/1987 12:13,PPpp→11 gen 1987 12:13:14,依此类推PPPppp/PPPPpppp组合同样 Errored
日期时间组合模板dateTimeFormats使用{{date}} {{time}}占位符拼接。快照中1453-05-29这一历史日期(君士坦丁堡陷落日)用于验证任意年份的兼容性,PP输出29 mag 1453,PPPP输出domenica 29 maggio 1453。
三、formatDistance:模糊距离的意大利语表达
快照假设now = 2000-01-01 00:00,列出目标日期对应的模糊距离文本。意大利语的量词体系与英文类似但更细致,核心规则(见 formatDistance/index.ts)为:count === 1时取one形式,否则用other模板替换{{count}}。
| 时间差 | 默认输出 | includeSeconds: true | addSuffix: true |
|---|---|---|---|
| 25 秒内 | meno di un minuto | meno di 20 secondi/meno di 10 secondi/meno di 5 secondi/alcuni secondi | tra meno di un minuto/meno di un minuto fa |
| 1 分钟 | un minuto | un minuto | tra un minuto/un minuto fa |
| 45 分钟 | circa un'ora | 同左 | tra circa un'ora |
| 1 天 | un giorno | 同左 | tra un giorno |
| 2 个月 | 2 mesi | 同左 | tra 2 mesi |
| 1 年 | circa un anno | 同左 | tra circa un anno |
| 6 年以上 | circa 6 anni | 同左 | tra circa 6 anni |
关键细节:
- 单复数形态:
un giorno(1 天)对{{count}} giorni(多天);un mese/mesi、un anno/anni同理。 - 约数表达:
circa(大约)用于小时、周、月、年级别,如circa 6 ore、circa un anno;超过 1 年 6 个月则升级为più di un anno(超过一年)。 - 秒级细分:
includeSeconds: true时按 5/10/20 秒分档,halfAMinute输出alcuni secondi(若干秒)。 - 方向后缀:
addSuffix: true时未来加前缀tra(“在……之后”),过去加后缀fa(“……之前”),例如tra 5 mesi与5 mesi fa。该逻辑位于源码 formatDistance/index.ts:
if (options?.addSuffix) { if (options.comparison && options.comparison > 0) { return "tra " + result; } else { return result + " fa"; } }- 注意
meno di un minuto(不到一分钟)在未来方向是tra meno di un minuto,过去方向是meno di un minuto fa——fa紧跟量词而非minuto。
四、formatDistanceStrict:精确距离与强制单位
formatDistanceStrict不做约化,直接给出精确数值;配合unit选项可强制以指定单位输出。快照第三列展示了强制小时(hour)单位时的换算结果:
| 日期 | 默认结果 | addSuffix: true | 强制hour |
|---|---|---|---|
| 2001-01-01 | un anno | tra un anno | 8784 ore |
| 2000-06-01 | 5 mesi | tra 5 mesi | 3648 ore |
| 2000-01-02 | un giorno | tra un giorno | 24 ore |
| 2000-01-01 06:00 | 6 ore | tra 6 ore | 6 ore |
| 1999-12-31 23:59 | un minuto | un minuto fa | 0 ore |
| 1994-01-01 | 6 anni | 6 anni fa | 52584 ore |
三个可验证的细节:
- 严格量化:45 分钟默认输出
45 minuti(不同于formatDistance的circa un'ora)。 - 单位换算:强制小时时,1 年 =
8760 ore(平年)、2001 年跨闰日故 2000-06-01 至 2001-06-01 为8784 ore(闰年 366 天),6 年跨 2000 闰年 =52584 ore(= 6×8760 + 24)。快照中的数值与公历闰年规则完全吻合。 - 过去后缀:
addSuffix: true对过去输出un anno fa、6 anni fa。
五、formatRelative:相对日期文案
formatRelative把“今天/昨天/明天/本周内”等相对关系转成带时间的地道文案(now = 2000-01-01 00:00):
| 日期 | 输出 |
|---|---|
| 2000-01-10 | 10/01/2000(超出周范围,回退为短日期P) |
| 2000-01-05 | mercoledì prossimo alle 00:00 |
| 2000-01-02 | domani alle 00:00 |
| 2000-01-01 | oggi alle 00:00 |
| 1999-12-31 | ieri alle 00:00 |
| 1999-12-27 | lunedì alle 00:00 |
| 1999-12-21 | 21/12/1999 |
实现位于 formatRelative/index.ts,要点:
today/tomorrow/yesterday模板为'oggi alle' p、'domani alle' p、'ieri alle' p(p是短时间HH:mm)。- 上周/下周模板按星期几分单复数:
domenica scorsa alle/domenica prossima alle(阴/阳性特殊),其他星期用lunedì scorso alle、mercoledì prossimo alle等——注意scorso/prossimo的性数随星期名词变化(domenica 为阴性)。 lastWeek/nextWeek通过isSameWeek(复用 pkgs/core/src/isSameWeek/index.ts,并透传 locale 的weekStartsOn: 1选项)判断目标日期是否与基准日同属一周,若同周则退化为thisWeek的'lunedì alle' p形式。- 超出上述范围的日期回退到
other: "P",即dd/MM/y短日期。
六、formatDuration:时长对象的本地化
formatDuration接收形如{"years":2, "months":1}的时长对象,按单位键逐项输出意大利语文本(快照只验证单键情况):
| 时长 | 输出 |
|---|---|
{"years":1} | un anno |
{"years":2} | 2 anni |
{"months":1} | un mese |
{"months":2} | 2 mesi |
{"weeks":1} | una settimana |
{"weeks":2} | 2 settimane |
{"days":1} | un giorno |
{"hours":1} | un'ora |
{"minutes":1} | un minuto |
{"seconds":2} | 2 secondi |
值得注意的形态变化:un'ora(一元音省略,una 遇 ora 省略 a)、una settimana(阴性单数)、2 ore、0 anni(零值也走复数形式)。这些文案同样定义在 formatDistance/index.ts 的量词表中,formatDuration与formatDistance共用同一套单复数数据,保证两类 API 的措辞一致。
七、如何验证与复现:快照的生成与检查
快照本身既是文档又是测试基准,若需在本地复现或更新意大利语快照:
- 在仓库根目录安装依赖后,以 UTC 时区运行快照生成命令(该脚本强制要求
TZ=utc,见 localeSnapshots/index.ts):TZ=utc pnpm run locale-snapshots生成结果会覆盖写入
pkgs/core/src/locale/it/snapshot.md。 - 若要检查磁盘上的快照与当前实现是否一致(CI 校验模式):
TZ=utc pnpm run locale-snapshots test不一致时脚本会抛出
The snapshot on the disk doesn't match the generated snapshot...错误,提示重新生成并提交。
在应用层验证意大利语输出,可直接引入 locale 并与format/formatDistance组合使用(示例):
import { format, formatDistance, formatRelative, formatDuration } from "date-fns"; import { it } from "date-fns/locale"; const date = new Date("1987-02-11T12:13:14.000Z"); format(date, "PPPP", { locale: it }); // "mercoledì 11 febbraio 1987" format(date, "PPpp", { locale: it }); // "11 feb 1987 12:13:14" formatDistance(new Date("2000-06-01T00:00:00.000Z"), new Date("2000-01-01T00:00:00.000Z"), { locale: it, addSuffix: true, }); // "tra 5 mesi" formatRelative(new Date("2000-01-02T00:00:00.000Z"), new Date("2000-01-01T00:00:00.000Z"), { locale: it, }); // "domani alle 00:00" formatDuration({ years: 1, months: 2, days: 3 }, { locale: it }); // "un anno 2 mesi 3 giorni"八、小结
意大利语 snapshot 展示了一个高质量 locale 的全部要素:五种宽度的月份/星期词汇、1º trimestre式季度表达、di mattina/del pomeriggio/di sera/di notte弹性时段、tra … / … fa方向后缀、circa/più di模糊量词,以及scorso/prossimo的性数变化。同时快照如实记录了若干边界行为(最短宽度星期的Invalid Date、带时区长度的 Errored),这些正是调试parse回读时最容易被忽视的坑。
对开发者的实用建议:
- 需要“预期值”时,直接查阅本快照对应语言的文件(如意大利语为 pkgs/core/src/locale/it/snapshot.md),无需运行代码即可断言输出;
- 修改任何 locale 实现后,务必重新生成并审查快照,再提交到版本库;
- 若发现
format能输出但parse返回Invalid Date或 Errored,请先对照快照确认是否为该语言已知的固有行为,再决定是否值得为解析器补充歧义消解规则。
关联参考文件:locale 入口、本地化数据、匹配/解析正则、长格式模板、相对格式实现、距离量词表、快照生成脚本、i18n 贡献指南。
【免费下载链接】date-fns⏳ Modern JavaScript date utility library ⌛️项目地址: https://gitcode.com/gh_mirrors/da/date-fns
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考