thai_lunar 0.1.0
thai_lunar: ^0.1.0 copied to clipboard
Pure-Dart Thai lunar calendar: Gregorian conversion, athikamat/athikavar year types, and Buddhist holiday full moons (Makha, Visakha, Asalha).
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.