You might think I'm crazy. That's okay, I think so too.
I don't remember exactly when it started. Maybe it was born out of frustration and anger with
time.Timeand existing time libraries. I developed a borderline absurd obsession: "Why don't I write my own Go time library?"It all began with a crude, perhaps even "ugly" prototype called
thru. I decided to systematically refactor and rewrite it from the ground up. Countless ideas exploded like fireworks, eventually leading to a metamorphosis across dimensions.I named it Aeon. In ancient philosophy, Aeon represents "eternity" and "layered dimensions".
I chose this name because it represents the truer logic of timeโtime is not a thin, linear line; it is a flowing universe that can be nested and penetrated.
๐จ๐ณ ไธญๆ | ๐บ๐ธ English
Aeon is a Zero-Allocation time navigation library for Go based on Time Containers. It replaces linear calculation with structured navigation, expressing complex time intentions in a way that aligns with human intuition.
Aeon achieves True Zero Allocation (Zero Alloc) and leverages a Cascading Addressing architecture. Whether you span multiple dimensions (from Millennium to Nanosecond), Aeon completes the operation in a single atomic step. The more complex the logic, the more staggering Aeon's lead becomes.
Note
The following baseline data were obtained under single-atom operations without using cascade parameters.
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
Parse (Compact) |
Aeon | 23.3 | 0 | x195
Carbon | โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ 4561 | 85x3922
Parse (ISO) |
Aeon | 19.6 | 0 | x91
Carbon | โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ 1794 | 15x1697
Start/End |
Aeon | โ 56.4 | 0 | x20
Carbon | โโโโโโโโโโโโโโโโโโโโ 1141 | 7x1440
Add (Offset) |
Aeon | โ 56.5 | 0 | x2.5
Carbon | โโ 142 | 2x128
Set (Position) |
Aeon | โ 58.7 | 0 | x2.6
Carbon | โโโ 156 | 2x128go get github.com/baagod/aeonThe core of Aeon is Container Offset. All navigation is essentially indexing within the Parent Container of
the current unit (starting from 0). For example:
GoYear(5): Not going to the year 5 AD, but indexing to the 5th year within the current Decade (the parent container) โยทยทยท5.GoDecade(2): Indexing to the 2nd Decade of the current Century โยทยท2ยท.GoCentury(0): Indexing to the 0th Century of the current Millennium โยท0ยทยท.
[Millennium]
โโ [0...9 Century]
โโ [0...9 Decade]
โโ [0...9 Year]
โโ [1...12 Month]
Example: GoYear(5) Addressing Logic
[-9] [-8] [-5] [-4] [-1]
2020 โโฌโ 2021 โโโฌโโ 2022 ยทยทยท โโโฌโโ [2025] โโโฌโโ 2026 โโฌโ ยทยทยท โโฌโ 2029
[0] [1] [2] [5] [6] [9]
Aeon's API design is completely Orthogonal. You only need to remember 4 Actions:
Go.. [ยท]Absolute Positioning:GoYear(5, 1)โ 5th Year, 1st Month of current decade.By.. [โ]Relative Offset:ByYear(1, 5)โ Offset by 1 Year and 5 Months.At.. [ยท, โ]Position then Offset:AtYear(5, 1)โ Locate 5th Year, then offset 1 Month.In.. [โ, ยท]Offset then Position:InYear(1, 5)โ Next Year (Offset 1), then 5th Month.
Important
Bymethods default to1. Others default to0.- Invalid
0time (e.g., 0th Month) remains unchanged in Positioning Mode (but works in Offset mode).
Combined with Start/End prefixes to hit time boundaries:
StartYear(): Start of this year (01-01 00:00:00...)EndYear(): End of this year (12-31 23:59:59...)
6 Top-Level methods allow the first parameter to enter Absolute Year mode:
Go(2025, 2)โ 2025-02At(2025, 2)โ Position at 2025, then offset 2 months.Start(2025, 2)โ 2025-02-01 00:00:00StartAt(2025, 1)โ Position at 2025, offset 1 month, then Start of Month.End(2025, 2)โ 2025-02-28 23:59:59...EndAt(2025, 1)โ Position at 2025, offset 1 month, then End of Month.
Method chaining? No, this is Atomic Operation! All methods support Variadic Parameters that cascade downwards. Parameters flow like water, completing complex positioning in one line of code.
Aeon automatically switches between 4 cascading sequences based on the Entry Unit:
-
Year Sequence
Default:Century โ Decade โ Year โ Month โ Day โ Hour.. โ Nanosecond -
Quarter Flow
Quarter:Quarter โ Month (in Quarter) โ Day โ Hour.. โ Nanosecond -
Week Sequence
Week๐ฆฌ:Week (Smart Context) โ Weekday โ Hour.. โ NanosecondThis is a Transformer! It automatically shifts shape based on the passed Flags:
ISO: ISO Week. Starts from the 1st ISO week of the year.Full: Full Week. Starts from the 1st Monday of the month.Ord: Ordinal Week. Starts from the 1st day of the month.Qtr: Quarter Week. Starts from the 1st day of the quarter's first month.Default: Calendar/Natural Week. Follows the calendar visual row.
-
Weekday Flow
Weekday:Weekday โ Hour.. โ Nanosecond
// Relative offset: 1 Year, 3 Months, 5 Days
ByYear(1, 3, 5)
// 2nd Tuesday of the current Quarter
GoWeek(aeon.Qtr|aeon.Ord, 2, 2)
// Last Friday of the current Quarter
GoWeek(aeon.Qtr|aeon.Ord, -1, 5)
// 2025, Feb, Last Day, 23:00
Go(2025).StartMonth(2, -1, 23)
// End of the 3rd Quarter, minus 1 month, minus 2 days
EndQuarter(3, -1, -2)
// 10th ISO Monday of 2025
Go(2025).StartWeek(aeon.ISO, 10, 1)
// 3rd Friday of this month (Ordinal week starting from 1st)
StartWeek(aeon.Ord, 3, 5)
// Last Friday of this month
GoWeek(aeon.Ord, -1, 5)
// End of previous Quarter
EndByQuarter(-1)
// 1st day of the last month of this Quarter
StartQuarter(0, -1, 1)
// This Friday at 18:00 (Happy Hour)
StartWeekday(5, 18)
// 3rd to last day of this month
StartDay(-3)
// Next Wednesday at 2 PM
StartInWeek(1, 3, 14)
// Yearly Archive: Start/End boundaries
StartYear() / EndYear()
// Last day of next month
EndInMonth(1, -1)Negative numbers are not just subtraction; they are Reverse Indexing, representing the "N-th from last" item in the container.
Aeon's core philosophy is Intention First. By default, navigation protects against day overflow for units "Month and above".
base := NewDate(2025, 1, 31)
base.GoMonth(2) // 2025-02-28 (Protected)
base.ByMonth(Overflow, 1) // 2025-03-03 (Overflow allowed)
base.ByMonth(1, 2) // ๐ก๏ธ๐ฆฌ 2025-03-02 (Protect to 2-28, then add 2 days)
// Leap Year Handling
leap := NewDate(2024, 2, 29)
leap.ByYear(1) // 2025-02-28 (Protected)
leap.ByYear(Overflow, 1) // 2025-03-01 (Overflow: Crosses month boundary)
leap.ByYear(4) // 2028-02-29 (Next Leap Year)