Package Exports
- @aharris02/bazi-calculator-by-alvamind
- @aharris02/bazi-calculator-by-alvamind/package.json
Readme
Bazi Calculator (TypeScript Port)
⚠️ This is a fork of the original bazi-calculator-by-alvamind and incorporates work from bazica by tommitoan, published by @aharris02 for compatibility with modern TypeScript builds and deployment environments (e.g. Vercel).
A modern, accurate, and comprehensive Bazi (八字 / Four Pillars of Destiny) calculator and analyzer with robust timezone handling and advanced features.
📢 Disclaimer
This package is provided for educational and research purposes only. The calculations and interpretations should not be used as the sole basis for making important life decisions. Chinese Metaphysics and Bazi analysis require professional expertise and years of study.
✨ Key Features
Core Calculations
- Four Pillars (四柱) Calculation: Accurate Year, Month, Day, and Hour pillar determination.
- Timezone-Aware Processing: Requires IANA timezone strings (e.g.,
America/New_York
,Asia/Shanghai
). - Unknown Birth Time Handling: Gracefully calculates when exact birth time is unknown.
- Luck Pillars Calculation: Determines 10-year Luck Pillar sequence with direction and precise start age.
- Gender Normalization: Accepts various gender inputs but normalizes to
'male'
or'female'
, since Bazi is based on binary genders.
Analysis Components
- Five Elements (五行) Analysis: Element distribution with relationship weighting.
- Day Master (日主) Analysis: Stem, Element, Yin/Yang properties.
- Eight Mansions (八宅) Feng Shui: Life Gua calculation with favorable/unfavorable directions.
- Destiny Indicators: Nobleman (貴人), Intelligence Star (文昌), Sky Horse (天馬), Peach Blossom (桃花).
- Stem & Branch Interactions: Comprehensive detection of Combinations, Clashes, Harms, Punishments, and Destructions within Natal chart and with Luck/Timed Pillars.
- Ten Gods (十神) Calculation: Determines the Ten Gods relationships between Heavenly Stems (Natal, Luck, Timed).
- Day Master Strength Assessment: Provides an estimated strength of the Day Master.
- Favorable Elements Suggestion: Suggests potentially favorable elements based on Day Master strength.
- Timed Event Analysis:
getAnalysisForDate(targetDate, targetTimezone, options)
: Provides detailed analysis for a single specific day, either in a 'general' context (the day's own chart) or 'personalized' (how that day interacts with a natal chart).getAnalysisForDateRange(startDate, endDate, targetTimezone, options)
: Provides daily analysis for a range of dates, supporting both 'general' and 'personalized' modes.
Technical Features
- 🔒 Type-safe with TypeScript
- 📦 ES Module Support
- 🌐 Timezone-correct calculations via
date-fns-tz
- 📝 Comprehensive Type Definitions (see
src/types.ts
and exported types) - ⚡ Optimized Performance
🚀 Installation
# Using npm
npm install @aharris02/bazi-calculator-by-alvamind date-fns date-fns-tz
# Using yarn
yarn add @aharris02/bazi-calculator-by-alvamind date-fns date-fns-tz
# Using pnpm
pnpm add @aharris02/bazi-calculator-by-alvamind date-fns date-fns-tz
Note: This library requires
date-fns
anddate-fns-tz
as peer dependencies for robust date and timezone handling.
🎯 Quick Start
import { BaziCalculator } from '@aharris02/bazi-calculator-by-alvamind';
import { toDate } from 'date-fns-tz'; // Essential for timezone-aware Date creation
// Define Birth Details
const dateString = '1990-05-10T12:30:00';
const timezone = 'Asia/Shanghai';
const gender = 'male';
// Create a timezone-aware Date object (IMPORTANT!)
const birthDate = toDate(dateString, { timeZone: timezone });
// Initialize calculator with modern constructor
const calculator = new BaziCalculator(
birthDate, // Date object (timezone-aware)
gender, // Gender ('male' or any other string -> 'female')
timezone, // IANA Timezone string
true // Is birth time known? (default: true)
);
// Get complete analysis for the natal chart
const analysis = calculator.getCompleteAnalysis();
// Display Chinese characters for the natal chart
console.log(calculator.toString()); // Example: 庚午年辛巳月乙酉日壬午時
if (analysis) {
console.log("Day Master:", analysis.basicAnalysis?.dayMaster?.stem);
// Access other parts of the analysis object as needed
}
For more detailed examples, including handling unknown birth times and using new daily/range analysis features, please see the Detailed Documentation section.
📖 Detailed Documentation
Birth Time Known Example
import { BaziCalculator } from '@aharris02/bazi-calculator-by-alvamind';
import { toDate, formatInTimeZone } from 'date-fns-tz';
import { isValid } from 'date-fns';
// 1. Define Birth Details
const year = 1995;
const month = 6; // 1-12
const day = 8;
const hour = 22; // 0-23
const minute = 5;
const gender = 'male'; // or 'female', 'nonbinary', 'other', etc.
const timeZone = 'Asia/Ho_Chi_Minh'; // IANA Timezone String is crucial!
const isTimeKnown = true; // Explicitly state time is known
// 2. Create a Timezone-Aware Date Object
// IMPORTANT: Use date-fns-tz's toDate for correct initial parsing
const dateString = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}T${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}:00`;
const birthDate = toDate(dateString, { timeZone });
if (!isValid(birthDate)) {
console.error("Invalid Date constructed. Check inputs and timezone.");
// Handle error appropriately
} else {
// 3. Instantiate the Calculator
// Gender normalizes internally: non-'male' inputs become 'female' for calculations
const calculator = new BaziCalculator(birthDate, gender, timeZone, isTimeKnown);
// 4. Get the Complete Analysis
const analysis = calculator.getCompleteAnalysis();
if (analysis) {
console.log("--- Four Pillars (Simple) ---");
console.log(analysis.mainPillars);
// Example: { year: {...}, month: {...}, day: {...}, time: {...} }
console.log("\n--- Luck Pillars Summary ---");
if (analysis.luckPillars) {
console.log(`Direction: ${analysis.luckPillars.incrementRule === 1 ? 'Forward' : 'Backward'}`);
console.log(`Timing Known: ${analysis.luckPillars.isTimingKnown}`);
console.log(`Start Age: ${analysis.luckPillars.startAgeYears}y ${analysis.luckPillars.startAgeMonths}m ${analysis.luckPillars.startAgeDays}d`);
}
console.log("\n--- Basic Analysis ---");
console.log(analysis.basicAnalysis);
console.log("\n--- Chart String ---");
console.log(calculator.toString()); // Output: 乙亥年 壬午月 庚午日 丁亥時
}
}
Unknown Birth Time Example
import { BaziCalculator } from '@aharris02/bazi-calculator-by-alvamind';
import { toDate } from 'date-fns-tz';
import { isValid } from 'date-fns';
const year = 1995;
const month = 6;
const day = 8;
const hour = 12; // Placeholder Hour (e.g., noon)
const minute = 0; // Placeholder Minute
const gender = 'male';
const timeZone = 'Asia/Ho_Chi_Minh';
const isTimeKnown = false; // <<< Indicate time is unknown
const dateString = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}T${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}:00`;
const birthDate = toDate(dateString, { timeZone });
if (isValid(birthDate)) {
const calculator = new BaziCalculator(birthDate, gender, timeZone, isTimeKnown);
const analysis = calculator.getCompleteAnalysis();
if (analysis) {
console.log("--- Analysis (Unknown Time) ---");
console.log("Pillars:", analysis.mainPillars);
// Output will have time: null
console.log("Pillars String:", calculator.toString());
// Output: 乙亥年 壬午月 庚午日 ??時
console.log("Luck Pillars Timing Known:", analysis.luckPillars?.isTimingKnown);
// Output: false
console.log("Luck Pillars Start Age:", analysis.luckPillars?.startAgeYears);
// Output: null
// Note: Some analysis components like Ten Gods related to the Hour Pillar might be absent or less precise.
console.log("Five Factors:", analysis.basicAnalysis?.fiveFactors);
}
}
Daily Analysis (getAnalysisForDate
) Example
This method provides analysis for a single specific day.
import { BaziCalculator } from '@aharris02/bazi-calculator-by-alvamind';
import { toDate } from 'date-fns-tz';
// Assume 'calculator' is an instance of BaziCalculator initialized with a natal chart (for 'personalized' analysis)
// For 'general' analysis, a dummy BaziCalculator instance can be used if you only need the day's chart.
const natalBirthDate = toDate('1990-01-01T10:00:00', { timeZone: 'America/New_York' });
const natalCalculator = new BaziCalculator(natalBirthDate, 'female', 'America/New_York', true);
// Define the target date and timezone for the daily analysis
const targetDateString = '2025-05-09T12:00:00'; // Time component is used to ensure the correct day in the target timezone
const targetTimezone = 'America/New_York'; // CRUCIAL: This determines the day's pillars
const targetDate = toDate(targetDateString, { timeZone: targetTimezone });
// 1. General Daily Analysis (the day's own chart and interactions)
const generalDailyAnalysis = natalCalculator.getAnalysisForDate(targetDate, targetTimezone, { type: 'general' });
if (generalDailyAnalysis) {
console.log("\n--- General Daily Analysis for", generalDailyAnalysis.date, "---");
console.log("Day Pillar:", generalDailyAnalysis.dayPillar.chinese);
// Explore generalDailyAnalysis.interactions, .annualPillarContext, .monthlyPillarContext etc.
// Output structure defined in GeneralDailyAnalysisOutput in src/types.ts
}
// 2. Personalized Daily Analysis (how the target day interacts with the natal chart)
const personalizedDailyAnalysis = natalCalculator.getAnalysisForDate(targetDate, targetTimezone, { type: 'personalized' });
if (personalizedDailyAnalysis) {
console.log("\n--- Personalized Daily Analysis for", personalizedDailyAnalysis.date, "---");
console.log("Day Pillar of Target Date:", personalizedDailyAnalysis.dayPillar.chinese);
console.log("Interactions with Natal Chart:", personalizedDailyAnalysis.interactions);
// Explore personalizedDailyAnalysis.currentLuckPillarSnap etc.
// Output structure defined in PersonalizedDailyAnalysisOutput in src/types.ts
}
Important Note on targetTimezone
: The targetTimezone
parameter is critical for getAnalysisForDate
and getAnalysisForDateRange
. It determines how the targetDate
(or dates in the range) is interpreted to calculate its daily pillars. Using the wrong timezone can lead to off-by-one day errors in the analysis.
Date Range Analysis (getAnalysisForDateRange
) Example
This method provides daily analysis for a sequence of dates.
import { BaziCalculator } from '@aharris02/bazi-calculator-by-alvamind';
import { toDate } from 'date-fns-tz';
// Assume 'natalCalculator' is an instance of BaziCalculator initialized with a natal chart (for 'personalized' analysis)
const natalBirthDate = toDate('1990-01-01T10:00:00', { timeZone: 'America/New_York' });
const natalCalculator = new BaziCalculator(natalBirthDate, 'female', 'America/New_York', true);
const rangeTimezone = 'America/Los_Angeles'; // Timezone for the daily analysis within the range
// Define the start and end dates for the range.
// Use toDate with the rangeTimezone to ensure correct day boundaries.
const startDate = toDate('2025-06-01T00:00:00', { timeZone: rangeTimezone });
const endDate = toDate('2025-06-03T00:00:00', { timeZone: rangeTimezone }); // Inclusive of this day
// 1. General Date Range Analysis
const generalRangeAnalysis = natalCalculator.getAnalysisForDateRange(startDate, endDate, rangeTimezone, { type: 'general' });
if (generalRangeAnalysis) {
console.log("\n--- General Date Range Analysis ---");
generalRangeAnalysis.forEach(dayAnalysis => {
console.log(dayAnalysis.date, "Day Pillar:", dayAnalysis.dayPillar.chinese);
});
}
// 2. Personalized Date Range Analysis
const personalizedRangeAnalysis = natalCalculator.getAnalysisForDateRange(startDate, endDate, rangeTimezone, { type: 'personalized' });
if (personalizedRangeAnalysis) {
console.log("\n--- Personalized Date Range Analysis ---");
personalizedRangeAnalysis.forEach(dayAnalysis => {
console.log(dayAnalysis.date, "Interactions with Natal:", dayAnalysis.interactions.length, "interactions found.");
});
}
Refer to src/types.ts
or the exported types (GeneralDailyAnalysisOutput
, PersonalizedDailyAnalysisOutput
) for the detailed structure of the objects returned by these methods.
API Reference
BaziCalculator
Class
class BaziCalculator {
constructor(
birthDateTime: Date, // Timezone-aware Date object (use date-fns-tz's toDate)
genderInput?: string, // 'male', 'female' (other inputs default to 'female')
timezoneInput?: string, // IANA timezone string (defaults to 'UTC')
isTimeKnownInput?: boolean // Whether the exact hour/minute are known (defaults to true)
);
// Main Natal Chart methods
calculatePillars(): Pillars | null;
calculateLuckPillars(): LuckPillarsResult | null;
calculateBasicAnalysis(): BasicAnalysis | null;
getCompleteAnalysis(): CompleteAnalysis | null; // Recommended for full natal chart
toString(): string; // Returns the Four Pillars as a Chinese string
// Timed Analysis methods
getAnalysisForDate(
targetDate: Date,
targetTimezone: string, // IANA timezone for interpreting targetDate
options: { type: 'general' | 'personalized' }
): GeneralDailyAnalysisOutput | PersonalizedDailyAnalysisOutput | null;
getAnalysisForDateRange(
startDate: Date,
endDate: Date,
targetTimezone: string, // IANA timezone for interpreting dates in the range
options: { type: 'general' | 'personalized' }
): (GeneralDailyAnalysisOutput | PersonalizedDailyAnalysisOutput)[] | null;
}
For detailed information on the structures returned by these methods (e.g., CompleteAnalysis
, Pillars
, LuckPillarsResult
, GeneralDailyAnalysisOutput
, PersonalizedDailyAnalysisOutput
), please refer to the exported types from the library and the definitions in src/types.ts
.
Data Files
This library relies on internal JSON data for calculations:
lunar-new-year.json
: Used for determining the Lunar Year for the Year Pillar.solar-term.json
: Used for determining the Month Branch and Luck Pillar timing.
These files are bundled with the library.
📝 Important Notes
Calculation Methods
- Timezone-aware calculations using IANA timezone strings are essential. Always use
date-fns-tz
'stoDate
when creatingDate
objects from strings to pass to the calculator. - Traditional Chinese time system (12 two-hour periods).
- Standard Stem-Branch (干支) system.
- Eight Mansions Feng Shui principles.
- Support for unknown birth time calculations (Hour Pillar will be null, affecting some analyses).
- Interaction analysis includes Natal, Luck, Annual, Monthly, and Daily pillars as applicable.
Limitations
- Luck Pillar Start Time precision depends on solar term data.
- Calculations use standard timezone time, not Real Solar Time adjusted for longitude.
- While Ten Gods are calculated, advanced interpretations and very specific Symbolic Star analyses beyond the core set (Nobleman, Intelligence, Sky Horse, Peach Blossom) are not exhaustive.
- For professional consultations, please consult a qualified Bazi practitioner.
🤝 Contributing
We welcome contributions! See our Contributing Guidelines for details.
📄 License
MIT License - see the LICENSE file for details.
Based on the original work by Alvamind