javascript 一句话算农历

同步发帖在 v2ex

今天发现 Intl 这个 ECMAscript 内置对象,可以一句话算农历。

  new Date().toLocaleString('zh-CN-u-ca-chinese').replace(/(\d+)\s*?年/, (_,y)=>"甲乙丙丁戊己庚辛壬癸".charAt((y-4)%10) + "子丑寅卯辰巳午未申酉戌亥".charAt((y-4)%12))

算农历最麻烦就是跨年。这个 API 处理得还挺好的。比如2020年1月的除夕夜+春节

  new Date(2020, 0, 24).toLocaleString('zh-CN-u-ca-chinese').replace(/(\d+)年 /, (_,y)=>"甲乙丙丁戊己庚辛壬癸".charAt((y-4)%10) + "子丑寅卯辰巳午未申酉戌亥".charAt((y-4)%12))
  乙亥腊月30 上午12:00:00
  new Date(2020, 0, 25).toLocaleString('zh-CN-u-ca-chinese').replace(/(\d+)年 /, (_,y)=>"甲乙丙丁戊己庚辛壬癸".charAt((y-4)%10) + "子丑寅卯辰巳午未申酉戌亥".charAt((y-4)%12))
  庚子正月1 上午12:00:00

连 腊月 正月 都能显示。还是挺 6 的。浏览器支持的话 Edge, Chrome 都可以,Firefox 和 Safari 的 ICU 版本太老需要微调一下。

23:39更新:网友 sarvatathagata 发现了个如下更简单的方法。不过这个方法无法地道的显示 腊月、正月。

  new Date().toLocaleString('ja-JP-u-ca-chinese')

稍微解释下 zh-Hans-CN-u-ca-chinese 是什么意思。这个叫 locale 也叫 language tag。
zh-Hans 是一门语言,简体中文。CN 表示在大陆地区用的。 -u-key1-value1-key2-value2... 表示打开 Unicode extension 模式,-ca 表示 calendar 日历,-chinese 表示农历。

如果把 -chinese 改成 -roc 还可以得到今年是民国109年。奇怪的姿势又增加了。

还有一个额外的参数,如 .toLocaleString(locale_id, options) 里面 options 可以细化

另外就是奇怪的数字变形方法:

  new Number(1234567890).toLocaleString('zh-Hans-CN-u-nu-hanidec')
  "一,二三四,五六七,八九〇"
  new Number(1234567890).toLocaleString('zh-Hans-CN-u-nu-fullwide')
  "1,234,567,890"
  new Number(1234567890).toLocaleString('zh-Hans-CN-u-nu-mathbold')
  "𝟏,𝟐𝟑𝟒,𝟓𝟔𝟕,𝟖𝟗𝟎"
  new Number(1234567890).toLocaleString('zh-Hans-CN-u-nu-mathdbl')
  "𝟙,𝟚𝟛𝟜,𝟝𝟞𝟟,𝟠𝟡𝟘"
  new Number(1234567890).toLocaleString('zh-Hans-CN-u-nu-mathmono')
  "𝟷,𝟸𝟹𝟺,𝟻𝟼𝟽,𝟾𝟿𝟶"
  new Number(1234567890).toLocaleString('zh-Hans-CN-u-nu-mathsanb')
  "𝟭,𝟮𝟯𝟰,𝟱𝟲𝟳,𝟴𝟵𝟬"
  new Number(1234567890).toLocaleString('zh-Hans-CN-u-nu-mathsans')
  "𝟣,𝟤𝟥𝟦,𝟧𝟨𝟩,𝟪𝟫𝟢"

还有获取相对时间(XX分钟前)、科学记数法、货币、地区的别名等奇奇怪怪的东西。

Intl 是 ECMAScript i18n API(ECMA-402)的一部分。在ES5.1+语言的运行时嵌入了一个阉割版的 ICU 库。为什么是阉割版呢?比如 ICU 库是 Unicode CLDR 规范的一种实现,比如 zh里可以发现不仅可以直接查到年(枚举60遍!),还可以查到生肖(js 里 {year: "zodiacs"}就不行),甚至节气(solarTerms)都包含了!js 里的 year 阉割得只有两种:numeric2-digit。可以看 v8 源码里的BuildPatternItems 怎么实现的。

值得注意的是,ICU 居然收录了日本天皇从大化 (645–650) 开始到现在 令和 年号。不公平啊。我大中华应该从西周的共和元年,公元前841年开始把年号都给补上啊混蛋!

还有就是货币大写 零壹贰叁肆伍陆柒捌玖拾 谁去给 ICU 提 issue 加上啊。

Comments