How I convert Gregorian date to Nepali date

With the magic of programming, you too can conveniently change between Gregorian and Nepali dates. Here I will show you exactly that using javascript.

On this page

The Nepali calendar (Bikram Sambat) is the official calendar of Nepal. It is a lunisolar calendar which may sound interesting but this causes a few headaches to the people as it is not as simple and consistent as it's Gregorian counterpart. Also having to constantly convert from Bikram Sambat(BS) to Gregorian(AD) is a huge challenge.

How is the Nepali calendar structured?

The Bikram Sambat has twelve months and a new year usually begins around 12–15 April. The start of a Nepali month lies approximately mid-way Gregorgian months.

A calendar for the month of Mangsir 2079 BS, showing corresponding Gregorian date.
A calendar for the month of Mangsir 2079 BS, showing corresponding Gregorian dates.
Bikram Sambat Months Gregorgian Months
Baisakh April–May
Jestha May–June
Ashad June–July
Shrawan July–August
Bhadra August–September
Ashoj September–October
Kartik October–November
Mangsir November–December
Poush December–January
Magh January–February
Falgun February–March
Chaitra March–April

Few quirks of the Nepali Calendar

Tackling the problem

  1. Find the Nepali year that the input Gregorian date lies on.
    1. A reference date is needed, usually it is taken as a single point in time or multiple references — say, start of every Nepali year.
  2. Find the total days passed respective to the selected reference date.
  3. For the month, keep adding up days in the month chronologically until it almost exceeds the days passed.
  4. For the day of month, the difference of the total days of month from before and days passed.

Setting up

Considering all the uncertainties it’s necessary to hard-code the start of each Nepali year. We’ll use this as reference date for finding the Nepali year and days passed.

const yearStart = {
  '2078': '2021-04-14',
  '2079': '2022-04-14',
  '2080': '2023-04-14',
  '2081': '2024-04-13',
  '2082': '2025-04-14'  // End of the previous year
};

We will also need to input length of each month of every year.

const monthLengths = {
  '2078': [31, 31, 31, 32, 31, 31, 30, 29, 30, 29, 30, 30],
  '2079': [31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30],
  '2080': [31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 30],
  '2081': [31, 31, 32, 32, 31, 30, 30, 30, 29, 30, 30, 30]
};

Lets add labels for months which will be useful later.

const monthTitles = ['Baisakh',
  'Jestha',
  'Ashad',
  'Shrawan',
  'Bhadra',
  'Ashoj',
  'Kartik',
  'Mangsir',
  'Poush',
  'Magh',
  'Falgun',
  'Chaitra'];

Step 1: Finding the year

Finding the Nepali year is straightforward, just loop though the array of reference dates and find the year where given date just exceeds the new year date.

// Convert any given date to timezone specific
function localiseDate(date) {
  let options = {
    timeZone: 'Asia/Kathmandu',
    year: 'numeric',
    month: 'numeric',
    day: 'numeric',
  }
  let localDate = date.toLocaleString('en-GB', options);
    // dd/mm/yyyy -> yyyy-mm-dd
  localDate = localDate.split('/').reverse().join('-');
  return localDate;
}

function getYear(date) {
  // For the sake of accuracy with the reference
  let localDate = localiseDate(date);
  let npYear = null;
  let lowerLimit = yearStart[Object.keys(yearStart)[0]];
  // Finds the index(key) of the array where the condition satisfies
  for (let key in yearStart) {
    if (localDate >= lowerLimit &&
      localDate < yearStart[key]) {
      npYear = `${key - 1}`;
      return npYear
    }
  }
  return "error";
}

Step 2: Calculating total days passed

Total days passed is taken from the start of the Nepali year to the given date.

Note: daysPassed needs to be incremented by 1 as it is calculated after first day of the reference year not from it.

function getDaysPassed(year, date) {
  let localDate = localiseDate(date)
  let givenDate = new Date(localDate);

  let startDate = new Date(yearStart[year]);
  // Difference of time in milliseconds then to days
  let daysPassed = (givenDate.getTime() - startDate.getTime())/(1000*60*60*24);
  
  return Math.round(daysPassed + 1);
}

Step 3: Finding the month and day of month

Subtract consecutive days in a month from days passed while also tracking the index for the month as monthIndex. Then the remainder days is the dayOfMonth (Date).

Visually,

Waterfall chart showing distribution of total days passed interms of months and days.
Waterfall chart showing distribution of total days passed interms of months and days.
function getMonthAndDate(year, date) {
  let daysPassed = getDaysPassed(year, date);
  let monthIndex = null;
  let dayOfMonth = null;
  for (let i = 0; i < 12; i++) {
    if (daysPassed <= monthLengths[year][i]) {
      monthIndex = i;
      dayOfMonth = daysPassed;
      break;
    }
    daysPassed -= monthLengths[year][i];
  }

  let result = {
    'month': parseInt(monthIndex + 1),
    'dayOfMonth': dayOfMonth
  };
  return result;
}

Step 4: Finishing up

Now we can calculate the any date from 2021-04-14 but before 2025-04-14.

let dateStr = "2022-12-02"; //yyyy-mm-dd
let date = new Date(dateStr);
let npYear = getYear(date);

if (npYear === "error") {
  console.log("Error: Date is outside the limit!");
} else {
  let npMonthAndDate = getMonthAndDate(npYear, date);
  let npDate1 = `${npYear}-${npMonthAndDate['month']}-${npMonthAndDate['dayOfMonth']}`

  console.log(npDate1);
  // 2079-8-16

  let npDate2 = `${monthTitles[npMonthAndDate['month'] - 1]} ${npMonthAndDate['dayOfMonth']}, ${npYear}`

  console.log(npDate2);
  // Mangsir 16, 2079
}

Conclusion

As you can see, conversion from BS to AD is fairly simple. This approach can be extended to include more range of dates.

For converting backwards, the same principle and data can be used with some minor changes to the code.

Resources

  1. Vikram Samvat (Bikram Sambat), Wikipedia
  2. English to Nepali Date Converter, Hamro Patro

Change log

August 2, 2023

Fixed a bug with localiseDate function, where it would incorrectly format dates in different locales.

function localiseDate(date) {
    …
-    let localDate = date.toLocaleString([], options);
+    let localDate = date.toLocaleString('en-GB', options);
    …
}
Comprehensive overview of equations in Word
Pandoc with LaTeX: Best of both worlds