首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >伊斯兰(Hijri)日历的Javascript Intl.DateTimeFormat()输出在“Islamic”和“ar-SA”之间的差异

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

Stack Overflow用户
提问于 2022-02-05 09:47:47
回答 2查看 815关注 0票数 7

2022年3月3日是这个Hijri月的结束(1443年的Rajab月),即30 Rajab 1443 AH。

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

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

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

这是错误/错误,还是javascript的正确内部工作方式?

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

参见下面的代码示例:

我已经测试过这个节点和铬,它给出了同样的结果差异。

代码语言:javascript
运行
复制
let date = new Date("2022-03-03");
let options = {year:'numeric', month:'long',day:'numeric'};

let format = new Intl.DateTimeFormat('ar-SA-u-nu-latn', options);
console.log("3 March 2022 with 'ar-SA'         :"+format.format(date)+ " ==> means: 30 Rajab 1443 AH");

format = new Intl.DateTimeFormat('en-u-ca-islamic-nu-latn', options);
console.log("3 March 2022 with Islamic Calendar: "+format.format(date));

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-02-06 07:08:18

有三个可能的原因导致了你所看到的“一刀切”约会的问题:

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

下面我将讨论每一个问题。

1.日期初始化与日期格式化之间的时区不匹配

出现停工一天错误的最常见原因(正如@RobG在上面的评论中所指出的)是声明Date值时使用的时区与在所需日历中格式化时区时使用的时区之间的不匹配。

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

代码语言:javascript
运行
复制
new Date('2022-03-03').toLocaleDateString('en-US');
// outputs '3/2/2022' when run in San Francisco

new Date('2022-03-03').toLocaleDateString('en-US', { timeZone: 'UTC' });
// outputs '3/3/2022' as expected. UTC is used both for declaring and formatting.

new Date('2022-03-03').toLocaleDateString(
  'en-SA-u-ca-islamic-umalqura',
  { timeZone: 'UTC', month: 'long', day: 'numeric', year: 'numeric' }
);
// outputs 'Rajab 30, 1443 AH' as expected

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

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

第二个也是更微妙的问题是,JavaScript中使用了多个伊斯兰日历的变体。支持的日历列表在这里:对象/Intl/Locale/日历。摘自该页,以下是受支持的伊斯兰历法变体:

  • islamic
    • 伊斯兰历法

  • islamic-umalqura
    • 伊斯兰日历,Umm al

  • islamic-tbla
    • 伊斯兰日历,表格(中间年份2,5,7,10,13,18,21,24,26,29-天文时代)

  • islamic-civil
    • 伊斯兰日历,表格(中间年份2,5,7,10,13,18,21,24,26,29-民事时代)

  • islamic-rgsa
    • 伊斯兰历法,沙特阿拉伯

(也有一个不推荐的islamicc日历,但是应该使用islamic-civil。)

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

代码语言:javascript
运行
复制
new Intl.DateTimeFormat('ar-SA').resolvedOptions();
// {
//   calendar: "islamic-umalqura"
//   day: "numeric"
//   locale: "ar-SA"
//   month: "numeric"
//   numberingSystem: "arab"
//   timeZone: "America/Los_Angeles"
//   year: "numeric"
// }

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

代码语言:javascript
运行
复制
calendars = ["islamic", "islamic-umalqura", "islamic-tbla", "islamic-civil", "islamic-rgsa"];
options = { timeZone: 'UTC', month: 'long', day: 'numeric', year: 'numeric' };
date = new Date('2022-03-03');
calendars.forEach(calendar => {
  formatted = date.toLocaleDateString(`en-SA-u-ca-${calendar}`, options);
  console.log(`${calendar}: ${formatted}`);
});
// The code above outputs the following:
//   islamic: Shaʻban 1, 1443 AH
//   islamic-umalqura: Rajab 30, 1443 AH
//   islamic-tbla: Rajab 30, 1443 AH
//   islamic-civil: Rajab 29, 1443 AH
//   islamic-rgsa: Shaʻban 1, 1443 AH

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

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

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

票数 6
EN

Stack Overflow用户

发布于 2022-02-06 11:14:23

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

  1. 伊斯兰教
  2. 伊斯兰-umalqura
  3. 伊斯兰-塔布拉
  4. 伊斯兰-公民
  5. 伊斯兰rgsa

进行了50年(1980年1月1日至2030年12月31日)的比较。

由此产生的产出如下:

代码语言:javascript
运行
复制
============================================================
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%)
=============================================================

结果提供了以下一般资料:

默认islamic日历下的日期始终与islamic-rgsa一致。不确定默认的islamic是使用与islamic rgsa相同的代码,还是基于region选择其他类型。

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

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

从一些伊斯兰网站和应用程序的观察来看,新的islamic-umalqura日历是最常用的伊斯兰日历。它也是欧洲和北美的首选。

由于地区ar-SA islamic-umalqura 默认使用islamic-umalqura日历,因此 ar-SA 的日期输出(和月长)将在61%以上的时间内与 islamic 日历的日期不同。

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

代码语言:javascript
运行
复制
console.log("Comparing 50 years results under the 5 islamic calendar formats (from year 1980 to 2030)");
console.log("=".repeat(60));

let startDate = new Date("1980-01-01");  // date to start test from
let options   = {year: 'numeric', month: 'long', day: 'numeric'};
let d         = startDate;
let diff      = [0,0,0,0,0,0,0,0,0,0];  // array to hold the diff results
let totalDays = 18628;                  // total days approx 50 Gregorian years
for (let i=0; i<totalDays; i++) {
let dateIslamic     = new Intl.DateTimeFormat('en-u-ca-islamic'         ,options).format(d),
    dateIslamicTBLA = new Intl.DateTimeFormat('en-u-ca-islamic-tbla'    ,options).format(d),
    dateIslamicRGSA = new Intl.DateTimeFormat('en-u-ca-islamic-rgsa'    ,options).format(d),
    dateIslamicUMQ  = new Intl.DateTimeFormat('en-u-ca-islamic-umalqura',options).format(d),
    dateIslamicCIVL = new Intl.DateTimeFormat('en-u-ca-islamic-civil'   ,options).format(d);

if (dateIslamic != dateIslamicTBLA) diff[0]++;
if (dateIslamic != dateIslamicRGSA) diff[1]++;
if (dateIslamic != dateIslamicUMQ)  diff[2]++;
if (dateIslamic != dateIslamicCIVL) diff[3]++;

if (dateIslamicTBLA != dateIslamicRGSA) diff[4]++;
if (dateIslamicTBLA != dateIslamicUMQ)  diff[5]++;
if (dateIslamicTBLA != dateIslamicCIVL) diff[6]++;

if (dateIslamicRGSA != dateIslamicUMQ)  diff[7]++;
if (dateIslamicRGSA != dateIslamicCIVL) diff[8]++;

if (dateIslamicUMQ != dateIslamicCIVL)  diff[9]++;

d    = new Date(d.setDate(d.getDate() + 1)); // next day
}

console.log("islamic diff from islamic-tbla           :"+perc(0));
console.log("islamic diff from islamic-rgsa           :"+perc(1));
console.log("islamic diff from islamic-umalqura       :"+perc(2));
console.log("islamic diff from islamic-civil          :"+perc(3));
console.log("-".repeat(50));
console.log("islamic-tbla diff from islamic-rgsa      :"+perc(4));
console.log("islamic-tbla diff from islamic-umalqura  :"+perc(5));
console.log("islamic-tbla diff from islamic-civil     :"+perc(6));
console.log("-".repeat(50));
console.log("islamic-rgsa diff from islamic-umalqura  :"+perc(7));
console.log("islamic-rgsa diff from islamic-civil     :"+perc(8));
console.log("-".repeat(50));
console.log("islamic-umalqura diff from islamic-civil :"+perc(9));


function perc(n) {return + diff[n]+" days (" +((diff[n]/totalDays)*100).toFixed(2)+"%)";}

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70996839

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档