date-fns 韩语(ko)语言包完整指南:format / parse / formatDistance 等全部快照行为详解
【免费下载链接】date-fns⏳ Modern JavaScript date utility library ⌛️项目地址: https://gitcode.com/gh_mirrors/da/date-fns
本指南以 date-fns 仓库中 韩语 locale 快照文档 为核心骨架,完整解析韩语(ko)语言包在format、parse、formatDistance、formatDistanceStrict、formatRelative、formatDuration六大 API 下的全部输出行为与规则,并结合 韩语 locale 实现源码 与快照生成脚本源码,说明每个输出结果背后的实现原理、序数词规则、时段时间段映射以及如何自己动手复现验证。读完本文,你将能够:准确预判韩语 locale 在各种日期时间 token 下的格式输出与解析回推结果;理解快照中每个字段(如 "1번째"、"약 6년"、"오후")的来源;掌握快照文档的生成与校验机制,并学会在业务代码中正确使用ko语言包。
快照文档是什么:ko locale 的行为基准
snapshot.md 不是手写文档,而是 date-fns 构建流程中由脚本自动生成的"行为快照":它对韩语 locale 的全部关键 API 输入一组固定的测试日期与 token,把真实运行结果以 Markdown 表格形式固化下来。生成逻辑位于 localeSnapshots 脚本:脚本枚举仓库中所有 locale(通过 listLocales.ts),逐个读取src/locale/<code>/index.ts导出对象,然后依次调用renderFormatParse、renderFormatDistance、renderFormatDistanceStrict、renderFormatRelative、renderFormatDuration五个渲染函数,拼装后写入各 locale 目录下的snapshot.md。
脚本对运行环境有硬性要求——TZ必须为utc(见 index.ts#L24-L25),因为快照中的日期字符串全部以Z结尾的 UTC ISO 格式呈现,任何非 UTC 时区都会导致输出偏差。脚本支持两种模式:默认generate模式把生成结果写回磁盘;test模式则比较磁盘上的快照与重新生成的结果,不一致即报错并提示运行pnpm run locale-snapshots。这意味着快照文档本身就是 ko locale 的回归测试基准:任何对韩语翻译或格式模板的改动,如果改变了输出,都会在test模式下被发现。
快照中每一行的parse结果同样由脚本实时计算(renderFormatParse/index.ts):先用format(date, token, { locale })得到格式串,再调用parse(formatResult, token, date, { locale })尝试回推,回推失败记作Errored。因此快照中"format 结果"与"parse 结果"天然构成一对可逆性验证。
快速上手:如何在项目中使用韩语 locale
在代码中引入韩语语言包即可让format、parse、formatDistance等函数输出韩文:
import { format, parse, formatDistance } from "date-fns"; import { ko } from "date-fns/locale"; format(new Date(2019, 0, 11, 12, 13, 14), "MMMM do", { locale: ko }); // => "1월 11일" parse("1월 11일", "MMMM do", new Date(2019, 0, 1), { locale: ko }); // => 2019-01-11T00:00:00.000Z 附近的 Date formatDistance(new Date(2000, 5, 1), new Date(2000, 0, 1), { locale: ko }); // => "5개월"ko对象定义在 pkgs/core/src/locale/ko/index.ts,包含五个必选字段与一个可选配置:
| 字段 | 作用 | 实现文件 |
|---|---|---|
code | 语言代码"ko" | index.ts#L18 |
formatDistance | formatDistance/formatDistanceStrict使用的距离本地化函数 | _lib/formatDistance/index.ts |
formatLong | format使用的长格式模板(P/PP/PPP/PPPP、p/pp等) | _lib/formatLong/index.ts |
formatRelative | formatRelative使用的相对时间模板 | _lib/formatRelative/index.ts |
localize | format使用的各类值(序数、季度、月份、星期、时段)本地化 | _lib/localize/index.ts |
match | parse使用的各类韩文文本匹配/解析规则 | _lib/match/index.ts |
options | weekStartsOn: 0(周日为一周第一天)、firstWeekContainsDate: 1 | index.ts#L24-L27 |
options两个值决定周相关计算:weekStartsOn: 0表示韩语语境下每周从周日开始,直接影响startOfWeek、getWeek等函数;firstWeekContainsDate: 1表示每年的第一周是包含 1 月 1 日的那一周。这正是快照中"Local week-numbering year"(Yo)与"Local week of year"(wo)的 parse 结果会回退到上一年 12 月末的原因(详见下文)。
format与parse:全部 token 输出速查表
快照的第一大节覆盖format/parse的 40 余种 token。下面按类别整理,format 列即韩语输出,parse 列是韩语文本回推得到的日期(UTC)。
年份(Calendar yearyo/ Local week-numbering yearYo)
| Token | 日期 | format | parse |
|---|---|---|---|
yo | 1987-02-11 | 1987번째 | 1987-01-01 |
yo | 0005-01-01 | 5번째 | 0005-01-01 |
Yo | 1987-02-11 | 1987번째 | 1986-12-28 |
Yo | 0005-01-01 | 5번째 | 0004-12-26 |
韩语序数后缀统一为번째,实现见 localize 的 ordinalNumber。注意Yo的 parse 结果比输入日期"更早":因为周从周日开始且第一周包含 1 月 1 日,1987 年 2 月 11 日所在周的第一天是 1986-12-28(周日),这正是该周编号年的起点。
季度(Quarter formattingQ/ stand-aloneq)
| Token | format | 含义 |
|---|---|---|
Qo/qo | 1번째、2번째… | 序数季度 |
QQQ/qqq | Q1、Q2… | 缩写季度 |
QQQQ/qqqq | 1분기、2분기… | 完整季度(wide) |
QQQQQ/qqqqq | 1、2… | 窄格式 |
映射数据来自 localize 的 quarterValues:narrow: ["1","2","3","4"]、abbreviated: ["Q1","Q2","Q3","Q4"]、wide: ["1분기","2분기","3분기","4분기"]。格式化与独立两种宽度输出完全一致。
月份(Month formattingM/ stand-aloneL)
| Token | format 示例(1 月/12 月) | 说明 |
|---|---|---|
Mo/Lo | 1번째 / 12번째 | 序数月份 |
MMM/LLL | 1월 / 12월 | 缩写 |
MMMM/LLLL | 1월 / 12월 | 完整(wide) |
MMMMM/LLLLL | 1 / 12 | 窄格式 |
韩语月份写作N월,abbreviated 与 wide 相同(见 monthValues)。parse 侧正则见 match 的 matchMonthPatterns:窄格式^(1[012]|[123456789])、缩写与完整格式^(1[012]|[123456789])월。
星期(Day of week:E / i / e / c 四族)
韩语星期名称实现于 dayValues:일/월/화/수/목/금/토为窄/短/缩写,일요일…토요일为完整。快照中具体映射:
| Token 族 | 格式 | 2019-02-11(周一) | 2019-02-15(周五) |
|---|---|---|---|
E/EE/EEE/EEEEE/EEEEEE | 缩写/窄 | 월 | 금 |
EEEE | 完整 | 월요일 | 금요일 |
i(ISO)eo/co(本地序数) | 序数 | 1번째/2번째 | 5번째/6번째 |
iii/iiii/iiiii/iiiiii(ISO 缩写) | 同 E 族 | 월 / 월요일 | 금 / 금요일 |
eee…eeeee(本地缩写) | 同 E 族 | 월 | 금 |
ccc…ccccc(独立缩写) | 同 E 族 | 월 | 금 |
io为 ISO 星期序数(周一到周日 = 1–7,2019-02-11 是周一故为 1번째);eo/co为本地序数(周日开始,周一排第 2、周五排第 6)。parse 侧星期匹配见 matchDayPatterns。
上下午与时段(AM/PMa、b,Flexible day periodB)
韩语时段词全部定义于 dayPeriodValues / formattingDayPeriodValues:
| 词 | 韩语 | 说明 |
|---|---|---|
| am / pm | 오전 / 오후 | 上下午 |
| midnight / noon | 자정 / 정오 | 午夜 / 正午 |
| morning / afternoon / evening / night | 아침 / 오후 / 저녁 / 밤 | 弹性时段 |
快照中的关键行为:
| Token | 时间 | format | parse 结果 |
|---|---|---|---|
a(AM/PM) | 11:13 / 14:13 / 02:13 | 오전 / 오후 / 오전 | 00:00 / 12:00 / 00:00 |
b(AM/PM/noon/midnight) | 同上 | 同a | 同a |
B(flexible) | 11:13 | 아침 | 04:00 |
B | 14:13 | 오후 | 12:00 |
B | 19:13 | 저녁 | 17:00 |
B | 02:13 | 밤 | 00:00 |
a/b的 parse 会把 오전 归一到当日 00:00、오후 归一到 12:00;B的 parse 则按时段起点回推:아침→04:00、오후→12:00、저녁→17:00、밤→00:00。这些解析锚点由 match 的 parseDayPeriodPatterns 与 date-fns 时段框架共同决定。注意快照中b的 5 个宽度(b/bb/bbb/bbbb/bbbbb)输出相同,因为韩语在 narrow/abbreviated/wide 三档都使用同一组词。
小时 / 分钟 / 秒
| Token | 含义 | format 示例 |
|---|---|---|
ho | Hour [1-12] | 11번째、23:13 时仍为 11번째 |
Ho | Hour [0-23] | 11번째、23번째 |
Ko | Hour [0-11] | 11번째(23:13 时也输出 11번째) |
ko | Hour [1-24] | 11번째、23번째 |
mo | Minute | 1 / 55(无后缀) |
so | Second | 1 / 55(无后缀) |
序数规则的精髓在 ordinalNumber 的 switch:minute与second直接返回纯数字,date返回N일,其余(年、月、季度、星期、小时、日序)一律返回N번째。这就是为什么分钟秒数是1/55而小时是11번째。date分支对应下文do(日序)。
日序与周序
| Token | 日期 | format | parse |
|---|---|---|---|
do(Day of month) | 2 月 1/11/28 日 | 1일 / 11일 / 28일 | 同日 |
do MMMM | 同上 | 1일 2월 / 11일 2월 / 28일 2월 | 同日 |
Do(Day of year) | 2019-02-11 | 42번째 | 2019-02-11 |
Do | 2019-12-31 | 365번째 | 2019-12-31 |
wo(Local week) | 2019-01-01 | 1번째 | 2018-12-30 |
wo | 2019-12-01 | 49번째 | 2019-12-01 |
Io(ISO week) | 2019-01-01 | 1번째 | 2018-12-31 |
Io | 2019-12-01 | 48번째 | 2019-11-25 |
do的 parse 回推与输入日期一致;wo的 parse 回退到该周第一天(周日),故 2019 年第 1 周回推为 2018-12-30;Io按 ISO 周规则回推到周一(2018-12-31 / 2019-11-25)。周序数在韩语中也使用번째,与N일形成对比,二者都源自同一个 ordinalNumber。
长日期 / 长时间 / 日期时间组合(P 族与 p 族)
长格式模板定义于 formatLong/index.ts:
const dateFormats = { full: "y년 M월 d일 EEEE", // PPPP long: "y년 M월 d일", // PPP medium: "y.MM.dd", // PP short: "y.MM.dd", // P }; const timeFormats = { full: "a H시 mm분 ss초 zzzz", // pppp long: "a H:mm:ss z", // ppp medium: "HH:mm:ss", // pp short: "HH:mm", // p };快照中的实际输出:
| Token | 示例输出 |
|---|---|
P/PP | 1987.01.11(短格式,含 1453-05-29 → 1453.05.29) |
PPP | 1987년 1월 11일 |
PPPP | 1987년 1월 11일 일요일(含星期) |
p | 12:13(HH:mm) |
pp | 12:13:14(HH:mm:ss) |
ppp | 오후 12:13:14 GMT+0 |
pppp | 오후 12시 13분 14초 GMT+00:00 |
Pp | 1987.01.11 12:13 |
PPpp | 1987.01.11 12:13:14 |
PPPppp/PPPPpppp | 完整日期 + 完整时间(含 오후 与 GMT 偏移) |
一个值得注意的快照细节:ppp、pppp、PPPppp、PPPPpppp这几行的parse 结果全部为Errored。原因在于时间模板中的z/zzzz(时区名 GMT+0 / GMT+00:00)在韩语match中没有对应的解析规则——match/index.ts 只实现了 ordinalNumber、era、quarter、month、day、dayPeriod 六类匹配器,不含时区解析,因此parse无法回推带时区名的完整时间格式。这是快照自动生成机制如实反映的实现边界,而非文档错误。
另外注意ppp行오후 23:59:59 GMT+0这类输出:a H:mm:ss z模板中a在 23 点输出 오후(下午),时间本身仍按 24 小时制H显示,这是模板拼接的固有表现。
formatDistance:相对时间距离输出
快照第二节固定"now = 2000-01-01T00:00:00Z",考察formatDistance(date, baseDate, { locale: ko })。实现位于 formatDistance/index.ts,其核心是{{count}}占位符模板与后缀逻辑:
if (options?.addSuffix) { if (options.comparison && options.comparison > 0) { return result + " 후"; // 未来 } else { return result + " 전"; // 过去 } }关键输出规律(节选,完整见 snapshot.md):
| 基准日期 | Result | includeSeconds: true | addSuffix: true |
|---|---|---|---|
| 2006-01-01 | 약 6년 | 약 6년 | 약 6년 후 |
| 2001-06-01 | 1년 이상 | 1년 이상 | 1년 이상 후 |
| 2000-06-01 | 5개월 | 5개월 | 5개월 후 |
| 2000-01-15 | 14일 | 14일 | 14일 후 |
| 2000-01-01T00:00:25 | 1분 미만 | 30초 | 1분 미만 후 |
| 2000-01-01T00:00:15 | 1분 미만 | 20초 미만 | 1분 미만 후 |
| 2000-01-01T00:00:05 | 1분 미만 | 10초 미만 | 1분 미만 후 |
| 2000-01-01T00:00:00 | 1분 미만 | 5초 미만 | 1분 미만 전 |
| 1999-12-31T23:59:35 | 1분 미만 | 30초 | 1분 미만 전 |
可归纳出韩语 distance 的翻译策略:
- 秒级:
lessThanXSeconds→{{count}}초 미만、xSeconds→{{count}}초、halfAMinute→ 固定串30초; - 分级近似:
aboutXHours→약 {{count}}시간、aboutXMonths→약 {{count}}개월、aboutXYears→약 {{count}}년; - 超过整年:
overXYears→{{count}}년 이상; - 后缀:未来加
후、过去加전,且comparison > 0才视为未来(类型定义见 locale/types.ts)。
includeSeconds: true时 15–25 秒区间输出20초 미만/30초等更细粒度结果;addSuffix: true时后缀(후/전)总是追加在完整短语末尾。
formatDistanceStrict:精确距离与强制单位
第三节的基准同样为 2000-01-01T00:00:00Z,但输出不再做"약/이상"近似,而是精确到所选单位,并展示unit: "hour"强制小时的换算效果:
| 日期 | Result | addSuffix: true | 强制 hour 单位 |
|---|---|---|---|
| 2006-01-01 | 6년 | 6년 후 | 52608시간 |
| 2001-06-01 | 1년 | 1년 후 | 12408시간 |
| 2000-06-01 | 5개월 | 5개월 후 | 3648시간 |
| 2000-01-15 | 14일 | 14일 후 | 336시간 |
| 2000-01-01T00:00:25 | 25초 | 25초 후 | 0시간 |
| 1999-12-31T23:59:35 | 25초 | 25초 전 | 0시간 |
| 1999-12-31T23:00:00 | 1시간 | 1시간 전 | 1시간 |
| 1994-01-01 | 6년 | 6년 전 | 52584시간 |
要点:formatDistanceStrict默认按最接近的自然单位输出(如 45 分 45초 附近输出 45분,00:45 与 00:30 均输出 45분/30분);当传入unit: "hour"时一切换算为整小时(向下取整,如 25 秒 → 0시간)。所有单位词干与formatDistance共用同一份 formatDistanceLocale,只是不再使用약/이상修饰。
formatRelative:相对日期模板
第四节基准为 2000-01-01T00:00:00Z,输出由 formatRelative/index.ts 的模板决定:
const formatRelativeLocale = { lastWeek: "'지난' eeee p", yesterday: "'어제' p", today: "'오늘' p", tomorrow: "'내일' p", nextWeek: "'다음' eeee p", other: "P", };| 日期 | Result |
|---|---|
| 2000-01-10 | 2000.01.10(超过一周,回落到P短日期) |
| 2000-01-05 | 다음 수요일 00:00(下周三) |
| 2000-01-02 | 내일 00:00 |
| 2000-01-01 | 오늘 00:00 |
| 1999-12-31 | 어제 00:00 |
| 1999-12-27 | 지난 월요일 00:00(上周一) |
| 1999-12-21 | 1999.12.21(超过一周) |
模板中的p使用formatLong的短时间格式HH:mm(故为 00:00),eeee输出完整星期名(수요일/월요일),'지난'/'다음'/'어제'/'오늘'/'내일'为韩语相对词,P即短日期y.MM.dd。超过一周的日期回落到普通日期格式。
formatDuration:Duration 对象格式化
最后一节覆盖formatDuration对 Duration 对象的输出,所有单位词干同样复用 formatDistanceLocale:
| Duration | Result |
|---|---|
{"years":0} | 0년 |
{"years":2} | 2년 |
{"months":2} | 2개월 |
{"weeks":2} | 2주 |
{"days":2} | 2일 |
{"hours":2} | 2시간 |
{"minutes":2} | 2분 |
{"seconds":2} | 2초 |
韩语没有英语的复数形态变化,1주与2주等单位词完全一致,仅数字变化,因此快照中0/1/2各值均可直接推导。
快照背后的实现原理与复现验证
序数后缀规则总结
从 ordinalNumber 可以提炼韩语序数三条规则,它解释了快照中几乎所有번째/일/纯数字的分布:
minute、second→ 纯数字(1、55);date→N일(1일、28일);- 其余单位(year、quarter、month、week、day-of-week、day-of-year、hour)→
N번째(1987번째、5개월属 distance 另行处理,11번째、42번째等)。
localize的其余部分用buildLocalizeFn统一构建(pkgs/core/src/_lib/buildLocalizeFn/index.ts),通过values、defaultWidth、argumentCallback、formattingValues等参数把上面看到的各 values 对象组装成format可直接调用的本地化函数。
match 层的解析边界
parse能否回推取决于 match/index.ts 是否覆盖对应 token:ordinalNumber用/^(\d+)(일|번째)?/i匹配数字与可选后缀,dayPeriod支持 오전/오후/자정/정오/아침/저녁/밤,quarter支持Q1–Q4与N분기,month/day支持N월与N요일。凡不在此列的(如z/zzzz时区名),parse 即返回Errored——这正是快照中 ppp/pppp 行全部 Errored 的根因。
手动复现快照
快照由 localeSnapshots 脚本 生成,仓库包内提供了对应脚本命令。复现或校验韩语快照:
# 在 pkgs/core 包目录下 TZ=utc pnpm run locale-snapshots # 重新生成全部 locale 快照(含 ko/snapshot.md) TZ=utc pnpm run locale-snapshots test # 校验磁盘快照与重新生成结果一致也可直接用 node 手动验证某个 token:
// 伪代码:TZ=utc 环境下 import { format } from "date-fns"; import { ko } from "date-fns/locale"; console.log(format(new Date("2019-02-11T12:13:14.015Z"), "EEEE", { locale: ko })); // 월요일test模式的意义在于:任何对 ko locale 翻译文本或模板的改动,只要改变输出,就会让快照与生成结果不一致而构建失败——快照因此成为韩语语言包的"行为契约"。
结语
ko 快照文档 以 5 组表格完整刻画了韩语语言包在 format/parse、formatDistance、formatDistanceStrict、formatRelative、formatDuration 五大 API 下的全部行为。结合 localize、match、formatLong、formatRelative、formatDistance 五份源码,可以清晰还原每个输出的来源:序数后缀由ordinalNumber按单位分发,时段词由dayPeriodValues提供,长格式由formatLong模板拼接,时区时间无法解析则是match未实现时区规则的如实反映。若需为韩语场景开发或校验本地化行为,直接以本快照为基准、以pnpm run locale-snapshots test为回归手段即可。
附:ko locale 由 Hong Chulju、Lee Seoyoen、Taiki IKeda 三位贡献者维护(见 index.ts 的 JSDoc 标注)。
【免费下载链接】date-fns⏳ Modern JavaScript date utility library ⌛️项目地址: https://gitcode.com/gh_mirrors/da/date-fns
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考