日期计算不踩坑:temporal-polyfill Duration 加减、舍入与差值计算的 10 个实用技巧
日期计算不踩坑temporal-polyfill Duration 加减、舍入与差值计算的 10 个实用技巧【免费下载链接】temporal-polyfillA lightweight polyfill for Temporal, successor to the JavaScript Date object项目地址: https://gitcode.com/gh_mirrors/tempo/temporalJavaScript 的Date对象在日期计算上一直让人头疼月份进位、时区偏移、时长比较处处是坑。作为Date的继任者Temporal 规范正在被各大浏览器逐步落地而temporal-polyfill就是一套轻量级仅约 19.5 kB且完全符合规范的兼容方案。它提供了Temporal.Duration类型专门负责时长计算——加减、舍入、差值、比较全部语义清晰、结果可控。这篇文章面向想快速上手的新手用 10 个实用技巧帮你把Duration 加减与舍入用得明明白白从此日期计算不再踩坑。1. 安装与引入三步开启 duration 计算 temporal-polyfill 的引入非常简单通过 npm 安装后一行代码即可注入全局npm install temporal-polyfillimport temporal-polyfill/global // 最常用的入口优先使用原生实现 const d new Temporal.Duration(0, 0, 0, 0, 1, 30) // 1 小时 30 分 d.toString() // PT1H30M如果不想污染全局命名空间也可以使用无副作用的 ponyfill 方式import { Temporal } from temporal-polyfill。核心类的实现代码位于 polyfill/src/classApi/full/duration.ts。2. 两种创建方式构造器与 from 解析 Temporal.Duration的构造器接受 10 个可选参数顺序固定年、月、周、天、时、分、秒、毫秒、微秒、纳秒const d1 new Temporal.Duration(1, 2, 0, 5, 10, 30) // 1年2月5天10小时30分更常用的是Duration.from()它既能解析ISO 8601 时长字符串也能接收普通对象const d2 Temporal.Duration.from(P1Y2M5DT10H30M) // 与 d1 等价 const d3 Temporal.Duration.from({ hours: 10, minutes: 30 }) 技巧和后端约定用 ISO 8601 字符串如PT90M传输时长from()与toString()双向转换零成本。3. 认识 sign 与 blank快速判断时长的正负与是否为空 ✍️在差值计算场景里经常要判断结果是提前还是推迟两个只读属性就够了const d Temporal.Duration.from({ minutes: -30 }) d.sign // -1负数 d.blank // false非零时长 Temporal.Duration.from({}).blank // true零时长实现上sign通过遍历所有字段符号计算得出见 polyfill/src/internal/durationMath.ts 中的computeDurationSign并且规定同一 Duration 内不允许混用正负字段否则直接抛错——这本身就是一种防呆设计。4. 纯时间单位的加减无需额外参数最省心 当两个 Duration 都只包含天及以下的时间单位天、时、分、秒……时add()和subtract()直接按纳秒换算无需任何额外参数const a Temporal.Duration.from({ hours: 2, minutes: 45 }) const b Temporal.Duration.from({ minutes: 30 }) a.add(b).toString() // PT3H15M a.subtract(b).toString() // PT2H15M5. 跨月/年单位加减必须提供 relativeTo ⚠️这是新手踩坑率最高的点只要涉及月、周、年等日历单位加减就必须传入relativeTo基准日期否则会抛出RangeError。原因很直观——一个月到底等于几天取决于具体是哪个月const oneMonth Temporal.Duration.from({ months: 1 }) // ❌ 报错missing relativeTo // oneMonth.add(Temporal.Duration.from({ days: 15 })) // ✅ 正确给一个明确的基准日期 oneMonth.add(Temporal.Duration.from({ days: 15 }), { relativeTo: Temporal.PlainDate.from(2026-02-01), }).toString() // P1M15D oneMonth.add(Temporal.Duration.from({ days: 15 }), { relativeTo: Temporal.PlainDate.from(2026-03-01), }).toString() // P1M15D实现逻辑在 polyfill/src/classApi/full/duration.ts 的add/subtract方法中当最大单位超过天且未提供relativeTo时会直接抛出missingRelativeTo错误。6. round() 舍入四个核心选项一次讲清 round()用于把时长舍入到指定精度常用选项包括选项作用示例smallestUnit最小保留单位minutelargestUnit最大展示单位hourroundingIncrement舍入增量5roundingMode舍入模式halfExpandconst d Temporal.Duration.from({ hours: 1, minutes: 47 }) // 舍入到最近的 5 分钟 d.round({ smallestUnit: minute, roundingIncrement: 5 }).toString() // PT1H45M // 全部折算成小时largestUnit 与 smallestUnit 均为 hour d.round({ largestUnit: hour, smallestUnit: hour }).toString() // PT2H7. 舍入月/年同样需要基准relativeTo 双保险 与加减一致对包含月份字段的 Duration 做舍入时也必须提供relativeTo。典型场景是把1年7个月舍入到年const d Temporal.Duration.from({ years: 1, months: 7 }) d.round({ largestUnit: year, relativeTo: Temporal.PlainDate.from(2026-01-01) }) // 结果为 2 年halfExpand 模式7 个月过半进位8. total()把时长折算成单一单位差值计算利器 total()用于回答这段时长总共等于多少 X 单位的问题返回数字而非 Durationconst d Temporal.Duration.from({ hours: 1, minutes: 30 }) d.total({ unit: hour }) // 1.5 d.total({ unit: minute }) // 90跨月换算同样需要relativeToconst d Temporal.Duration.from({ months: 2 }) d.total({ unit: day, relativeTo: Temporal.PlainDate.from(2026-01-01) }) // 611月31天 2月28天9. compare()两个时长谁大谁小差值判断不再手写 比较时长不能直接a bDuration 的valueOf被禁用防止隐式比较出错要用静态方法Duration.compare()const a Temporal.Duration.from({ hours: 3 }) const b Temporal.Duration.from({ minutes: 90 }) Temporal.Duration.compare(a, b) // 1a 更大 Temporal.Duration.compare(b, a) // -1 Temporal.Duration.compare(a, a) // 0如果比较涉及月份字段同样传入relativeTo作为第三参数确保一个月被公平换算。10. negated() 与 abs()处理方向性时长倒计时与退款业务中常有倒计时剩余时间或退款金额对应时长这类方向性需求const remaining Temporal.Duration.from({ minutes: 45 }) remaining.negated().toString() // -PT45M表示已超时/需要扣减 remaining.abs().toString() // PT45M取绝对值与 negated 结果互为相反数negated()将所有字段取反实现见negateDuration而abs()用于把可能为负的时长归一为正数配合sign属性可灵活处理正负分支逻辑。总结记住三条黄金法则 ✅纯时间单位天及以下加减、舍入、折算随便用无需额外参数。日历单位月/周/年任何计算都必须携带relativeTo基准日期。比较与传输用Duration.compare()做差值比较用 ISO 8601 字符串做跨端传输。掌握这 10 个技巧配合 temporal-polyfill 这套轻量级实现你的JavaScript 日期计算代码将更清晰、更少 bug。更多 API 细节可参考官方文档 docs/fns/duration.md 与 Duration 树摇 API 说明开始愉快的日期编程吧【免费下载链接】temporal-polyfillA lightweight polyfill for Temporal, successor to the JavaScript Date object项目地址: https://gitcode.com/gh_mirrors/tempo/temporal创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考