thai_lunar
A pure-Dart, dependency-free Thai lunar calendar (จันทรคติ / chantarakati, Suriyayatra) engine.
It converts between Gregorian and Thai lunar dates, classifies lunar year types (อธิกมาส athikamat / อธิกวาร athikavar), and computes the Buddhist holidays that fall on full moons — Makha Bucha, Visakha Bucha, Asalha Bucha — plus wan phra (Buddhist sabbath) days by the conventional civil lunar reckoning (waxing 8 & 15, waning 8, and the last day of the lunar month).
All arithmetic is integer — these are integer algorithms; floating point drifts.
Features
- Gregorian → Thai lunar conversion (
gregorianToThaiLunar) and the exact inverse (thaiLunarToGregorian) — round-trips losslessly for every day. - Lunar year classification: normal / athikavar (extra day) / athikamat
(extra month) via
lunarYearType,isAthikamat,isAthikavar. - Movable Buddhist holiday full moons via
fullMoonOf(Makha Bucha date, Visakha Bucha date, Asalha Bucha date), with the athikamat month shift and the doubled-month-8 (secondEighth) handled for you. - Wan phra (Buddhist sabbath) detection: top-level
isWanPhra(DateTime)and the computedThaiLunarDate.isWanPhragetter. - เสาร์ห้า (Sao Ha) finder — the rare auspicious Saturday on the 5th of
lunar month 5 — via
isSaoHa,saoHaType,saoHaDatesInandnextSaoHa. - A rich, value-equal
ThaiLunarDate(==/hashCode/copyWith,Comparableso aListsorts chronologically) exposingbeYear,ceYear,csYear,month,phase,day,isFullMoon,weekday,isSecondEighthandisYearEndWrap. - BE / CE era-aware API (
ThaiEra) withbeToCe/ceToBehelpers. - Zero dependencies, pure Dart.
Install
dependencies:
thai_lunar: ^0.1.0
Usage
import 'package:thai_lunar/thai_lunar.dart';
// Gregorian -> Thai lunar
final lunar = gregorianToThaiLunar(DateTime.utc(2000, 1, 1));
print(lunar); // แรม 9 ค่ำ เดือน 1 พ.ศ. 2542
print(lunar.beYear); // 2542 (Buddhist Era; the lunar year had not
print(lunar.ceYear); // 1999 yet rolled over on 1 Jan)
print(lunar.csYear); // 1361 (Chula Sakarat)
print(lunar.weekday); // 6 (Saturday; 1=Mon..7=Sun)
print(lunar.isFullMoon); // false
print(lunar.isWanPhra); // false (computed from phase/day/month-length)
// Year classification (BE by default; pass era: ThaiEra.ce for CE years)
lunarYearType(2026, era: ThaiEra.ce); // ThaiLunarYearType.extraMonth
isAthikamat(2026, era: ThaiEra.ce); // true (leap month: doubled month 8)
isAthikavar(2025, era: ThaiEra.ce); // true (leap day in month 7)
// Holidays — full moon of a lunar month, landing in the given calendar year.
// In an athikamat year the conventional months shift (Makha 3->4, Visakha
// 6->7, Asalha -> the SECOND month 8).
fullMoonOf(2026, 4, era: ThaiEra.ce); // Makha 2026-03-03
fullMoonOf(2026, 7, era: ThaiEra.ce); // Visakha 2026-05-31
final asalha = fullMoonOf(2026, 8, era: ThaiEra.ce, secondEighth: true); // 2026-07-29
final khaoPhansa = asalha.add(const Duration(days: 1)); // 2026-07-30
// Wan phra (Buddhist sabbath)
isWanPhra(DateTime.utc(2026, 5, 31)); // true (Visakha full moon)
// Era helpers
beToCe(2569); // 2026
ceToBe(2026); // 2569
เสาร์ห้า (Sao Ha)
เสาร์ห้า is a Saturday that coincides with the 5th day of lunar month 5 (เดือน 5) — either the waxing 5th (ขึ้น 5 ค่ำ) or the waning 5th (แรม 5 ค่ำ). It is the strongest auspicious day in Thai belief for consecrating amulets and วัตถุมงคล (sacred objects). It is rare: it does not occur every year, arriving roughly once every 2–3 years. Two grades:
- เสาร์ห้าใหญ่ (
SaoHaType.major) — Saturday + ขึ้น 5 ค่ำ เดือน 5 (waxing). The rarer, "greater" grade. - เสาร์ห้าน้อย (
SaoHaType.minor) — Saturday + แรม 5 ค่ำ เดือน 5 (waning).
// Classify a single day.
isSaoHa(DateTime.utc(2024, 4, 13)); // true
saoHaType(DateTime.utc(2024, 4, 13)); // SaoHaType.major (ขึ้น 5 ค่ำ เดือน 5)
saoHaType(DateTime.utc(2011, 4, 23)); // SaoHaType.minor (แรม 5 ค่ำ เดือน 5)
saoHaType(DateTime.utc(2024, 1, 6)); // null (an ordinary Saturday)
// All เสาร์ห้า in a Gregorian year (usually none).
saoHaDatesIn(2024); // [2024-04-13] (major)
saoHaDatesIn(2022); // [] (none that year)
// The next one on/after a date (searches forward ~30 years; null if none).
nextSaoHa(DateTime.utc(2021, 1, 1)); // 2024-04-13
Validated range
The engine is validated against the official Thai calendar for roughly
1900–2050 CE (the range over which the conversion and holiday APIs are tested
and supported). The underlying arithmetic is a Suriyayatra reconstruction that
runs beyond those bounds, but before the early-20th-century standardisation of
the Thai calendar it diverges from the official record, so fullMoonOf and
thaiLunarToGregorian throw ArgumentError for input outside this range.
Year-type classifiers (lunarYearType etc.) do not throw and may be used
beyond the range with this caveat in mind.
Notes & caveats
- Calendar-day contract.
gregorianToThaiLunaruses only theDateTime's ownyear/month/day; the time of day and the time zone are ignored, so you get the Thai lunar date for that wall-clock calendar day. To convert "the UTC day" instead, passdate.toUtc(). fullMoonOfreturns the occurrence of that lunar month's full moon whose Gregorian date falls within the requested calendar year. A lunar year straddles the Gregorian boundary, so an early month (1..4) belongs to the lunar year that began the previous Gregorian year — this is handled for you.- Months 5 and 6 each occur twice in a Gregorian year — once at the head of
a lunar year and once again as the previous lunar year wraps round at its end.
The year-end occurrence is flagged via
ThaiLunarDate.isYearEndWrapand carries the BE year of the lunar year it closes (= CS year + 1181), matching the convention a Thai reader expects for those tail days. Because of this flagthaiLunarToGregorian(gregorianToThaiLunar(d)) == dis exact for every day, including the wrap days.
Related packages
- thai_holidays — Thai public holiday dates (uses lunar holidays like these).
- The same publisher also maintains the Thai-numerals toolkit thainum and a Thai PromptPay helper thai_promptpay.
Attribution
This package is a faithful port of
pythaidate by Mark Hollow (MIT,
© 2023). The underlying algorithm derives from J.C. Eade, The Calendrical
Systems of Mainland South-East Asia (Brill, 1995). See
NOTICE.md.
License
MIT — see LICENSE.
Libraries
- thai_lunar
- A pure-Dart, dependency-free Thai lunisolar (chantarakati / Suriyayatra) calendar engine.