date-fns 泰卢固语(Telugu/te)locale 全解析:format、parse 与 formatDistance 快照深度指南
2026/9/19 6:56:35 网站建设 项目流程

date-fns 泰卢固语(Telugu/te)locale 全解析:format、parse 与 formatDistance 快照深度指南

【免费下载链接】date-fns⏳ Modern JavaScript date utility library ⌛️项目地址: https://gitcode.com/gh_mirrors/da/date-fns

本文以 pkgs/core/src/locale/te/snapshot.md 为骨架,完整解析 date-fns 中泰卢固语(te)区域设置在formatparseformatDistanceformatDistanceStrictformatRelativeformatDuration六大 API 下的真实行为快照,并结合 te locale 源码 逐层拆解其实现原理。读完本文,你将掌握:Telugu locale 的完整 token 映射与输出规则、序数词(后缀)的生成逻辑、addSuffix与介词屈折的处理方式、weekStartsOn 等选项对解析结果的影响,以及如何在自己的项目中使用并验证该 locale。

一、快照文档是什么:locale 行为的"黄金测试基准"

snapshot.md是 date-fns 每个 locale 目录下都会维护的一份行为快照(snapshot),它不是普通文档,而是用真实 API 跑出来的输入-输出对照表。它同时验证两条链路:

  • format链路:给定一个 UTC 日期与 token 字符串,输出本地化文本;
  • parse链路:把本地化文本反向解析回日期。

快照表中的Invalid DateErrored两列值尤其关键——它们不是笔误,而是已知的、被测试接受的行为边界(例如 telugu 简写月份సెప్టెంనవండిసెం无法被parse识别,详见下文匹配正则分析)。因此,这份快照既是使用者查手册的依据,也是贡献者改词条后必须回归验证的标尺。

1.1 te locale 的组成结构

在 pkgs/core/src/locale/te/index.ts 中,te被定义为标准的Locale对象:

export const te: Locale = { code: "te", formatDistance: formatDistance, formatLong: formatLong, formatRelative: formatRelative, localize: localize, match: match, options: { weekStartsOn: 0 /* Sunday */, firstWeekContainsDate: 1, }, };

五个功能模块分别位于te/_lib/下,与Locale类型一一对应:

模块文件职责
localize_lib/localize/index.ts将数字/枚举值转为 Telugu 文本(月份、星期、纪元、时段)
match_lib/match/index.ts提供反向解析用的正则模式
formatDistance_lib/formatDistance/index.ts相对时间距离的本地化
formatLong_lib/formatLong/index.ts长格式模板(P/PP/PPP/PPPP 等)
formatRelative_lib/formatRelative/index.ts相对日期(今天/昨天/下周等)模板

options中的两个参数直接影响快照结果:weekStartsOn: 0表示一周从星期日开始firstWeekContainsDate: 1表示一周内包含 1 月 1 日的那周算第一周——这解释了快照中Yo(本地周年份)与wo(本地周序号)的解析结果会落到上一年 12 月的原因。

二、formatparse快照:token 全映射

快照第一部分覆盖 24 类 token。下表保留每一类的关键示例(完整矩阵请查阅 snapshot.md,所有测试基准时间均为12:13:14.015Z):

2.1 年份、季度与月份

类别Token示例输入format 输出parse 结果
Calendar yearyo1987-02-111987వ1987-01-01
Local week-numbering yearYo1987-02-111987వ1986-12-28(周起始于周日)
Quarter (formatting)Qo2019-04-012వ2019-04-01
QQQ2019-01-01త్రై12019-01-01
QQQQ2019-01-011వ త్రైమాసికం2019-01-01
QQQQQ2019-01-0112019-01-01
Quarter (stand-alone)qo/qqq/qqqq2019-04-012వ/త్రై2/2వ త్రైమాసికం2019-04-01
Month (formatting)Mo2019-01-111వ2019-01-01
MMM2019-01-11జన2019-01-01
MMMM2019-09-10సెప్టెంబర్2019-09-01
MMMMM2019-06-10జూ2019-01-01(窄格式二义性)
Month (stand-alone)Lo/LLL/LLLL/LLLLL同上与 formatting 宽度相同同上

源码依据在 _lib/localize/index.ts:月份三套宽度直接取自 CLDR 数据(జన/ఫిబ్ర/… 为 abbreviated,జనవరి/ఫిబ్రవరి/… 为 wide,/ఫి/… 为 narrow)。

值得注意的行为MMMMM(窄格式)在 6 月输出జూ、7 月输出జు,但parse两个都解析回1 月——因为match中窄月份正则/^జూ/i/^జు/i无法区分,且回退到首月。这是快照中"看似错误实则已知"的典型案例。

同样,MMM简写月份的 9 月(సెప్టెం)、11 月(నవం)、12 月(డిసెం)在parse时返回Invalid Date,因为 _lib/match/index.ts 的简写正则写作/^(జన|ఫిబ్ర|మార్చి|ఏప్రి|మే|జూన్|జులై|ఆగ|సెప్|అక్టో|నవ|డిసె)/i——其中 9 月匹配前缀是సెప్而非సెప్టెం,11/12 月同理,导致这三个格式化输出无法被反向解析。

2.2 周、日与星期

类别Token示例输入format 输出parse 结果
Local week of yearwo2019-01-011వ2018-12-30(周日为一周之始)
ISO week of yearIo2019-01-011వ2018-12-31
Day of monthdo2019-02-1111వ2019-02-11
do MMMM2019-02-1111వ ఫిబ్రవరి2019-02-11
Day of yearDo2019-12-31365వ2019-12-31
Day of week (formatting)E/EE/EEE2019-02-11సోమ2019-02-11
EEEE2019-02-15శుక్రవారం2019-02-15
EEEEE2019-02-11సో2019-02-11
EEEEEE2019-02-11సోమ2019-02-11
ISO day of weekio2019-02-111వ(周一=1)2019-02-11
iii/iiii/iiiii/iiiiii同 E 系列同 E 系列同 E 系列
Local day of weekeo2019-02-112వ(周日=1)2019-02-11
eeeeeeeee同 E 系列同 E 系列同 E 系列
Local day of week (stand-alone)co/ccccccccc同 E 系列同 E 系列同 E 系列

注意io(ISO 周几)与eo/co(本地周几)的序数差异:2019-02-11 是周一,ISO 序数为1వ,而 Telugu 本地(周日起始)序数为2వ。星期文本在 _lib/localize/index.ts 中定义,shortabbreviated宽度相同(ఆది/సోమ/…),narrow用首字符(/సో/…),wide为完整形式(ఆదివారం/సోమవారం/…)。

2.3 时段(AM/PM)与弹性时段

类别Token输入时间format 输出parse 结果
AM, PMa/aa/aaa/aaaa/aaaaa11:13పూర్వాహ్నం当天 00:00
同上14:13 / 19:13అపరాహ్నం当天 12:00
AM, PM, noon, midnightbbbbbb11:13పూర్వాహ్నం00:00
同上14:13అపరాహ్నం12:00
Flexible day periodBBBBBB11:13ఉదయం(上午)04:00
同上14:13మధ్యాహ్నం(下午)12:00
同上19:13సాయంత్రం(傍晚)17:00
同上02:13రాత్రి(夜间)00:00

Telugu 的时段体系比英文丰富:పూర్వాహ్నం(AM)、అపరాహ్నం(PM)、ఉదయం(清晨/上午)、మధ్యాహ్నం(正午/下午)、సాయంత్రం(傍晚)、రాత్రి(夜间)、అర్ధరాత్రి(午夜)、మిట్టమధ్యాహ్నం(正午)。这些值在 _lib/localize/index.ts 中定义,注意其narrow / abbreviated / wide 三档文本完全相同(Telugu 无缩略习惯),且formattingDayPeriodValuesdayPeriodValues一致。

parse对弹性时段的锚点值(04:00 / 12:00 / 17:00 / 00:00)由 _lib/match/index.ts 中的parseDayPeriodPatterns决定:మధ్యాహ్నం前缀మధ్య匹配 afternoon、సాయంత్రం匹配 evening,日期框架(date-fns 的 parse 框架)再映射为固定时刻。

2.4 小时、分钟、秒

类别Token输入format 输出parse 结果
Hour [1-12]ho23:1311వ23:00
Hour [0-23]Ho23:1323వ23:00
Hour [0-11]Ko23:1311వ23:00
Hour [1-24]ko23:1323వ23:00
Minutemo12:5555వ12:55
Secondso12:13:5555వ12:13:55

所有数值型 token 的序数后缀由 ordinalNumber 统一生成:

const ordinalNumber: LocalizeFn<number> = (dirtyNumber, _options) => { const number = Number(dirtyNumber); return number + "వ"; };

即 Telugu 序数词规则为数字直接拼接(如1వ42వ365వ),无性别/数范畴变化,相比英语的 st/nd/rd/th 规则更简单。

2.5 长格式组合(P/PP/PPP/PPPP 与 p/pp/ppp/pppp)

快照中长格式部分由 _lib/formatLong/index.ts 的模板驱动:

const dateFormats = { full: "d, MMMM y, EEEE", long: "d MMMM, y", medium: "d MMM, y", short: "dd-MM-yy", }; const timeFormats = { full: "h:mm:ss a zzzz", long: "h:mm:ss a z", medium: "h:mm:ss a", short: "h:mm a", }; const dateTimeFormats = { full: "{{date}} {{time}}'కి'", long: "{{date}} {{time}}'కి'", medium: "{{date}} {{time}}", short: "{{date}} {{time}}", };
Token输入format 输出parse 结果
P(short date)1987-02-1111-02-871987-02-11
PP(medium date)1987-02-1111 ఫిబ్ర, 19871987-02-11
PPP(long date)1987-02-1111 ఫిబ్రవరి, 19871987-02-11
PPPP(full date)1987-02-1111, ఫిబ్రవరి 1987, బుధవారం1987-02-11
p(short time)1987-01-1112:13 అపరాహ్నం12:13
pp(medium time)1987-01-1112:13:14 అపరాహ్నం12:13:14
ppp(long time)1987-01-1112:13:14 అపరాహ్నం GMT+0Errored
pppp(full time)1987-01-1112:13:14 అపరాహ్నం GMT+00:00Errored
Pp1987-01-1111-01-87 12:13 అపరాహ్నం12:13
PPpp1987-01-1111 జన, 1987 12:13:14 అపరాహ్నం12:13:14
PPPppp/PPPPpppp1987-01-11GMT+0కి/GMT+00:00కి后缀Errored

两个要点:

  1. కి后置词:full/long 的 dateTime 模板中'కి'(泰卢固语"在…时"的格助词)作为字面量拼接,因此PPPppp输出… అపరాహ్నం GMT+0కి
  2. Errored是有意的:带时区(z/zzzz)的 ppp/pppp 及组合 token 在parse下会抛错(框架不支持该 parse 组合),快照明确记录了这一行为,属于"测试承认的受限能力"而非缺陷。

三、formatDistance快照:相对时间与介词屈折

快照前提是now = 2000-01-01 00:00,三列分别为默认输出、includeSeconds: trueaddSuffix: true

日期默认includeSecondsaddSuffix
2006-01-01సుమారు 6 సంవత్సరాలు同左సుమారు 6 సంవత్సరాలలో
2001-06-01ఒక సంవత్సరం పైగా同左ఒక సంవత్సరంలో
2000-06-015 నెలలు同左5 నెలలలో
2000-01-02ఒక రోజు同左ఒక రోజులో
2000-01-01T00:00:25ఒక నిమిషం కన్నా తక్కువఅర నిమిషంఒక నిమిషంలో
2000-01-01T00:00:05ఒక నిమిషం కన్నా తక్కువ10 సెకన్ల కన్నా తక్కువఒక నిమిషంలో
1999-12-31T23:59:55ఒక నిమిషం కన్నా తక్కువ10 సెకన్ల కన్నా తక్కువఒక నిమిషం క్రితం
1999-12-31T23:4515 నిమిషాలు同左15 నిమిషాల క్రితం
1999-12-31T23:00సుమారు ఒక గంట同左సుమారు ఒక గంట క్రితం
1999-12-302 రోజులు同左2 రోజుల క్రితం
1998-01-01సుమారు 2 సంవత్సరాలు同左సుమారు 2 సంవత్సరాల క్రితం

3.1 addSuffix 与"独立/介词"双形态的实现

这是 Telugu locale 相对时间最值得注意的语言学特性。实现位于 _lib/formatDistance/index.ts:每个 token 的词条都同时定义standalone(独立形态)与withPreposition(介词后形态)两套,且各自含one/other两种数形:

xDays: { standalone: { one: "ఒక రోజు", other: "{{count}} రోజులు" }, withPreposition: { one: "ఒక రోజు", other: "{{count}} రోజుల" }, },

而 formatDistance 函数本体 负责组装:

const tokenValue = options?.addSuffix ? formatDistanceLocale[token].withPreposition : formatDistanceLocale[token].standalone;

后缀规则为:未来时间(comparison > 0)追加లో("之后"),过去时间追加క్రితం("之前"):

if (options?.addSuffix) { if (options.comparison && options.comparison > 0) { return result + "లో"; } else { return result + " క్రితం"; } }

对比快照可见:5 నెలలు(独立)→5 నెలలలో(未来,介词形నెలల+లో);15 నిమిషాలు15 నిమిషాల క్రితం(过去)。泰卢固语要求名词在格助词前发生词尾变化,这正是standalone/withPreposition双形态存在的意义,也是该 locale 区别于英语(仅拼接 "ago"/"in")的核心实现。

四、formatDistanceStrict快照:强制单位行为

日期结果addSuffix强制unit: "hour"
2006-01-016 సంవత్సరాలు6 సంవత్సరాలలో52608 గంటలు
2001-01-01ఒక సంవత్సరంఒక సంవత్సరంలో8784 గంటలు
2000-01-1514 రోజులు14 రోజులలో336 గంటలు
2000-01-01T00:4545 నిమిషాలు45 నిమిషాలలోఒక గంట(四舍五入)
2000-01-01T00:00:055 సెకన్ల5 సెకన్లలో0 గంటలు
1999-12-31T23:59:555 సెకన్ల5 సెకన్ల క్రితం0 గంటలు
1999-12-01ఒక నెలఒక నెల క్రితం744 గంటలు
1994-01-016 సంవత్సరాలు6 సంవత్సరాల క్రితం52584 గంటలు

formatDistanceStrictformatDistance的差异在于:前者不做"约/超过"的近似,直接输出精确计数(如25 సెకన్ల45 నిమిషాలు);当强制unit: "hour"时,所有间隔被换算成小时并遵循取整规则(如 45 分钟 →ఒక గంట,15 分钟 →0 గంటలు)。由于复用同一个formatDistanceLocale词表,序数/复数规则与formatDistance完全一致。

五、formatRelative快照:相对日期的模板展开

日期结果
2000-01-1010-01-00(超出窗口,回退 P 格式)
2000-01-05తదుపరి బుధవారం 12:00 పూర్వాహ్నం(下周三)
2000-01-02రేపు 12:00 పూర్వాహ్నం(明天)
2000-01-01ఈ రోజు 12:00 పూర్వాహ్నం(今天)
1999-12-31నిన్న 12:00 పూర్వాహ్నం(昨天)
1999-12-27గత సోమవారం 12:00 పూర్వాహ్నం(上周一)
1999-12-2121-12-99(超出窗口)

模板定义在 _lib/formatRelative/index.ts:

const formatRelativeLocale = { lastWeek: "'గత' eeee p", yesterday: "'నిన్న' p", today: "'ఈ రోజు' p", tomorrow: "'రేపు' p", nextWeek: "'తదుపరి' eeee p", other: "P", };

规律清晰:lastWeekగత("过去的")+eeee(完整星期名)+p(本地短时间);nextWeekతదుపరి("接下来的");超出上周/下周窗口的日期回退到P(短日期dd-MM-yy)。p展开为h:mm a,所以时间部分统一输出为12:00 పూర్వాహ్నం这样的 12 小时制。

六、formatDuration快照:时长组件本地化

Duration 输入结果
{"years":0}0 సంవత్సరాలు
{"years":1}ఒక సంవత్సరం
{"years":2}2 సంవత్సరాలు
{"months":1}ఒక నెల
{"weeks":2}2 వారాలు
{"days":1}ఒక రోజు
{"hours":2}2 గంటలు
{"minutes":1}ఒక నిమిషం
{"seconds":2}2 సెకన్ల

formatDuration复用formatDistanceLocale词表中的复数规则,0other形(如0 సంవత్సరాలు),1one形(ఒక సంవత్సరం)。注意 Telugu 的复数形态:2 వారాలు(周)、2 నెలలు(月)、2 రోజులు(天)、2 సంవత్సరాలు(年),与英语的 "2 weeks/months/days/years" 一一对应,但单数用独立词ఒక("一")。

七、如何在项目中使用与验证 te locale

7.1 引入方式

从源码结构看,所有 locale 统一从 pkgs/core/src/locale/index.ts 导出(该文件由脚本自动生成)。在你的应用中:

import { te } from "date-fns/locale"; import { format, parse, formatDistance } from "date-fns"; // format:按 Telugu 习惯输出 format(new Date(2019, 1, 11, 14, 13), "d MMMM y, EEEE 'గం'", { locale: te }); // => "11 ఫిబ్రవరి 2019, సోమవారం గం" // parse:反向解析 Telugu 文本 parse("11 ఫిబ్రవరి, 1987", "PPP", new Date(), { locale: te }); // formatDistance:相对时间 formatDistance(new Date(2000, 0, 1, 6), new Date(2000, 0, 1), { locale: te }); // => "సుమారు 6 గంటలు"

7.2 把快照当回归测试使用

snapshot.md的每一行都可以直接转化为断言。例如验证"简写月份解析失败"这一已知行为:

import { parse } from "date-fns"; import { te } from "date-fns/locale"; // 已知行为:MMM 简写中 9/11/12 月 parse 失败 const d = parse("సెప్టెం", "MMM", new Date(2019, 8, 10), { locale: te }); console.log(isValid(d)); // false

在修改或贡献telocale 时(例如修正 _lib/match/index.ts 中సెప్సెప్టెం的匹配前缀),必须同步更新snapshot.md并运行 locale 测试,确保快照与实现始终一致。

7.3 常见坑位小结

  • 窄月份二义性MMMMM的 6 月(జూ)与 7 月(జు)parse 均回退到 1 月;
  • 简写月份 9/11/12 月:format 可输出సెప్టెం/నవం/డిసెం,但 parse 返回Invalid Date
  • 带时区长格式ppp/pppp/PPPppp/PPPPpppp在 parse 下报错(Errored),应避免用 parse 解析含z的 Telugu 长时间文本;
  • 周起始weekStartsOn: 0(周日)导致本地周/周序号 token(Yo/wo/eo)的结果可能落在相邻年份/月份。

八、延伸阅读

  • 快照原始文件:pkgs/core/src/locale/te/snapshot.md
  • locale 入口与选项:pkgs/core/src/locale/te/index.ts
  • 文本/序数本地化:pkgs/core/src/locale/te/_lib/localize/index.ts
  • 解析正则:pkgs/core/src/locale/te/_lib/match/index.ts
  • 相对时间双形态词表:pkgs/core/src/locale/te/_lib/formatDistance/index.ts
  • 长格式模板:pkgs/core/src/locale/te/_lib/formatLong/index.ts
  • 相对日期模板:pkgs/core/src/locale/te/_lib/formatRelative/index.ts
  • locale 通用构造器(buildLocalizeFn等):pkgs/core/src/locale/_lib/buildLocalizeFn/index.ts

【免费下载链接】date-fns⏳ Modern JavaScript date utility library ⌛️项目地址: https://gitcode.com/gh_mirrors/da/date-fns

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询