Javascript Intl.DateTimeFormat() 伊斯兰 (Hijri) 日历输出中“islamic”和“ar-SA”之间的差异

Moh*_*fei 9 javascript datetime calendar date hijri

2022 年 3 月 3 日是回历月(今年回历 1443 年的回历月)结束;即伊斯兰历 30 Rajab 1443。

\n

根据伊斯兰 (Hijri) 日历,根据所有网站、应用程序、MS Office 和 Windows 日历,伊斯兰教历 1443 年的 Rajab 月为 30 天。

\n

当使用 javascript使用日历选项Intl.DateTimeFormat()显示2022 年 3 月 3 日islamic的伊斯兰 (Hijri) 日期时,它将给出伊斯兰 Hijri 日期 ( 1 Sha\xca\xbbban 1443 AH )。该结果是 Rajab 月后的一天(即下个月的 1 号),并且计算出 Rajab 月为 29 天而不是 30 天。

\n

但是,如果传递给的选项Intl.DateTimeFormat()ar-SA(即阿拉伯语-沙特阿拉伯),它将给出正确的结果。这很奇怪,因为该ar-SA区域设置默认使用伊斯兰(回历)日历。

\n

这是一个错误/错误还是 javascript 的正确内部工作原理?

\n

除了使用\'ar-SA\'语言环境(但不使用外部库)之外,是否有更可靠的方法来获取 Javascript 中的伊斯兰日期?

\n

请参阅下面的代码示例:

\n

我已经在 node 和 chrome 中对此进行了测试,它给出了相同的结果差异。

\n

\r\n
\r\n
let date = new Date("2022-03-03");\nlet options = {year:\'numeric\', month:\'long\',day:\'numeric\'};\n\nlet format = new Intl.DateTimeFormat(\'ar-SA-u-nu-latn\', options);\nconsole.log("3 March 2022 with \'ar-SA\'         :"+format.format(date)+ " ==> means: 30 Rajab 1443 AH");\n\nformat = new Intl.DateTimeFormat(\'en-u-ca-islamic-nu-latn\', options);\nconsole.log("3 March 2022 with Islamic Calendar: "+format.format(date));
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

Jus*_*ant 11

您遇到的“相差一位”日期问题可能有以下三种原因:

\n
    \n
  1. 日期初始化和日期格式之间的时区不匹配
  2. \n
  3. 使用伊斯兰历的错误变体(JS 实现通常提供 5 种不同的伊斯兰历!)
  4. \n
  5. 用于 JS 日历计算的 ICU 库中的错误
  6. \n
\n

我将在下面逐一介绍这些内容。

\n

1. 日期初始化和日期格式化时区不匹配

\n

相差一天错误的最常见原因是(正如@RobGDate在上面的评论中指出的那样)声明值时使用的时区与在所需日历中格式化该值时使用的时区不匹配。

\n

当您使用 ISO 8601 字符串初始化 Date 实例时,Date 实例中存储的实际值是自 UTC 1970 年 1 月 1 日以来的毫秒数。根据您的系统时区,new Date(\'2022-02-03\')可以是系统时区的 2 月 3 日或 2 月 2 日。避免此问题的一种方法是在格式化时也使用 UTC:

\n
new Date(\'2022-03-03\').toLocaleDateString(\'en-US\');\n// outputs \'3/2/2022\' when run in San Francisco\n\nnew Date(\'2022-03-03\').toLocaleDateString(\'en-US\', { timeZone: \'UTC\' });\n// outputs \'3/3/2022\' as expected. UTC is used both for declaring and formatting.\n\nnew Date(\'2022-03-03\').toLocaleDateString(\n  \'en-SA-u-ca-islamic-umalqura\',\n  { timeZone: \'UTC\', month: \'long\', day: \'numeric\', year: \'numeric\' }\n);\n// outputs \'Rajab 30, 1443 AH\' as expected\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,我Date.toLocaleDateString在上面使用,但结果与您使用的结果相同Intl.DateTimeFormat.format。两种方法的参数和实现是相同的。

\n

2. 使用错误的伊斯兰历法(JS 实现通常提供 5 种不同的伊斯兰历法!)

\n

第二个更微妙的问题是 JavaScript 中使用了多种伊斯兰日历变体。支持的日历列表位于: https: //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendars。摘自该页面,以下是受支持的伊斯兰历变体:

\n
\n
    \n
  • islamic\n
      \n
    • 伊斯兰历
    • \n
    \n
  • \n
  • islamic-umalqura\n
      \n
    • 伊斯兰历,乌姆古拉
    • \n
    \n
  • \n
  • islamic-tbla\n
      \n
    • 伊斯兰历,表格(闰年 [2,5,7,10,13,16,18,21,24,26,29] - 天文纪元)
    • \n
    \n
  • \n
  • islamic-civil\n
      \n
    • 伊斯兰历,表格(闰年 [2,5,7,10,13,16,18,21,24,26,29] - 民用历元)
    • \n
    \n
  • \n
  • islamic-rgsa\n
      \n
    • 伊斯兰历,沙特阿拉伯目击事件
    • \n
    \n
  • \n
\n
\n

(还有一个已弃用的islamicc日历,但islamic-civil应该使用。)

\n

区域设置的默认日历ar-SAislamic-umalqura日历,而不是islamic日历。核实:

\n
new Intl.DateTimeFormat(\'ar-SA\').resolvedOptions();\n// {\n//   calendar: "islamic-umalqura"\n//   day: "numeric"\n//   locale: "ar-SA"\n//   month: "numeric"\n//   numberingSystem: "arab"\n//   timeZone: "America/Los_Angeles"\n//   year: "numeric"\n// }\n
Run Code Online (Sandbox Code Playgroud)\n

不同的伊斯兰历变化会产生不同的日历日期。例如:

\n
calendars = ["islamic", "islamic-umalqura", "islamic-tbla", "islamic-civil", "islamic-rgsa"];\noptions = { timeZone: \'UTC\', month: \'long\', day: \'numeric\', year: \'numeric\' };\ndate = new Date(\'2022-03-03\');\ncalendars.forEach(calendar => {\n  formatted = date.toLocaleDateString(`en-SA-u-ca-${calendar}`, options);\n  console.log(`${calendar}: ${formatted}`);\n});\n// The code above outputs the following:\n//   islamic: Sha\xca\xbbban 1, 1443 AH\n//   islamic-umalqura: Rajab 30, 1443 AH\n//   islamic-tbla: Rajab 30, 1443 AH\n//   islamic-civil: Rajab 29, 1443 AH\n//   islamic-rgsa: Sha\xca\xbbban 1, 1443 AH\n
Run Code Online (Sandbox Code Playgroud)\n

3.用于JS日历计算的ICU库中的Bug

\n

意外日期的第三个可能原因是 JS 引擎内的日历计算代码是否存在错误。据我所知,所有主要浏览器都将其日历计算委托给一个名为ICU. 如果您使用了正确的时区和日历变化,但计算仍然存在问题,那么您可能需要尝试在 ICU JIRA 站点中提交问题:https://unicode-org.atlassian。 net/jira/software/c/projects/ICU/issues/ .

\n

顺便说一句,在回答这个问题时,我注意到Intl.DateTimeFormat 构造函数的 MDN 文档中存在一个错误,其中支持的日历列表是错误的。我提交了https://github.com/mdn/content/pull/12764来修复内容。此 PR 已合并,但生产 MDN 站点可能需要一段时间才能更新固定内容。

\n

  • 这是一个很好的回应。谢谢贾斯汀。 (2认同)

Moh*_*fei 6

根据贾斯汀·格兰特提供的以下精彩信息和数据,我对五 (5) 个伊斯兰历法的输出进行了比较:

  1. 伊斯兰的
  2. 伊斯兰乌马尔库拉
  3. 伊斯兰-tbla
  4. 伊斯兰民事
  5. 伊斯兰-rgsa

产出比较是在50年期间(从1980年1月1日到2030年12月31日)进行的

结果输出如下:

============================================================
islamic diff from islamic-tbla           :6369  days (34.19%)
islamic diff from islamic-rgsa           :0     days ( 0.00%)
islamic diff from islamic-umalqura       :11425 days (61.33%)
islamic diff from islamic-civil          :15919 days (85.46%)
------------------------------------------------------------
islamic-tbla diff from islamic-rgsa      :6369  days (34.19%)
islamic-tbla diff from islamic-umalqura  :10777 days (57.85%)
islamic-tbla diff from islamic-civil     :18628 days (100.00%)
-------------------------------------------------------------
islamic-rgsa diff from islamic-umalqura  :11425 days (61.33%)
islamic-rgsa diff from islamic-civil     :15919 days (85.46%)
-------------------------------------------------------------
islamic-umalqura diff from islamic-civil :9049  days (48.58%)
=============================================================
Run Code Online (Sandbox Code Playgroud)

结果给出以下一般信息:

默认日历下的日期islamic始终与 一致islamic-rgsa。不确定默认值是否islamic使用与 相同的代码,islamic rgsa或者它根据region.

日历下的日期islamic-civil与所有其他日历格式的差异最大(85% 到 100% 之间)。

新日历下的日期islamic-umalqura与其他日历下的日期差异约为50%至62%。

从一些伊斯兰遗址和应用的观察来看,新islamic-umalqura历是最常用的伊斯兰历。它在欧洲和北美也受到青睐。

由于区域设置默认ar-SA使用日历,因此在超过 61% 的时间里,日期输出(和月份长度)将与日历的输出不同。islamic-umalquraar-SAislamic

下面提供了我使用的测试代码,但请注意,它需要大约 25 秒才能给出输出;请稍等

============================================================
islamic diff from islamic-tbla           :6369  days (34.19%)
islamic diff from islamic-rgsa           :0     days ( 0.00%)
islamic diff from islamic-umalqura       :11425 days (61.33%)
islamic diff from islamic-civil          :15919 days (85.46%)
------------------------------------------------------------
islamic-tbla diff from islamic-rgsa      :6369  days (34.19%)
islamic-tbla diff from islamic-umalqura  :10777 days (57.85%)
islamic-tbla diff from islamic-civil     :18628 days (100.00%)
-------------------------------------------------------------
islamic-rgsa diff from islamic-umalqura  :11425 days (61.33%)
islamic-rgsa diff from islamic-civil     :15919 days (85.46%)
-------------------------------------------------------------
islamic-umalqura diff from islamic-civil :9049  days (48.58%)
=============================================================
Run Code Online (Sandbox Code Playgroud)