TEA Calendar
Pragmatically convert Gregorian calendar date of the period 1583-2100 to Chinese Calendar date
Demo
Table Of Contents
About the Project
This JavaScript program converts any given Gregorian calendar date of the period 1583-2100 to its corresponding Chinese calendar date. It is intended to be an alternative to the conversion via the JavaScript standard built-in object [Intl.DateTimeFormat](Intl.DateTimeFormat - JavaScript | MDN), not always reliable for this particular purpose in the real world. The code below (see also this codepen) illustrates this inconsistency, which encompasses more than four thousand dates of the past five centuries.
//conversion wiht the JavaScript's Standard built-in objects
const date = new Date('2018-11-08T12:00:00.000');
const options = {year: 'numeric', month: 'numeric', day: 'numeric' };
const dateFormat = new Intl.DateTimeFormat('fr-CA-u-ca-chinese', options);
let output = dateFormat.format(date);
//output in Chrome as well as in Firefox: "2/10/35".
//In reality, the corresponding date is "1/10/35".
Note
About the correct conversion of the date above, cf., for example, the conversion table 2011-2020 published by the Taipei Astronomical Museum or the Gregorian-Lunar Calendar Conversion Table 2018 of Hong Kong Observatory.
Due to the nature and the history of the traditional Chinese calendar (and the traditional East-Asian calendars in general), it is impossible to resolve this problem by adjusting the astro-mathematical formulas used in the major browser engines (more precisely, the subclass ChineseCalendar developped by IBM and integrated in International Components for Unicode, then in Chromium, Gecko and Webkit). One of possible solutions is to convert the problematic dates by referring to a dedicated dataset. Such a patch requires filtering each input, resulting certainly in a slow-down in the calculation process.
It is more pragmatic to use only the data collected from the existing calendars (in the same way as the class ChineseLunisolarCalendar of .NET) instead of (re)doing the work of calculation of their editors. By adopting this “down-to-earth” approach, the program presented here is built upon a model of data abstraction which, by exploiting certain characteristics of the traditional lunisolar calendar of East Asia, allows not only to substantially reduce the size of the data to be conveyed but also to do the conversion by quite few simple arithmetic operations.
An NPM version with identical core codes is also published in GitHub.
Features
ESM.
With a linguistic module supporting outputs with pinyin, in Chinese and in Korean.
Size of minified js file: 4.42 kB.
Speed of conversion (operations per second, according to tests carried out in JSBench.me):
Day (s) TEA calendar JS's Intl.DateTimeFormat One day 1.1M ops 52K ops 30 consecutive days 37K ops 1.7K ops 365 consecutive days 3.2K ops 143 ops
Note
Although demonstrating a narrower gap, the outcome of another test, which utilizes the Performance API and runs on localhost, essentially corroborates the findings shown above.
Usage
Basic conversion
1. import the core module:
- local import:
import {Teac} from '/PATH/TO/teac.min.js'
- remote import from deno.land:
import {Teac} from 'https://deno.land/x/tea_calendar/teac.min.js'
string
in "YYYY-MM-DD" format to get an array
of four elements:
2. input a Gregorian Calendar date number of the year in the sexagenary cycle,
lunar month number,
day number,
Boolean value for leap month (
true
: leap month)
const date = new Teac('2025-07-28').num();
// Expected output: [42, 6, 4, true]
Note
In order to avoid the impact of time zone setting of the device (or the network), this program uses the UTC and the 12:00:00 GMT+00:00 for each input date. For example, the string '2023-04-04' is converted to "2023-04-04T12:00:00.000Z" before the construction of the corresponding JavaScript Date object.
i18n
Lang
with the core module (for the CDN links, see above):
1. import the linguistic module import {Teac, Lang} from './Teac.js'
2a. output the sexagenary years in string format:
- in Chinese:
const d = new Teac('2025-07-28').yearIn('zh');
// Expected output: ['乙巳', 6, 4, true]
- in Korean:
const d = new Teac('2025-07-28').yearIn('ko');
// Expected output: ['을사', 6, 4, true]
- in Pinyin:
const d = new Teac('2025-07-28').yearIn('en');
// Expected output: ['yi-si', 6, 4, true]
Note
Any ISO 639-1 codes other than ko
and zh
could replace the en
here. In other words, de
, fr
, nl
are valid and all produce the same output.
2b. or, output entirely in text format:
- in traditional Chinese:
const d = new Teac('2025-07-28').sino(0)
// Expected output: ['乙巳年', '閏六月', '初四']
- in simplified Chinese:
const d = new Teac('2025-07-28').sino(1)
// Expected output: ['乙巳年', "闰六月', '初四']
- without literal characters:
const d = new Teac('2025-07-28').sino(0, false);
// Expected output: ['乙巳', "閏六', '初四']
## Limitations
Because of their closeness to the midnight, the 9th new moon of 2057, the 8th new moon of 2089 and the 7th one of 2097 may have a discrepancy of one day. Any prospective conversion concerning these dates is subject to adjustment and this program is of no exception.
License
Distributed under the MIT License. See LICENSE for more information.
Author
- Kuo Wei-Shiung, kws.baseed.net.
Acknowledgements
- Calendrical data from Professor Yuk Tung Liu's Conversion between Western and Chinese Calendar (722 BCE — 2200 CE), one of the best, if not the best source now published.