Computer Method

The previous section shows the steps to determine if a given year is a normal year, a leadp-day year or a leap-month year. With the result, we can loop through the calendar year from a known point until the target year.

Sample Php Code

The following are Php code from the algorithm from previous section. The following are based on the books by Mr. Roath Kim Soeun. This is only a portion of the calculation that needed to determine if the year is a regular year, a leap-day year, or a leap-month year.

// return 0-29
function get_bodithey($year) {
  $ahk = get_aharkun($year);
  $avml = floor((11 * $ahk + 25)  / 692);
  $m = $avml + $ahk + 29;
  return ($m % 30);
}

// return 0-291
function get_avoman($year) {
  $ahk = get_aharkun($year);
  $avm = (11 * $ahk + 25)  % 692;
  return $avm;
}

// return int
function get_aharkun($ad_year) {
  $beyear = get_be_year($ad_year);
  $t = $beyear * 292207 + 499;
  $ahk = floor($t / 800) + 4;
  return $ahk;
}

// return 1-800
function kromthupul($be_year) {
   $akh = get_akhakun_mod($be_year);
   $krom = 800 - $akh;
   return $krom;
}

function is_khmer_solar_leap($year) {
   $be_year = get_be_year($year); 
   $krom = kromthupul($be_year);
   if ($krom <= 207) return 1;
   else return 0;
}
 
function get_akhakun_mod($be_year) {
   $t = $be_year * 292207 + 499;
   $ahkmod = $t % 800;
   return $ahkmod;
}

// return 0:regular, 1:leap month, 2:leap day, 3:leap day and month
function get_bodithey_leap($ad_year) {
  $result = 0;
  $a = get_avoman($ad_year);
  $b = get_bodithey($ad_year);

  // check bodithey leap month
  $bodithey_leap = 0;
  if ($b >= 25 || $b <= 5) {
    $bodithey_leap = 1;
  }
  // check for avoman leap-day based on gregorian leap
  $avoman_leap = 0;
  if (is_khmer_solar_leap($ad_year)) {
    if ($a <= 126) $avoman_leap = 1;
  } else {
    if ($a <=137) {
      // check for avoman case 137/0, 137 must be normal year (p.26)
      if (get_avoman($ad_year + 1) == 0) {
        $avoman_leap = 0;
      } else $avoman_leap = 1;
    }
  }

  // case of 25/5 consecutively
  // only bodithey 5 can be leap-month, so set bodithey 25 to none
  if ($b == 25) {
    $next_b = get_bodithey($ad_year + 1);
    if ($next_b == 5) $bodithey_leap = 0;
  }

  // case of 24/6 consecutively, 24 must be leap-month
  if ($b == 24) {
    $next_b = get_bodithey($ad_year + 1);
    if ($next_b == 6) $bodithey_leap = 1;
  }
  
  // format leap result (0:regular, 1:month, 2:day, 3:both)
  if ($bodithey_leap == 1 && $avoman_leap == 1) {
    $result = 3;
  } else if ($bodithey_leap == 1) {
    $result = 1;
  } else if ($avoman_leap == 1) {
    $result = 2;
  } else $result = 0;

  return $result;
}

// return 0:regular, 1:leap month, 2:leap day (no leap month and day together)
function get_protetin_leap($adyear) {
  $b = get_bodithey_leap($adyear);
  if ($b == 3) { 
    return 1;
  }
  if ($b == 2 || $b == 1) { 
    return $b;
  }
  // case of previous year is 3
  if (get_bodithey_leap($adyear - 1) == 3) { 
    return 2;
  }
  // normal case
  return 0;
}

The final get_protetin_leap function can tell us whether a particular year is a normal year, a leap-month year or a leap-day year. Thus we can iterate through the year from a know point to a target year.

Iteration

The approach is to use the known Gregorian calendar then mapped out the correspond Khmer calendar system. After knowing the type of Khmer calendar year, we will increment one year at a time from a specific year to the target year. To do that we first need a start date. I use January 1, 1900 AD in Gregorian calendar. This date will be called an epoch. The associate Khmer known date is 1 Keit of Bos (month number two).

Epoch Date: January 1, 1900

Associate Khmer Epoch Date: 
    epoch_year  = 1900;
    khmer_month = 2; // 1:Makasay, 2:Boss
    khmer_day   = 1; // First day of the month (1-30)

Next, we will start iterate from the Epoch year to the desired calendar year that we wanted to show. We start of by saving off the Epoch month and day into $newm and $newd respectively.

    newm = epoch_month;
    newd = epoch_day;

We need to update the $newm and $newd per each iteration. In order to perform this update, we need to know how many days in a Gregorian year. This function (is_gregorian_leap) determines if a year is a Gregorian leap year or not. See the code section for detail implementation of this function. If a year a Gregorian year is a leap year then it has 366 days and 365 days if it is not. We save this in $gnumday variable.

   // get number of days in a Gregorian year 
   if (is_gregorian_leap(year)) { 
     gnumday = 366;
   } 
   else { 
     gnumday = 365;
   }

Then we find the number of days that differ in Gregorian year and Khmer year. The number of days in Khmer year is determined by the type of Khmer year (discuss in the next section). If it is a leap-day year the number of days is 355 days, a leap-month year is 384 days, and a normal year is 354 days.

   // get number of days in a Khmer year
   if (is_khmer_leap_month(year)) { 
     knumday = 384;
   }
   else if (is_khmer_leap_day(year)) { 
     knumday = 355;
   } else { 
     knumday = 354;
   }
   // find the different between gnumday and knumday
   diff = gnumday - knumday;

From the differences in number of days above (diff), we can update newm and newd for that year. This update is using the fact that if Khmer year is shorter or longer than Gregorian year by x number of days, we just subtract or add from the current KhmerDay and KhmerMonth respectively.

This method is done by determining how many days in a particular Khmer month in case the subtraction or addition goes pass the valid number of day in Khmer month (1 to 29 or 30).

   // find newd, newm of Khmer date
   newd = newd + diff;
   maxday = get_numofday_in_kmonth(newm, year);
   // if newd is bigger the number of day in 
   // in that month, adjust the newm and newd
   while(newd > maxday) { 
      newd = newd - maxday; 
      newm++;
      maxday = get_numofday_in_kmonth(newm, year);
   }
   // if newd is negative (case of subtraction)
   while (newd <= 0) {
      newd = get_numofday_in_kmonth(newm - 1, year) 
      + newd; 
      newm--;
   }

In this iteration, the Khmer month and day would result in January 1, 1901.

The iteration repeats until the year matches the year we want to show. At the end of the iteration, we know that Khmer date for the beginning of the year to display. This is saved in $newm and $newd for Khmer month and day respectively.

Now we call to the Khmer calculation to determine the type of year for Khmer calendar.

get_protetin_leap($year);
After knowing the KhmerDay and KhmerMonth for a given year, we can display the monthly calendar with Khmer date. We first need to identify if the given Khmer year is a normal, leap-day, or leap-month year.

Khmer Monthly Calendar Utility

From the algorithm above, I can create a Khmer monthly calendar. Khmer calendar typically added specific the moon phases. We can use the Khmer day to determine the moon phases. If the Khmer day is 8 (8 Keit), it is a first quarter and 15 (15 Keit) is a full moon. If it is the last day of the Khmer month which is 29 or 30 (14 Roaj or 15 Roaj), it is a new moon.

There are also specific types of day that are added to the calendar. For example Tgnai Koar, Tgnai Pengboramei, and Tgnai Sel are usually shown in Khmer calendar. See Khmer Terminologies in the appendix for more detail on how to add these types of day.

It is important to display the Khmer associated months in the calendar. One Gregorian month can span exactly one Khmer month or it can span up to three months. To accommodate the possibilities, I use three different color codes to identify the month. The Khmer date shown each day will have the color that corresponds to the month.

A calendar cannot be complete without display the year. The most used era in Khmer calendar is Buddhist Era (BE). To find BE year, we just add 544 to the current Gregorian year. Be aware that BE year is incremented in Khmer New Year day. The date is typically fall in April. See the section about Songkran date for more detail. The following is the pseudo code for determining the BE.

if (current_month < april) {  
   BE = current_year + 543;
} else { 
   BE = current_year + 544;
}

Khmer also uses Moha Sakaraj (MS)1 and Jolak Sakaraj (JS)2. The following shows the pseudo code of calculating the MS and JS.

MS = current_year - 78;
JS = current_year - 638;

The religious events can also be added to the calendar by using the Khmer date. See the appendix for religious events.

Data Verification

The following are list of dates that has Khmer Calendar and Gregorian Calendar from different sites I found online.

Source Event Khmer Calendar Date Gregorian Date Comment
http://km.wikipedia.org/wiki/និល_ទៀង និល ទៀង ប្រសូត ថ្ងៃ​ព្រហស្បតិ៍ ​២​កើត ខែ​អស្សុជ ឆ្នាំ​ឆ្លូវ បញ្ច​ស័ក ព.ស.​២៤៥៧ ២ តុលា គ.ស.​១៩១៣ Matched
http://whoincam.wordpress.com/   ​ថ្ងៃ​ព្រហស្បតិ៍ ១៣​រោច​ ខែ​បុស្ស ឆ្នាំ​វក (ឆ​ស័ក)ព.ស.​២៤៨៨ ថ្ងៃ​ទី​១១ ខែ​មករា ឆ្នាំ​១៩៤៤ 1945 would match
http://km.wikipedia.org/wiki/ប្រាក់_ហ៊ិន ប្រាក់ ហ៊ិន ៨​កើត ខែ​កក្ដិក ឆ្នាំ​កុរ ព.ស.​២៤៩១ ២០ ខែ​វិច្ឆិកា គ.ស.​១៩៤៧ Matched
http://km.wikipedia.org/wiki/ជួន_ណាត Chuon Nath ថ្ងៃ​១៣​កើត និង​១៤​កើត ខែ​ភទ្របទ (ឆ្នាំរកា ឯក​ស័ក, ព.ស.​ ២៥១៣) ​ថ្ងៃ​ទី​២៤ និង​២៥ ខែ​កញ្ញា ឆ្នាំ​១៩៦៩ Matched
http://whoincam.wordpress.com/   ថ្ងៃ​ច័ន្ទ ៦​រោច ខែ​អស្សុជ ឆ្នាំ​រោង (សំរឹទ្ធិ​ស័ក) ព.ស.​២៥៣២ ​ថ្ងៃ​ទី​៣១ ខែ​តុលា គ.ស.​១៩៨៧ 1988 would match
http://km.wikipedia.org/wiki/ជួន_ណាត Chuon Nath Death ថ្ងៃ​១២​កើត ខែ​ភទ្របទ ឆ្នាំ​រកា ឯក​ស័ក ព.ស.​២៥១៣ ថ្ងៃ​ទី​២៣ កញ្ញា ឆ្នាំ​១៩៦៩ Matched
http://www.everyday.com.kh ពិធីច្រត់ព្រះនង្គ័ល ថ្ងៃ ៤ រោច ខែពិសាខ ថ្ងៃទី ២៦ ឧសភា2005 Matched
http://www.chanbokeo.com   ថ្ងៃ ចន្ទ ១២កើត ខែមាឃ ឆ្នាំខាលទោស័ក ព.ស ២៤៩៣ ទី១៨ ខែកុម្ភៈឆ្នាំ១៩៥១ Matched
http://khmeritforyou.blogspot.com ថ្ងៃ ភ្ជុំបិណ្ឌ ថ្ងៃ ១៥ រោច ខែ ភទ្របទ ឆ្នាំ ជូត សំរិទ្ធិស័ក
ព.ស. ២៥៥២
ទី 29 ខែ កញ្ញា ឆ្នាំ 2008 Matched

 

Sample Computer Programs

See the Calendar Tools section more information about the web utilities and source codes on related materials.

This is a sample utility that displays Khmer Chhankitek calendar. The implementation is done using PHP.


<< Calendar Algorithm < Table of Content > Khmer New Year >>