mazeye/swiftstembranch
A high-precision Chinese Gan-Zhi (Stem-Branch) calendar library for Swift.
✨ Features
- Pure Swift Extension: Directly extends
Datefor seamless integration. - High Precision: Uses simplified VSOP87/Meeus algorithms to calculate Apparent Solar Longitude for precise solar term determination.
- True Solar Time: Automatically corrects time based on longitude and Equation of Time (EoT).
- Scientific Day Calculation: Uses Julian Day algorithms to eliminate timezone and leap year drifts.
- Dynamic Energy System: Precise strength calculation for Five Elements and Ten Gods using seasonal coefficients (1.4/1.2/1.0/0.8/0.6), rooting strength (supports heterogeneous roots at 50%), distance decay, and branch interaction (San He/San Hui) bonuses.
- Mixed Rooting Logic: Accurate energy support matching both strict characters and same-element different-polarity stems (e.g., Bing Fire sitting on Ding Fire gets 50% support), keeping energy levels realistic while maintaining strict pattern analysis.
- Relationship Detection: Automatically detects combinations, clashes, harms, punishments, and destructions (刑冲会合).
📦 Installation
Swift Package Manager
Add the following to your Package.swift:
dependencies: [
.package(url: "https://github.com/YOUR_USERNAME/SwiftGanZhi.git", from: "1.0.0")
]Or in Xcode: File > Add Packages... > Enter repository URL.
🚀 Quick Start
### 1. Basic Usage (Mean Solar Time)
```swift
import GanZhi
// Initialize a Date (using the provided helper or standard methods)
let date = Date(year: 2024, month: 2, day: 4, hour: 16, minute: 30)!
// Get Four Pillars directly from Date
let pillars = date.fourPillars()
print(pillars.description)
// Output: 甲辰年 丙寅月 戊戌日 庚申时
```
### 2. Advanced Usage (True Solar Time)
Location matters. The library can adjust the time column based on longitude.
```swift
import GanZhi
// Birthplace: Urumqi (Longitude 87.6°), Time: Beijing Time 10:00
let date = Date(year: 2024, month: 6, day: 15, hour: 10, minute: 0)!
let urumqi = Location(longitude: 87.6, timeZone: 8.0)
// Get corrected pillars
let pillars = date.fourPillars(at: urumqi)
print(pillars.hour.character)
// Original 10:00 is Si Hour (Snake)
// Corrected time is approx 07:50, which is Chen Hour (Dragon)
```
### 3. Ten Gods Analysis
Calculate the Ten Gods (Shi Shen) relationships for Stems and Branches (based on Hidden Stems/Main Qi):
```swift
let pillars = date.fourPillars()
// Get Ten God for a Stem
// Note: Stem/Branch are now wrappers. Property access is transparent.
let stemTenGod = pillars.tenGod(for: pillars.year.stem)
print(stemTenGod.name) // e.g., "Rob Wealth"
// Accessing energy
let energy = pillars.month.stem.energy
print("Month Stem Energy: \(energy)")
// In some cases (e.g., matching or strict type passing), use .value for the raw enum
let rawStem: Stem = pillars.day.stem.value
### 4. Relationship Detection (刑冲会合)
Detect all interactions between pillars, including celestial and earthly interactions.
```swift
let relationships = pillars.relationships
for rel in relationships {
// e.g., "[Year-Month] Zi-Wu Branch Clash"
print(rel.description)
}
```
Support detection:
- **Stem**: Combination (五合), Clash (相冲).
- **Branch**: Six Harmony (六合), Triple Harmony (三合), Directional (三会), Clash (六冲), Harm (六害), Punishment (相刑), Destruction (相破).
```
### 5. Hidden Stems Analysis (Main, Middle, Residual Qi)
Access the detailed hidden stems and their corresponding Ten Gods for any branch.
```swift
let pillars = date.fourPillars()
// Get hidden stems and their Ten Gods
let hidden = pillars.hiddenTenGods(for: pillars.month.branch)
// Main Qi (Stem, TenGods)
print("Main Qi: \(hidden.benQi.stem.character) [\(hidden.benQi.tenGod.name)]")
// Middle Qi (Optional<(Stem, TenGods)>)
if let zhong = hidden.zhongQi {
print("Middle Qi: \(zhong.stem.character) [\(zhong.tenGod.name)]")
}
// Residual Qi (Optional<(Stem, TenGods)>)
if let yu = hidden.yuQi {
print("Residual Qi: \(yu.stem.character) [\(yu.tenGod.name)]")
}
```
### 6. GeJu (Pattern) Determination
Automatically determine the chart pattern based on traditional rules (Month Qi priority, Stem penetration, etc.). For auxiliary pattern detection in Peer-type charts (Jian Lu, Yang Ren), the auxiliary must dominate the entire "Self Group" (combined energy of Day Master, Friend, and Rob Wealth) for increased rigor.
```swift
let pattern = pillars.determinePattern()
print("Pattern: \(pattern.description)") // e.g., "Direct Resource Pattern"
print("Basis: \(pattern.method.description)") // e.g., "Month Branch Main Qi"
print("Core Ten God: \(pattern.tenGod.name)") // e.g., "Direct Resource"
```
### 7. Luck Cycles & Annual Luck (Da Yun & Liu Nian)
Calculate the Start Age, Major Luck Cycles (Da Yun), and derive Annual Luck (Liu Nian).
```swift
let calculator = LuckCalculator(gender: .male, pillars: pillars, birthDate: date)
// 1. Get Start Age
let startAge = calculator.calculateStartAge()
print("Start Age: \(startAge)")
// 2. Get Major Cycles (Default: 10 cycles)
let cycles = calculator.getMajorCycles()
for cycle in cycles {
print(cycle.description) // e.g. "Bing-Yin Cycle (Start: 3.4 yrs, 1987-1996)"
// 3. Derive Annual Luck (Liu Nian)
// Iterate through years in the cycle
for year in cycle.startYear...cycle.endYear {
// Calculate Stem-Branch for the year
// 1984 is Jia-Zi (Index 0)
let offset = year - 1984
var index = offset % 60
if index < 0 { index += 60 }
let yearSB = StemBranch.from(index: index)
let age = year - Calendar.current.component(.year, from: date)
print(" \(year) \(yearSB.character) (Age: \(age))")
}
}
```
### 8. Shen Sha Analysis (Stars/Gods)
#### 8.1 Branch-based Stars
Analyze common Shen Sha based on Life Stages and Five Elements relationships within specific branches.
```swift
let branch = pillars.month.branch
let stars = pillars.shenSha(for: branch)
if !stars.isEmpty {
// Use .name for localized output
print("Stars: \(stars.map { $0.name }.joined(separator: " "))")
// e.g., "Stars: Nobleman Traveling Horse"
}
```
#### 8.2 Global Situations (Chart-wide Patterns)
Analyze patterns that apply to the entire chart or specific pillar combinations (e.g., San Qi, Kui Gang).
```swift
let globalSituations = pillars.allGlobalSituations
if !globalSituations.isEmpty {
print("Global Situations: \(globalSituations.joined(separator: " "))")
// e.g., "Global Situations: Three Wonders Kui Gang Nobleman"
}
```
Built-in support: Three Wonders (San Qi), Kui Gang, Golden Spirit, Ten Evils Big Failure, Heavenly Unity, etc.
#### 8.3 Register Custom Situation
SwiftGanZhi allows you to define custom rules to support different schools of thought.
```swift
// Register a "Pure Yang" rule
GlobalSituationRegistry.register("Pure Yang") { pillars in
let stems = [pillars.year.stem, pillars.month.stem, pillars.day.stem, pillars.hour.stem]
let branches = [pillars.year.branch, pillars.month.branch, pillars.day.branch, pillars.hour.branch]
return stems.allSatisfy { $0.yinYang == .yang } &&
branches.allSatisfy { $0.yinYang == .yang }
}
// The rule will be automatically checked when calling .allGlobalSituations
```
### 9. Internationalization (i18n)
Supports Simplified Chinese (Default), Traditional Chinese, Japanese, and English.
```swift
// Switch language
GanZhiConfig.language = .english
let stem = Stem.jia
print(stem.character) // Output: "Jia"
let tenGod = TenGods.friend
print(tenGod.name) // Output: "Friend"
```
Note: Use `.name` or `.description` properties instead of `.rawValue` to get localized strings.
### 10. Thermal Balance (Temperature & Moisture)
Analyze the "Han Nuan Zao Shi" (Cold/Warm/Dry/Wet) balance of the chart.
- **Temperature**: Calculated based on Fire element strength (and Life Stages).
- **Moisture**: Calculated based on Water (mirroring Fire logic) and Earth content.
- **States**: Automatically detects "Frozen" (Temp ≤ 0) and "Vapor" (Temp > 100) states.
```swift
let tb = pillars.thermalBalance
print(String(format: "Temperature: %.2f", tb.temperature))
print(String(format: "Moisture: %.2f", tb.moisture))
if tb.isFrozen {
print("Status: Frozen")
} else if tb.isVapor {
print("Status: Vapor")
}
```
### 11. Useful God Analysis (Yong Shen)
Determine the "Useful God" (Yong Shen) and "Ji God" (Negative God) using three different methods:
1. **Pattern Method (Ge Ju Fa)**: Traditional approach based on chart structure and Ten Gods patterns (e.g., Officer Pattern, Wealth Pattern).
2. **Wang Shuai Method (Strength)**: Balances the chart based on the strength of the Day Master (Weak/Strong/Follow).
3. **Tiao Hou Method (Climate)**: Adjusts temperature and moisture (Cold/Warm/Dry/Wet) using specific stems.
```swift
// 1. Default Analysis (Pattern Method)
let analysis = pillars.usefulGodAnalysis
// 2. Specify Method Explicitly
let patternResult = pillars.calculateUsefulGod(method: .pattern)
let strengthResult = pillars.calculateUsefulGod(method: .wangShuai)
let climateResult = pillars.calculateUsefulGod(method: .tiaoHou)
print("--- Pattern Method ---")
print("Useful Gods: \(patternResult.yongShen.map { $0.name })")
print(patternResult.description)
print("--- Wang Shuai Method ---")
print("Useful Gods: \(strengthResult.yongShen.map { $0.name })")
print(strengthResult.description)
print("--- Climate Method ---")
print("status: \(climateResult.description)")
```
### 12. Dynamic Relationship Analysis (Generic)
Analyze relationships between *any* two Stem-Branch pairs, useful for comparing the Chart against Dynamic Pillars (Grand Luck / Annual Luck / "Liu Nian").
It supports detection of:
- **Duplicates**: Fu Yin (伏吟)
- **Clashes**: Fan Yin (反吟 - Heaven Clash & Earth Clash)
- **Standard**: Combinations, Clashes, Harm, Punishment, Destruction
```swift
// 1. Create a Chart
let chart = FourPillars(date: Date())
// 2. Define a Dynamic Pillar (e.g., Grand Luck "Jia-Chen")
let grandLuck = StemBranch(stem: .jia, branch: .chen)
// 3. Analyze Relationships (e.g., Year Pillar vs. Grand Luck)
let yearRels = Relationship.analyze(
lhs: chart.year.value,
rhs: grandLuck,
lhsName: "Year",
rhsName: "Grand Luck"
)
// Print results
for rel in yearRels {
// Method 1: Direct Description (Old Way)
// print(rel.description)
// [Year-Grand Luck] 辰酉地支六合 Branch Six Harmony
// Method 2: Structured Access (New Way)
let info = rel.listing
print("Pillars: \(info.pillars)") // "Year-Grand Luck"
print("Characters: \(info.characters)") // "ChenYou"
print("Type: \(info.type)") // "Branch Six Harmony"
}
```📄 License
MIT License. See LICENSE for details.
Package Metadata
Repository: mazeye/swiftstembranch
Default branch: main
README: README.md