tibetan-date-calculator
Version:
A library to calculate tibetan calendar details. It is based on Svante Janson's paper www2.math.uu.se/~svante/papers/calendars/tibet.pdf
65 lines (57 loc) • 2.54 kB
text/typescript
import { YEAR_DIFF } from '../constants';
import { julianFromTrueDate, julianFromUnix, monthCountFromTibetan } from '../conversions';
import getMonthFromMonthCount from './get-month-from-month-count';
import getDayFromTibetan from './get-day-from-tibetan';
import { Day } from '../types'
/**
* Calculates a Tibetan date for a given western date. This does a binary search, and is therefore
* much slower than tibToWestern().
*
* The algorithm could be much improved by using the reverse of meanDate() to start with,
* and then using the fact that julian dates and "tibetan day numbers" have a quasi-linear relation.
*
* @param {Date} date - the western date
* @return {Day}
*/
const getDayFromWestern = (date: Date): Day => {
// const date = new Date(wYear, wMonth - 1, wDay);
const wYear = date.getFullYear();
const jd = julianFromUnix(date);
const tibYears = [wYear + YEAR_DIFF - 1, wYear + YEAR_DIFF + 1];
const monthCounts = tibYears.map(y => monthCountFromTibetan({ year: y, month: 1, isLeapMonth: true }));
const trueDate = monthCounts.map(m => 1 + 30 * m);
const jds = trueDate.map(n => julianFromTrueDate(n));
// croak "Binary search algorithm is wrong" unless $jd1 <= $jd && $jd <= $jd2;
while (trueDate[0] < trueDate[1] - 1 && jds[0] < jds[1]) {
const nTrueDate = Math.floor((trueDate[0] + trueDate[1]) / 2);
const njd = julianFromTrueDate(nTrueDate);
if (njd < jd) {
trueDate[0] = nTrueDate;
jds[0] = njd;
} else {
trueDate[1] = nTrueDate;
jds[1] = njd;
}
}
// so we found it;
let winnerJd;
let winnerTrueDate;
// if the western date is the 1st of a doubled tib. day, then jd[0] == jd - 1 and
// jd[1] == jd + 1, and the corresponding tib. day number is the one from jd[1].
if (jds[0] === jd) {
winnerJd = jds[0]; // eslint-disable-line prefer-destructuring
winnerTrueDate = trueDate[0]; // eslint-disable-line prefer-destructuring
} else {
winnerJd = jds[1]; // eslint-disable-line prefer-destructuring
winnerTrueDate = trueDate[1]; // eslint-disable-line prefer-destructuring
}
// figure out the real tib. date: year, month, leap month, day number, leap day.
const isLeapDay = winnerJd > jd;
const monthCount = Math.floor((winnerTrueDate - 1) / 30);
const day = (winnerTrueDate % 30) || 30;
const { year, month, isLeapMonth } = getMonthFromMonthCount(monthCount);
return getDayFromTibetan({
year, month, isLeapMonth, day, isLeapDay
});
};
export default getDayFromWestern;