Skip to content

Repository files navigation

Myanmar Calendar for Kotlin Multiplatform

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:

  • Gregorian (English) date → Myanmar date
  • Myanmar date → Gregorian (English) date
  • Gregorian/Myanmar date strings with custom numeric patterns
  • Moon phase, fortnight day, Sabbath status, weekday, and localized display names
  • Gregorian-month and Myanmar lunar-month calendar views
  • Recurring Myanmar calendar observances for past and future years, plus verified annual official-holiday data where available
  • Pluggable holiday rules and a compact sample API for app integration

The calendar engine has no Android, iOS, or Compose dependency. The Compose UI is only a demo consumer of the shared library.

Project layout

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

Use the library

Install from Maven

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))
// တန်ခူး လဆန်း ၉

Demo

Visit the demo project to see MMCalendar in action:

https://github.com/newarjun101/myanmar-calendar-demo

Core conversion API

Gregorian to Myanmar

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.

Myanmar to Gregorian

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.

Julian day number

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,
)

Myanmar date result

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

Year type (yearType)

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.

Moon phase (moonPhase) and fortnight day (fortnightDay)

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 လကွယ်.

Sabbath marker (sabbathDay)

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.

Myanmar month numbers

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.

Formatting and parsing date strings

Output patterns

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.2024

Myanmar 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 09

Input patterns

CalendarDateConverter accepts numeric date strings. Input patterns require each of these tokens exactly once:

  • yyyy — year
  • MM or M — month
  • dd or d — day

All 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.2024

For a typed result instead of a string, use parseGregorian(...) or parseMyanmar(...).

Display helpers

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.

Weekday, holiday, and astrology extensions

Weekday helper

import com.newarjun101.mmcalendar.calendar_astrology.MyanmarAstrology

val weekday = MyanmarAstrology.weekday(GregorianDate(2024, 4, 17))
// Weekday.WEDNESDAY

calendar_astrology currently exposes calendar weekday data only. Traditional astrological rules can be built on top of this stable input.

Holiday rules

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.

Compose demo

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.

Run the demo

Build the Android demo:

./gradlew :androidApp:assembleDebug

For iOS, open iosApp in Xcode and run the iosApp scheme.

Notes and boundaries

  • The engine uses pure Kotlin and has no platform date/time dependency.
  • Date-string parsing is intentionally numeric and strict; use typed APIs for business/domain code whenever possible.
  • Official holiday observance and traditional astrology rules are app-specific extension points, not built-in assertions by this library.
  • This repository contains the library source in its shared module; publishing it as an independent Maven artifact is a separate build/release step.

Credits and algorithm attribution

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.

MIT License

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.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages