你或许觉得我疯了,没关系,我也这么认为。
记不清是从哪一刻开始了,也许是源于对
time.Time和现有时间库的不满与愤怒 —— 我产生了一个近乎荒诞的执念:我自己写一个 Go 时间库?这一切始于那个简陋、甚至可以说是有些 "丑陋" 的前身
thru,我决定对其系统化更新与重构。无数个灵感与想象如烟火般炸裂,才最终让它完成了跨越维度的蜕变。我将其正式命名为:Aeon。在古老的哲学中,Aeon 代表着 "永恒" 与 "层叠的维度"。
我选择这个名字,是因为它代表了时间更本质的逻辑 —— 时间不是一条细长的直线,它是流动的、是可以被嵌套和穿透的宇宙。
Aeon 是一个基于 时间容器 索引的 Go 时间导航库,用结构化导航替代线性计算,以更贴近人类时间直觉的方式表达复杂时间意图。
🎬 视频讲解
go get github.com/baagod/aeonAeon 的核心是基于 容器 偏移。所有 导航,本质上都是在 当前单位的父容器 中进行索引 (从 0 开始)。例如:
GoYear(5): 不是去公元 5 年,而是在 本年代 这个 父容器 中,索引 到第 5 年 ➜···5。GoDecade(2): 索引到 本世纪 第 2 个年代 ➜··2·。GoCentury(0): 索引到 本千年 第 0 个世纪 ➜·0··。
[千年 Millennium]
└─ [0...9 世纪 Century]
└─ [0...9 年代 Decade]
└─ [0...9 年份 Year]
└─ [1...12 月份 Month]
示例:GoYear(5) 寻址逻辑
[-9] [-8] [-5] [-4] [-1]
2020 ─┬─ 2021 ──┬── 2022 ··· ──┬── [2025] ──┬── 2026 ─┬─ ··· ─┬─ 2029
[0] [1] [2] [5] [6] [9]
Aeon 的 API 设计是完全 正交 的,你只需要记住 4 个动作:
Go.. [·]全绝定位:GoYear(5, 1)➜ 本年代第 5 年 1 月By.. [➜]全相偏移:ByYear(1, 5)➜ 偏移 1 年 5 月At.. [·, ➜]先定后移:AtYear(5, 1)➜ 定位到本年代的第 5 年再偏移 1 个月In.. [➜, ·]先移后定:InYear(1, 5)➜ 明年 5 月
Important
By系列方法默认值为1,其余为0。- 无效的
0时间 (如0月) 在 定位模式 下(而非偏移)保持不变。
之后,配合 Start/End 前缀可定位到时间边界:
StartYear(): 本年 开始时间 (01-01 00:00:00...)EndYear(): 本年 结束时间 (12-31 23:59:59...)
配合 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 个月的月末
链式调用?不,是原子操作!所有方法均支持 变长参数 向下级联,参数像水流,一行代码即可完成复杂定位。
Aeon 会根据 入口单位 自动切换 4 种不同的级联序列:
-
年序列
Default:世纪 ➜ 年代 ➜ 年 ➜ 月 ➜ 日 ➜ 时.. ➜ 纳秒 -
季度流
Quarter:季度 ➜ 月 (季内) ➜ 日 ➜ 时.. ➜ 纳秒 -
周序列
Week🦬:周 (智能上下文) ➜ 星期 ➜ 时.. ➜ 纳秒这是 变形金刚!它根据传入的 标志位 自动切换形态:
ISO: ISO 年周。从本年第 1 个 ISO 年周开始。Full: 完整周。从本月第 1 个周一开始。Ord: 序数周。从本月 1 日开始。Qtr: 季内周。从本季度首月 1 日开始。Default: 日历周/自然周,遵循日历行视觉。
-
星期流
Weekday:星期 ➜ 时.. ➜ 纳秒
// 相对偏移 1 年 3 月 5 日
ByYear(1, 3, 5)
// 本季度第 2 个星期二
GoWeek(aeon.Qtr|aeon.Ord, 2, 2)
// 本季度最后一个星期五
GoWeek(aeon.Qtr|aeon.Ord, -1, 5)
// 2025 年 2 月最后一天 23 点整
Go(2025).StartMonth(2, -1, 23)
// 本年第 3 个季度最后一个月,最后 2 天结束时间
EndQuarter(3, -1, -2)
// 2025 年第 10 个 ISO 周一
Go(2025).StartWeek(aeon.ISO, 10, 1)
// 本月从 1 日开始的第 3 个 "七天周" 周五(本月第 3 个星期五)
StartWeek(aeon.Ord, 3, 5)
// 本月最后一个周五
GoWeek(aeon.Ord, -1, 5)
// 上个季度结束时间
EndByQuarter(-1)
// 本季度最后一个月 1 号
StartQuarter(0, -1, 1)
// 本周五 18 点 (下班时间)
StartWeekday(5, 18)
// 本月倒数第 3 天
StartDay(-3)
// 下周三下午 2 点
StartInWeek(1, 3, 14)
// 年度归档:年初/年末边界
StartYear() / EndYear()
// 下个月最后一天
EndInMonth(1, -1)负数不仅仅是减法,它是 反向索引,代表在 "容器内倒数第 N 个"。
Aeon 的核心哲学是 意图优先,默认导航会保护 "月及以上单位" 溢出天数。
base := NewDate(2025, 1, 31)
base.GoMonth(2) // 2025-02-28 (保护)
base.ByMonth(Overflow, 1) // 2025-03-03 (溢出)
base.ByMonth(1, 2) // 🛡️🦬 2025-03-02 (保护到 2-28 再加2天)
// 跨年:从闰年到平年
leap := NewDate(2024, 2, 29)
leap.ByYear(1) // 2025-02-28 (保护)
leap.ByYear(Overflow, 1) // 2025-03-01 (溢出:跨月)
leap.ByYear(4) // 2028-02-29 (下一个闰年)Aeon 实现了 全零内存分配 (Zero Alloc),并得益于 级联寻址架构,无论你跨越多少个时间维度 (从千年到纳秒),Aeon 始终在 单次原子操作 内完成。逻辑越复杂,Aeon 的领先倍数就越惊人。
Note
以下基准数据在 未使用 级联参数的单一原子操作下测得。
Benchmark | ns/op | allocs/op x B/op | up
New |
Aeon | 18.6 | 0 | x74
Carbon | ██████████████████████████████████████████████████████████ 1376 | 13x1600
Now |
Aeon | 7.8 | 0 | x177
Carbon | ██████████████████████████████████████████████████████████ 1384 | 13x1600
From Unix |
Aeon | 3.6 | 0 | x383
Carbon | ██████████████████████████████████████████████████████████ 1380 | 13x1600
From Std |
Aeon | 5.0 | 0 | x323
Carbon | ██████████████████████████████████████████████████████████ 1619 | 13x1600
To Std |
Aeon | 7.9 | 0 | x179
Carbon | ██████████████████████████████████████████████████████████ 1411 | 13x1600
ISO8601 Parse |
Aeon | 34.7 | 0 | x241
Carbon | ██████████████████████████████████████████████████████████ 8371 | 163x6952
Add Overflow |
Aeon | █ 58.5 | 0 | x1.6
Carbon | ██ 93.0 | 2x128
Add NoOverflow |
Aeon | █ 56.2 | 0 | x2.5
Carbon | ████ 142 | 2x128
Set Overflow |
Aeon | ██ 60.8 | 0 |
Carbon | █ 37.4 | 0 | x1.6
Set NoOverflow |
Aeon | █ 58.2 | 0 | x2.7
Carbon | ███ 158 | 2x128
Start/End |
Aeon | █ 56.4 | 0 | x20
Carbon | ████████████████████ 1141 | 7x1440