
Accurate Myanmar civil/lunar date conversion, bidirectional Gregorian–Myanmar mapping, lunar phases, sabbath markers, formatting/parsing with localized month names, pluggable holiday rules and demo UI.
A pure Kotlin Myanmar calendar library and interactive Kotlin Multiplatform demo. It runs from shared code on Android and iOS and converts dates in both directions:
The calendar engine has no Android, iOS, or Compose dependency. The Compose UI is only a demo consumer of the shared library.
shared/src/commonMain/kotlin/com/aj/mmp_multi/myanmarcalendar/
├── calendar_core/
│ ├── model/ # Public data types and enums
│ ├── engine/ # Myanmar calendar algorithm (internal)
│ ├── converter/ # Gregorian ↔ Julian-day conversion helpers
│ ├── util/ # Gregorian validation and leap-year helpers
│ ├── internal/ # Algorithm constants (internal)
│ └── MyanmarCalendar.kt
├── calendar_formatter/ # Numeric parsing and Myanmar/English formatting
├── calendar_holiday/ # Pluggable holiday-rule API
├── calendar_astrology/ # Calendar weekday helper
└── sample/ # Minimal non-UI sample
commonMain.dependencies {
implementation("io.github.newarjun101:mmcalendar:$latestVersion")
}Define latestVersion yourself in your version catalog, build constants, or Gradle configuration.
Ensure your project includes Maven Central:
repositories {
mavenCentral()
}After adding the dependency, use the library from commonMain, androidMain, or iosMain.
import com.newarjun101.mmcalendar.calendar_core.MyanmarCalendar
import com.newarjun101.mmcalendar.calendar_core.model.GregorianDate
import com.newarjun101.mmcalendar.calendar_formatter.MyanmarDateFormatter
val gregorian = GregorianDate(2024, 4, 17)
val myanmar = MyanmarCalendar.fromGregorian(gregorian)
println(myanmar.year) // 1386
println(MyanmarDateFormatter.format(myanmar))
// တန်ခူး လဆန်း ၉Visit the demo project to see MMCalendar in action:
https://github.com/newarjun101/myanmar-calendar-demo
val myanmar = MyanmarCalendar.fromGregorian(2024, 4, 17)
// Or use a validated value object.
val myanmar2 = MyanmarCalendar.fromGregorian(GregorianDate(2024, 4, 17))GregorianDate validates the month and day, including Gregorian leap years. Invalid values throw IllegalArgumentException.
val english = MyanmarCalendar.toGregorian(myanmar)
// Or provide Myanmar year, month, and day directly.
val english2 = MyanmarCalendar.toGregorian(
year = 1386,
month = 1,
day = 9,
)Myanmar input is validated against the calendar engine. For example, First Waso (month = 0) is accepted only in a watat year.
val jdn = MyanmarCalendar.toJulianDayNumber(GregorianDate(2000, 1, 1))
// 2451545
val myanmar = MyanmarCalendar.fromJulianDayNumber(jdn)
val jdnFromMyanmar = MyanmarCalendar.toJulianDayNumber(
year = myanmar.year,
month = myanmar.month,
day = myanmar.day,
)MyanmarCalendar.fromGregorian(...) returns MyanmarDate:
| Field | Meaning |
|---|---|
year |
Myanmar Era year |
month |
Myanmar month number; see the month table below |
day |
Calendar day within the Myanmar month |
yearType |
COMMON, LITTLE_WATAT, or BIG_WATAT
|
moonPhase |
WAXING, FULL_MOON, WANING, or NEW_MOON
|
fortnightDay |
Day in the waxing or waning fortnight (1–15) |
sabbathDay |
NONE, SABBATH, or SABBATH_EVE
|
Myanmar calendar years can contain an intercalary month (watat) to keep lunar months aligned with the solar year.
| Value | Meaning | Calendar length |
|---|---|---|
COMMON |
Ordinary year with no intercalary Waso month | 354 days |
LITTLE_WATAT |
Watat year with an additional 30-day First Waso month | 384 days |
BIG_WATAT |
Watat year with First Waso plus one additional day in Nayon | 385 days |
First Waso is represented by month = 0; it is valid only in a watat year. The yearType is calculated by the engine, so callers normally read it from MyanmarDate instead of setting it themselves.
The engine assigns a phase from the Myanmar calendar day:
| Moon phase | Calendar day rule |
fortnightDay use |
|---|---|---|
WAXING |
Days 1–14 | 1–14, counted from the new moon toward the full moon |
FULL_MOON |
Day 15 | 15 |
WANING |
Days 16 through the day before the last day of the month | 1–14/15, counted after the full moon |
NEW_MOON |
Last day of the Myanmar month | Use the phase rather than the fortnight number for display |
For display, prefer MyanmarDateFormatter.moonPhaseName(date.moonPhase) and MyanmarDateFormatter.format(date). This correctly renders labels such as လဆန်း, လပြည့်, လဆုတ်, and လကွယ်.
sabbathDay is a Myanmar lunar observance marker, not a public-holiday decision:
| Value | Calendar day rule |
|---|---|
SABBATH |
8th waxing day, full moon day (15), 8th waning day (23), or new moon day (the final day of the month) |
SABBATH_EVE |
Day immediately before each Sabbath: 7, 14, 22, or the day before the last day of the month |
NONE |
Any other calendar day |
Use sabbathDay to decorate a calendar UI or to apply app-specific observance logic. Use MyanmarHolidayCalendar for actual holiday policy.
| Number | Myanmar name | English name |
|---|---|---|
| 0 | ပဝါဆို | First Waso |
| 1–12 | တန်ခူး … တပေါင်း | Tagu … Tabaung |
| 13 | နှောင်းတန်ခူး | Late Tagu |
| 14 | နှောင်းကဆုန် | Late Kason |
Use MyanmarDateFormatter.monthName(...) rather than hard-coding names in UI.
Gregorian formatting supports yyyy, yy, MM, M, dd, and d.
import com.newarjun101.mmcalendar.calendar_formatter.GregorianDateFormatter
val text = GregorianDateFormatter.format(
GregorianDate(2024, 4, 17),
pattern = "dd.MM.yyyy",
)
// 17.04.2024Myanmar formatting supports all of the above plus MMMM for the localized month name.
import com.newarjun101.mmcalendar.calendar_core.model.MyanmarLanguage
import com.newarjun101.mmcalendar.calendar_formatter.MyanmarDateFormatter
val myanmarText = MyanmarDateFormatter.format(myanmar, "yyyy MMMM dd")
// ၁၃၈၆ တန်ခူး ၀၉
val englishText = MyanmarDateFormatter.format(
myanmar,
pattern = "yyyy MMMM dd",
language = MyanmarLanguage.ENGLISH,
)
// 1386 Tagu 09CalendarDateConverter accepts numeric date strings. Input patterns require each of these tokens exactly once:
yyyy — yearMM or M — monthdd or d — dayAll non-token characters are treated as literal separators, so -, /, ., and spaces can be used. Myanmar input accepts either Myanmar digits (၁၃၈၆) or Western digits (1386). Month names (MMMM) and two-digit years (yy) are output-only.
import com.newarjun101.mmcalendar.calendar_formatter.CalendarDateConverter
val myanmarText = CalendarDateConverter.gregorianToMyanmar(
text = "17/04/2024",
inputPattern = "dd/MM/yyyy",
outputPattern = "yyyy MMMM dd",
)
val gregorianText = CalendarDateConverter.myanmarToGregorian(
text = "၁၃၈၆-၁-၉",
inputPattern = "yyyy-M-d",
outputPattern = "dd.MM.yyyy",
)
// 17.04.2024For a typed result instead of a string, use parseGregorian(...) or parseMyanmar(...).
val month = MyanmarDateFormatter.monthName(myanmar.month)
val phase = MyanmarDateFormatter.moonPhaseName(myanmar.moonPhase)
val digits = MyanmarDateFormatter.number(myanmar.year)By default, formatter methods return Myanmar text and Myanmar digits. Pass MyanmarLanguage.ENGLISH when English names and Western digits are required.
import com.newarjun101.mmcalendar.calendar_astrology.MyanmarAstrology
val weekday = MyanmarAstrology.weekday(GregorianDate(2024, 4, 17))
// Weekday.WEDNESDAYcalendar_astrology currently exposes calendar weekday data only. Traditional astrological rules can be built on top of this stable input.
Holiday policy differs by locale and official observance, so the library deliberately does not hard-code a national holiday list. Supply rules from your app:
import com.newarjun101.mmcalendar.calendar_holiday.CalendarHoliday
import com.newarjun101.mmcalendar.calendar_holiday.HolidayRule
import com.newarjun101.mmcalendar.calendar_holiday.MyanmarHolidayCalendar
val holidays = MyanmarHolidayCalendar(
HolidayRule { year ->
listOf(CalendarHoliday("new-year", "New Year", GregorianDate(year, 1, 1)))
},
)
val holidaysIn2024 = holidays.holidaysFor(2024)MyanmarPublicHolidays.holidaysFor(2026) provides the published 2026 public-holiday list, including multi-day festivals. MyanmarHolidayCatalog.holidaysFor(year) is the demo-friendly option: it generates recurring calendar observances for any past or future year and merges any verified annual official list. Each CalendarHoliday has a kind of OFFICIAL or CALENDAR_OBSERVANCE so the UI can show the distinction.
The demo in shared/src/commonMain/kotlin/com/aj/mmp_multi/App.kt is fully stateful and demonstrates the public API.
| Screen | What it shows |
|---|---|
| Today | Current Gregorian/Myanmar date, weekday, moon phase, and observance |
| Month | Switchable Gregorian and Myanmar lunar-month views, previous/next navigation, selected dates, full-moon/new-moon/Sabbath markers, holiday/observance summaries, and matching dates from the other calendar |
| Holidays | Previous/next year navigation, recurring calendar observances for any year, and verified official holiday labels where available |
| Convert | Bidirectional string conversion with editable date and format patterns |
| About | Library layers and supported capabilities |
Month colors: red ● full moon, blue ○ new moon, green ✦ Sabbath.
Build the Android demo:
./gradlew :androidApp:assembleDebugFor iOS, open iosApp in Xcode and run the iosApp scheme.
The Myanmar calendar conversion logic in calendar_core is a Kotlin Multiplatform port/adaptation of the calendrical algorithms from yan9a/mmcal, a Myanmar calendar implementation maintained by Yan Naing Aye and its contributors. The upstream project provides C++ and JavaScript implementations of modern Myanmar calendrical calculations under the MIT License.
Special thanks to the contributors who made the underlying algorithms and reference implementation available to the community:
Thank you to these contributors and all contributors to yan9a/mmcal.
This project’s Kotlin API design, Kotlin Multiplatform demo, format utilities, holiday catalog, and documentation are maintained in this repository.
Copyright (c) 2026 Arjun Dhakal
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
A pure Kotlin Myanmar calendar library and interactive Kotlin Multiplatform demo. It runs from shared code on Android and iOS and converts dates in both directions:
The calendar engine has no Android, iOS, or Compose dependency. The Compose UI is only a demo consumer of the shared library.
shared/src/commonMain/kotlin/com/aj/mmp_multi/myanmarcalendar/
├── calendar_core/
│ ├── model/ # Public data types and enums
│ ├── engine/ # Myanmar calendar algorithm (internal)
│ ├── converter/ # Gregorian ↔ Julian-day conversion helpers
│ ├── util/ # Gregorian validation and leap-year helpers
│ ├── internal/ # Algorithm constants (internal)
│ └── MyanmarCalendar.kt
├── calendar_formatter/ # Numeric parsing and Myanmar/English formatting
├── calendar_holiday/ # Pluggable holiday-rule API
├── calendar_astrology/ # Calendar weekday helper
└── sample/ # Minimal non-UI sample
commonMain.dependencies {
implementation("io.github.newarjun101:mmcalendar:$latestVersion")
}Define latestVersion yourself in your version catalog, build constants, or Gradle configuration.
Ensure your project includes Maven Central:
repositories {
mavenCentral()
}After adding the dependency, use the library from commonMain, androidMain, or iosMain.
import com.newarjun101.mmcalendar.calendar_core.MyanmarCalendar
import com.newarjun101.mmcalendar.calendar_core.model.GregorianDate
import com.newarjun101.mmcalendar.calendar_formatter.MyanmarDateFormatter
val gregorian = GregorianDate(2024, 4, 17)
val myanmar = MyanmarCalendar.fromGregorian(gregorian)
println(myanmar.year) // 1386
println(MyanmarDateFormatter.format(myanmar))
// တန်ခူး လဆန်း ၉Visit the demo project to see MMCalendar in action:
https://github.com/newarjun101/myanmar-calendar-demo
val myanmar = MyanmarCalendar.fromGregorian(2024, 4, 17)
// Or use a validated value object.
val myanmar2 = MyanmarCalendar.fromGregorian(GregorianDate(2024, 4, 17))GregorianDate validates the month and day, including Gregorian leap years. Invalid values throw IllegalArgumentException.
val english = MyanmarCalendar.toGregorian(myanmar)
// Or provide Myanmar year, month, and day directly.
val english2 = MyanmarCalendar.toGregorian(
year = 1386,
month = 1,
day = 9,
)Myanmar input is validated against the calendar engine. For example, First Waso (month = 0) is accepted only in a watat year.
val jdn = MyanmarCalendar.toJulianDayNumber(GregorianDate(2000, 1, 1))
// 2451545
val myanmar = MyanmarCalendar.fromJulianDayNumber(jdn)
val jdnFromMyanmar = MyanmarCalendar.toJulianDayNumber(
year = myanmar.year,
month = myanmar.month,
day = myanmar.day,
)MyanmarCalendar.fromGregorian(...) returns MyanmarDate:
| Field | Meaning |
|---|---|
year |
Myanmar Era year |
month |
Myanmar month number; see the month table below |
day |
Calendar day within the Myanmar month |
yearType |
COMMON, LITTLE_WATAT, or BIG_WATAT
|
moonPhase |
WAXING, FULL_MOON, WANING, or NEW_MOON
|
fortnightDay |
Day in the waxing or waning fortnight (1–15) |
sabbathDay |
NONE, SABBATH, or SABBATH_EVE
|
Myanmar calendar years can contain an intercalary month (watat) to keep lunar months aligned with the solar year.
| Value | Meaning | Calendar length |
|---|---|---|
COMMON |
Ordinary year with no intercalary Waso month | 354 days |
LITTLE_WATAT |
Watat year with an additional 30-day First Waso month | 384 days |
BIG_WATAT |
Watat year with First Waso plus one additional day in Nayon | 385 days |
First Waso is represented by month = 0; it is valid only in a watat year. The yearType is calculated by the engine, so callers normally read it from MyanmarDate instead of setting it themselves.
The engine assigns a phase from the Myanmar calendar day:
| Moon phase | Calendar day rule |
fortnightDay use |
|---|---|---|
WAXING |
Days 1–14 | 1–14, counted from the new moon toward the full moon |
FULL_MOON |
Day 15 | 15 |
WANING |
Days 16 through the day before the last day of the month | 1–14/15, counted after the full moon |
NEW_MOON |
Last day of the Myanmar month | Use the phase rather than the fortnight number for display |
For display, prefer MyanmarDateFormatter.moonPhaseName(date.moonPhase) and MyanmarDateFormatter.format(date). This correctly renders labels such as လဆန်း, လပြည့်, လဆုတ်, and လကွယ်.
sabbathDay is a Myanmar lunar observance marker, not a public-holiday decision:
| Value | Calendar day rule |
|---|---|
SABBATH |
8th waxing day, full moon day (15), 8th waning day (23), or new moon day (the final day of the month) |
SABBATH_EVE |
Day immediately before each Sabbath: 7, 14, 22, or the day before the last day of the month |
NONE |
Any other calendar day |
Use sabbathDay to decorate a calendar UI or to apply app-specific observance logic. Use MyanmarHolidayCalendar for actual holiday policy.
| Number | Myanmar name | English name |
|---|---|---|
| 0 | ပဝါဆို | First Waso |
| 1–12 | တန်ခူး … တပေါင်း | Tagu … Tabaung |
| 13 | နှောင်းတန်ခူး | Late Tagu |
| 14 | နှောင်းကဆုန် | Late Kason |
Use MyanmarDateFormatter.monthName(...) rather than hard-coding names in UI.
Gregorian formatting supports yyyy, yy, MM, M, dd, and d.
import com.newarjun101.mmcalendar.calendar_formatter.GregorianDateFormatter
val text = GregorianDateFormatter.format(
GregorianDate(2024, 4, 17),
pattern = "dd.MM.yyyy",
)
// 17.04.2024Myanmar formatting supports all of the above plus MMMM for the localized month name.
import com.newarjun101.mmcalendar.calendar_core.model.MyanmarLanguage
import com.newarjun101.mmcalendar.calendar_formatter.MyanmarDateFormatter
val myanmarText = MyanmarDateFormatter.format(myanmar, "yyyy MMMM dd")
// ၁၃၈၆ တန်ခူး ၀၉
val englishText = MyanmarDateFormatter.format(
myanmar,
pattern = "yyyy MMMM dd",
language = MyanmarLanguage.ENGLISH,
)
// 1386 Tagu 09CalendarDateConverter accepts numeric date strings. Input patterns require each of these tokens exactly once:
yyyy — yearMM or M — monthdd or d — dayAll non-token characters are treated as literal separators, so -, /, ., and spaces can be used. Myanmar input accepts either Myanmar digits (၁၃၈၆) or Western digits (1386). Month names (MMMM) and two-digit years (yy) are output-only.
import com.newarjun101.mmcalendar.calendar_formatter.CalendarDateConverter
val myanmarText = CalendarDateConverter.gregorianToMyanmar(
text = "17/04/2024",
inputPattern = "dd/MM/yyyy",
outputPattern = "yyyy MMMM dd",
)
val gregorianText = CalendarDateConverter.myanmarToGregorian(
text = "၁၃၈၆-၁-၉",
inputPattern = "yyyy-M-d",
outputPattern = "dd.MM.yyyy",
)
// 17.04.2024For a typed result instead of a string, use parseGregorian(...) or parseMyanmar(...).
val month = MyanmarDateFormatter.monthName(myanmar.month)
val phase = MyanmarDateFormatter.moonPhaseName(myanmar.moonPhase)
val digits = MyanmarDateFormatter.number(myanmar.year)By default, formatter methods return Myanmar text and Myanmar digits. Pass MyanmarLanguage.ENGLISH when English names and Western digits are required.
import com.newarjun101.mmcalendar.calendar_astrology.MyanmarAstrology
val weekday = MyanmarAstrology.weekday(GregorianDate(2024, 4, 17))
// Weekday.WEDNESDAYcalendar_astrology currently exposes calendar weekday data only. Traditional astrological rules can be built on top of this stable input.
Holiday policy differs by locale and official observance, so the library deliberately does not hard-code a national holiday list. Supply rules from your app:
import com.newarjun101.mmcalendar.calendar_holiday.CalendarHoliday
import com.newarjun101.mmcalendar.calendar_holiday.HolidayRule
import com.newarjun101.mmcalendar.calendar_holiday.MyanmarHolidayCalendar
val holidays = MyanmarHolidayCalendar(
HolidayRule { year ->
listOf(CalendarHoliday("new-year", "New Year", GregorianDate(year, 1, 1)))
},
)
val holidaysIn2024 = holidays.holidaysFor(2024)MyanmarPublicHolidays.holidaysFor(2026) provides the published 2026 public-holiday list, including multi-day festivals. MyanmarHolidayCatalog.holidaysFor(year) is the demo-friendly option: it generates recurring calendar observances for any past or future year and merges any verified annual official list. Each CalendarHoliday has a kind of OFFICIAL or CALENDAR_OBSERVANCE so the UI can show the distinction.
The demo in shared/src/commonMain/kotlin/com/aj/mmp_multi/App.kt is fully stateful and demonstrates the public API.
| Screen | What it shows |
|---|---|
| Today | Current Gregorian/Myanmar date, weekday, moon phase, and observance |
| Month | Switchable Gregorian and Myanmar lunar-month views, previous/next navigation, selected dates, full-moon/new-moon/Sabbath markers, holiday/observance summaries, and matching dates from the other calendar |
| Holidays | Previous/next year navigation, recurring calendar observances for any year, and verified official holiday labels where available |
| Convert | Bidirectional string conversion with editable date and format patterns |
| About | Library layers and supported capabilities |
Month colors: red ● full moon, blue ○ new moon, green ✦ Sabbath.
Build the Android demo:
./gradlew :androidApp:assembleDebugFor iOS, open iosApp in Xcode and run the iosApp scheme.
The Myanmar calendar conversion logic in calendar_core is a Kotlin Multiplatform port/adaptation of the calendrical algorithms from yan9a/mmcal, a Myanmar calendar implementation maintained by Yan Naing Aye and its contributors. The upstream project provides C++ and JavaScript implementations of modern Myanmar calendrical calculations under the MIT License.
Special thanks to the contributors who made the underlying algorithms and reference implementation available to the community:
Thank you to these contributors and all contributors to yan9a/mmcal.
This project’s Kotlin API design, Kotlin Multiplatform demo, format utilities, holiday catalog, and documentation are maintained in this repository.
Copyright (c) 2026 Arjun Dhakal
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.