Adding Myanmar Calendar to Unicode

One of my goals for 2019 is tackling a problem which I first encountered in 2015 while working with the Asia Foundation in Myanmar. Several people listed their birthdates in the traditional Burmese lunar calendar and after paging through some homemade PHP sites, we ultimately had to buy an astrology book to convert them.
I learned that I was born on the 10th of Tagu (တန်ခူး), in the year 1350. It was during the water festival, which is good luck!

Yes. The likelihood of seeing a non-Gregorian calendar in practical use depends on where you travel: Japan just announced the next era in their emperor-based calendar, the Taiwanese/Minguo year (108) shows up on everyday tickets and receipts, and both the Islamic and Jewish calendars are used in religious settings. A handful of governments use these calendars officially, so it’s worth including them all in ICU.

You can use the most common calendars in the browser without special libraries, for example:

(new Date()).toLocaleDateString(“en-US-u-ca-japanese”)
> “4/9/31”
(new Date()).toLocaleDateString(“ja-JP-u-ca-japanese”, {era: “short”})
> 平成31年4月9日

This calendar code is not rewritten for every app and language, but instead imported from the International Components for Unicode (ICU) libraries in C++ and Java. These libraries unfortunately overlooked the Myanmar calendar and an SVN ticket was long abandoned before I ever landed on this problem.

The Myanmar year begins in April and has at least 12 months, alternating between 29 and 30 days.
Due to the lunar origins of the calendar, the first 14 days are labeled as ‘Waxing’, the 15th as ‘Full Moon’, with the remaining days starting over at ‘Waning 1’ and ending on ‘New Moon’.

To keep alignment between lunar and solar years, every 2–3 years there are watat leap years where the month Waso becomes known as First Waso, and is followed by a 30-day leap month called Second Waso or Waso II. In rare ‘great leap years,’ you have First Waso, Second Waso, plus one more day added to Nayon. Since independence from the UK there has been only one great leap year declared — a surprise decision in 2015 — so we hardcode the past years and don’t try to predict future ones:

Hardcoding is an imperfect solution to great leap years, but should find company with ICU’s support of the Islamic calendar, where the end of Ramadan depends on astronomical observations announced each year.

When I looked for calendar resources in 2015, I found little information and no JavaScript code. Revisiting the problem, I found two helpful open source libraries: mcal (JavaScript, by Yan Naing Aye) and mmcalendar (Java, by Chan Mrate Ko Ko).
In 2018, mcal was rewritten with a C++ implementation and multiple historical dates. This was instrumental to getting this done, so huge thanks to Yan Naing Aye for this and for making the library and interactive site.

ICU has a ‘Buddhist’ option following the Thai solar calendar, but it only changes the year (2019 is 2562 BE) and doesn’t support lunar months or the April new year.

The closest existing implementation in ICU was the Persian calendar. From that, I learned how to keep the calendars consistent with a count of days since the Julian calendar began (in 4713 BC). Considering how the Burmese calendar works, we should calculate the years since a recent checkpoint (such as Burmese independence), tick through additional days as I pass standard and great leap years, and arrive at the current year, month, then date.

One option for the waxing and waning cycles within a month, would be to list each as two months, (Tagu Waxing, Tagu Waning) or even four to include Full Moon and New Moon. Another option would be to print ‘Waxing’ and ‘Waning’ inside of the day/date, even though that’s typically a number.

Currently I decided to print the day as a number 1–30. Anyone who is going through the trouble of outputting a Burmese date can convert that number to waxing/waning in the local language as needed. The real legwork of this library is converting dates between different calendars and handling the effects of leap years.

It’s my first time creating a calendar, and this happens so rarely that the documentation and reference materials barely exist. I have little experience in C++ and want to keep the implementation as simple as possible.

I found instructions for building and testing the whole ICU4C test suite, but the system wouldn’t consider building a new calendar locale. I hacked together a testable solution by (locally only!) replacing the Thai/Buddhist calendar with the Myanmar one. This process still takes a lot of time to rebuild and capture the relevant logs before they scroll out of sight, but it works.

Currently I am seeing offsets of one day (possibly due to my timezone?), but at other times there is a month difference, and a particularly weird result for the added day in great leap year 2015. The JavaScript code works fine, so the bugs could have come from JS<->C++, changing variable types, or replacing MCal’s math.h functions with the ClockMath::floorDivide method used by other calendars. I’m reaching out to the real Unicode experts now to get advice on testing and documentation. With luck this will be on the way to production soon!

Nomadic web developer and mapmaker.