你或许觉得我疯了,没关系,我也这么认为。
记不清是从哪一刻开始了,也许是源于对
time.Time和现有时间库的不满与愤怒 —— 我产生了一个近乎荒诞的执念:我自己写一个 Go 时间库?这一切始于那个简陋、甚至可以说是有些 “丑陋” 的前身
thru,我决定对其系统化更新与重构。无数个灵感与想象如烟火般炸裂,才最终让它完成了跨越维度的蜕变。我将其正式命名为:Aeon。在古老的哲学中,Aeon 代表着 “永恒” 与 “层叠的维度”。
我选择这个名字,是因为它代表了时间更本质的逻辑 —— 时间不是一条细长的直线,它是流动的、是可以被嵌套和穿透的宇宙。
Aeon 是一个试图重塑 Go 语言时间操作体验的库。它不只是教你 “拨动时钟”,还教你如何 操控时空结构。
go get github.com/baagod/aeon要掌握 Aeon 时间导航,你只需要理解一个核心概念:容器。
即,所有 时间导航 操作,本质上都是在 当前单位的父级容器 中进行 Zero-based (从 0 开始) 寻址。
GoYear(5): 不是去公元 5 年,而是在 本年代 这个 父级容器 中,索引 到第 5 年 ➜···5。GoDecade(2): 索引到 本世纪 第 2 个年代 ➜··2·。GoCentury(0): 是索引到 本千年 第 0 个世纪 ➜·0··。
在现实世界中,没有第 0 个世纪,这样设计是为了更简洁和直观表达。例如:GoCentury(1) ➜ 21··
Aeon 的 API 设计是完全 正交 的,你只需要记住 4 个动作,就能推导出所有 API。
Go..全绝对定位 (abs, abs..):GoYear(5)➜ 本年代第 5 年Add/By..全相对偏移 (rel, rel..):AddYear(1)➜ 明年At..先定后移 (abs, rel, rel..):AtYear(5, 1)➜ 在本年代的第 5 年偏移 1 个月In..先移后定 (rel, abs, abs..):InYear(1, 5)➜ 明年 5 月
提示:
By是Add在Start/End前缀下的别名,它们逻辑完全相同。Add系列方法的默认值为1,其余为0。
在上述 4 个动作 加入 Start/End 前缀,能定位到该时间单位的 边界。
Start..(归零):将所有下级时间单位归零。如00:00:00.000..。End..(置满):将所有下级时间单位置满。如23:59:59.999..。
示例:
StartYear(5)(对应Go):本年代第 5 年的 年初 (01-01 00:00:00.000..)。StartByYear(1)(对应Add):明年 年初。StartAtYear(5, 1)(对应At):本年代第 5 年偏移 1 个月的 月初 (01 00:00:00.000..)。StartInYear(1, 5)(对应In):明年 5 月初。
Aeon 提供了 6 个顶级方法作为进入 “绝对年份” 入口。
规则非常简单:首个 参数永远代表着 绝对年份,后续 参数的行为完全遵循 导航矩阵。
Go(2025, 2)➜ 2025-02At(2025, 2)➜ 定位到 2025 年后再偏移 2 个月Start(2025, 2)➜ 2025-02-01 00:00:00StartAt(2025, 1)➜ 定位到 2025 年后再偏移 1 个月的月初End(2025, 2)➜ 2025-02-28 23:59:59...EndAt(2025, 1)➜ 定位到 2025 年后再偏移 1 个月的月末
链式调用?不,是原子操作!GoYear(5, 2, 1) ➜ 2025-02-01。
所有方法均支持 变长参数 向下级联,参数像水流,一行代码即可完成复杂定位。
Aeon 会根据 入口单位 自动切换 4 种不同的级联序列。
- 标准流
Default:世纪 ➜ 年代 ➜ 年 ➜ 月 ➜ 日 ➜ 时.. ➜ 纳秒 - 季度流
Quarter:季度 ➜ 月 (季内) ➜ 日 ➜ 时.. ➜ 纳秒 - 月周流
Week:周 (月内) ➜ 星期 ➜ 时.. ➜ 纳秒 - 年周流
YearWeek:年周 ➜ 星期 ➜ 时.. ➜ 纳秒
在级联中,负数参数不仅仅是减法,它是 反向索引,代表在 “容器内倒数第 N 个”。
这让你无需关心大月小月或平闰年,直接定位 “尾部”。
场景 1:标准流 + 反向寻址 寻找 "2025年,第2个月,最后一天,23点"
// 1. Go(2025): 顶级入口,定位年份
// 2. StartMonth(2): 2月
// 3. 参数 -1: 倒数第一天 (28日)
// 4. 参数 23: 23点
t.Aeon().Go(2025).StartMonth(2, -1, 23)场景 2:季度流 + 边界置满 寻找 "本年第 3 季度的最后一个月,最后一天"
// 1. EndQuarter(3): 定位到第3季度结束时刻
// 2. 参数 -1: 季度的最后一个月 (9月)
// 3. 参数 -1: 月的最后一天 (30日)
t.EndQuarter(3, -1, -1)场景 3:年周流 + 精准定位 寻找 "2025年第 10 周的周五,上午 9 点"
// 1. Go(2025): 定位到 2025 年
// 2. StartYearWeek(10, 5, 9):
// - YearWeek: 10 (第10周)
// - Weekday: 5 (周五)
// - Hour: 9 (9点)
t.Go(2025).StartYearWeek(10, 5, 9)Aeon 默认拦截非预期的日期溢出,但也赋予你打破规则的权利。
t := aeon.NewDate(2025, 1, 31)
// 默认行为:智能截断
t.GoMonth(2) // -> 2月28日 (自动截断)
// 显式溢出:打破容器限制
t.GoMonth(aeon.Overflow, 2) // -> 3月3日 (2月28 + 3天)Aeon 不仅追求语义的优雅,更追求极致的性能。
- Zero Alloc: 核心导航逻辑 0 内存分配。
- Bitmask Protocol: 我们将
ISO,Overflow等配置压缩进了int参数的高位,避免了创建配置对象的开销。 - Nano Precision: 全链路支持纳秒级对齐,
End*方法精准覆盖到.999999999,确保数据库范围查询不漏数据。