A rigorous BaZi (Four Pillars) computation core in pure Swift.
Explicit rules, traceable boundaries, golden-fixture validation, and layered providers.
简体中文 · Report Issue · Releases
Table of Contents
- ✨ Features
- 🧩 Architecture
- 🗂️ Modules
- 🧠 Design Principles
- 📦 Installation
- 🚀 Usage
- 🔬 Validation
- ⚡ Performance
- 🗺️ Roadmap
- 📋 Supported Range
- 📚 References
- 📝 License
| Capability | Description | |
|---|---|---|
| 🎯 | Four Pillars | Year / month / day / hour pillars with configurable boundary rules |
| 🧭 | Traceable Boundaries | Li Chun, Jie boundaries, Zi hour, and true solar time travel with the chart |
| 📚 | Metaphysics Tables | Hidden stems, ten gods, five elements, NaYin, void branches, ShenSha — table-driven |
| 🔁 | Luck Cycles | DaYun, LiuNian, LiuYue, XiaoYun, and child-limit (起运) calculation |
| 🌙 | Calendar Provider | GanZhi and solar-term data via LunarCore-Swift |
| ☀️ | Astronomy Provider | True solar time and exact solar terms via AstroCore-Swift v3 |
| 🧱 | Layered Providers | Calendar and astronomy engines are swappable; the core binds to neither |
| 🧪 | Golden Fixtures | Self-generated baselines, cross-validated across 17,000+ charts including every boundary |
| 🧵 | Thread-Safe | Targeting full Sendable conformance |
| 🚫 | Isolated Tables | Derived metaphysics tables never leak into calendar engines |
BaziCore sits above calendar and astronomy libraries, keeping BaZi rules
separate from Chinese lunar calendar conversion and astronomical computation.
Each concern is a standalone product you can adopt independently.
BaziCore rules · inputs · pillar models · chart engine
│
├─ BaziCoreTables hidden stems · ten gods · five elements · NaYin · void · ShenSha
│
├─ BaziCoreLuck DaYun · LiuNian · LiuYue · XiaoYun · child-limit (needs Tables)
│
├─ BaziCoreLunarCoreAdapter GanZhi & solar-term data (via LunarCore-Swift)
│
├─ BaziCoreAstronomy true solar time & exact solar terms (via AstroCore-Swift v3)
│
└─ BaziCoreTesting golden fixture schemas · provider parity helpers
| Module | Depends on | Responsibility |
|---|---|---|
BaziCore |
— | Birth inputs, rule sets, pillar models, chart calculation |
BaziCoreTables |
BaziCore |
Hidden stems, ten gods, five elements, NaYin, void branches, ShenSha catalogs |
BaziCoreLuck |
BaziCore, BaziCoreTables |
DaYun, LiuNian, LiuYue, XiaoYun, and child-limit calculations |
BaziCoreLunarCoreAdapter |
BaziCore, LunarCore |
GanZhi and solar-term data backed by LunarCore-Swift |
BaziCoreAstronomy |
BaziCore, AstroCore |
True solar time and exact boundary support backed by AstroCore-Swift v3 |
BaziCoreTesting |
BaziCore |
Golden fixture schemas and provider parity helpers |
- Rules are explicit. Li Chun, Jie boundaries, Zi hour, and true solar time are represented in configuration — never hidden behind defaults.
- Results are traceable. Boundary decisions and provider confidence travel with the chart, so any value can be explained.
- Tables are isolated. Derived metaphysics tables do not leak into calendar or astronomy engines.
- Validation is thorough. Golden fixtures are generated by our own engines and cross-validated across 17,000+ charts spanning more than a century, including leap days, 时辰 boundaries, and every solar-term edge.
Add the dependency:
dependencies: [
.package(url: "https://github.com/wbx1-Ltd/BaziCore-Swift.git", from: "1.1.0"),
]Then add only the products you need as target dependencies:
.target(
name: "YourTarget",
dependencies: [
"BaziCore", // core rules & chart engine
"BaziCoreTables", // metaphysics tables
"BaziCoreLuck", // luck-cycle calculations
"BaziCoreLunarCoreAdapter", // GanZhi & solar terms via LunarCore
"BaziCoreAstronomy", // true solar time via AstroCore
]
),Or in Xcode: File → Add Package Dependencies… → paste the URL above.
Compute a chart from a birth moment. The calculator needs a solar-term provider;
BaziCoreAstronomy ships the high-precision one.
import BaziCore
import BaziCoreAstronomy
let moment = try CivilMoment(
year: 1995, month: 6, day: 15, hour: 8, minute: 30,
timeZoneIdentifier: "Asia/Shanghai"
)
let input = BirthInput(moment: moment, sexForLuckCycle: .female)
let solarTerms = AstronomicalSolarTermProvider.shared
let calculator = BaziCalculator(solarTermProvider: solarTerms)
let chart = try calculator.chart(for: input)
print(chart.fourPillars.chinese) // 乙亥 壬午 丁丑 甲辰
print(chart.dayMaster.chinese) // 丁Every chart carries a trace so any value can be explained:
chart.trace.provider // .astronomy
chart.trace.confidence // .canonical
chart.trace.notes // [.yearBoundaryLiChunExact, .birthBeforeLiChun, …]For batch calculation, warm likely years once and reuse the same provider:
solarTerms.prewarm(gregorianYears: 1995...1996)Derive metaphysics tables and ShenSha from BaziCoreTables:
import BaziCoreTables
let tenGod = TenGodEngine.tenGod(of: chart.fourPillars.year.stem, dayMaster: chart.dayMaster)
let naYin = NaYinTable.naYin(for: chart.fourPillars.day.cycle)
let shenSha = ShenShaCatalog.ziPingCommon.evaluate(chart: chart)Compute luck cycles from BaziCoreLuck:
import BaziCoreLuck
let direction = LuckDirection.resolve(yearStem: chart.fourPillars.year.stem, sex: .female)
let childLimit = try ChildLimitEngine.compute(
birth: moment, direction: direction, rule: .threeDaysPerYear,
provider: solarTerms
)
let daYun = DaYunEngine.compute(
monthPillar: chart.fourPillars.month.cycle, birthGregorianYear: 1995,
childLimit: childLimit, direction: direction
)For true solar time, set the rule and inject a corrector:
var rules = BaziRuleSet.professionalDefault
rules.timeCorrection = .trueSolarTime
let calculator = BaziCalculator(
ruleSet: rules,
solarTermProvider: solarTerms,
timeCorrectionProvider: TrueSolarTimeEngine()
)
let chart = try calculator.chart(for: BirthInput(
moment: moment,
location: CalculationLocation(longitude: 87.6)
))BaziCoreTesting defines golden-fixture schemas and provider parity helpers so
that every chart can be checked against independent, source-backed references
rather than a single engine's opinion.
| Strategy | Description |
|---|---|
| Golden fixtures | Versioned expected charts stored as fixtures and replayed in CI |
| Provider parity | Same input run through different calendar/astronomy providers must agree |
| Cross-validation | Engine output checked across 17,000+ charts and the full solar-term range, to the second |
| Boundary cases | Li Chun, Jie transitions, late Zi hour, and true-solar-time edges |
Measured on Apple Silicon, release build.
| Metric | Result | |
|---|---|---|
| 🏎️ | Four-pillar throughput | ~25,000 charts/sec (≈40 µs/chart, warm) |
| 🔮 | With full luck cycle | ~19,000 charts/sec (≈53 µs/chart) |
| ❄️ | Cold single chart | ~5 ms (first chart computes solar terms) |
| 🌞 | Child-limit boundary lookup | Nearby Jie fast path for natural providers, with full-scan fallback |
| 🧠 | Memory | ~8 MB steady — flat from 20k to 200k charts, no leaks |
| ✅ | Validation | 17,000+ charts cross-checked across 1902–2099, zero discrepancies |
Solar-term instants are computed to the second. The bounded term cache is thread-safe and never grows unbounded.
For batch workloads, reuse AstronomicalSolarTermProvider.shared and call
prewarm(gregorianYears:) before chart calculation to keep solar-term roots warm
across charts and luck-cycle calculations.
The computation layers are complete, cross-validated, and shipped in 1.0.0.
- Package layout, six-module split, and CI (format / lint / test)
- Birth inputs and configurable rule sets
- Four Pillars chart engine
- Metaphysics tables (
BaziCoreTables) - Calendar and astronomy adapters (
LunarCore/AstroCore) - Luck-cycle calculations (
BaziCoreLuck) - Golden fixtures and cross-validation suite (
BaziCoreTesting) - First tagged release (
1.0.0) - AstroCore v3 migration and shared solar-term cache (
1.1.0)
| Item | Range | |
|---|---|---|
| 🖥️ | Platforms | iOS 15+ · macOS 12+ · tvOS 15+ · watchOS 8+ · visionOS 1+ |
| 🔧 | Swift | 6.0+ |
| 🌙 | Calendar provider | LunarCore-Swift 1.2.0+ |
| ☀️ | Astronomy provider | AstroCore-Swift 3.0.0+ |
| Source | Usage |
|---|---|
LunarCore-Swift |
GanZhi and solar-term data provider |
AstroCore-Swift |
True solar time, precise solar terms, and JD-native astronomy primitives |
Copyright © 2026-present wbx1 Ltd..
This project is MIT licensed.