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中的伊斯兰日期?
参见下面的代码示例:
我已经测试过这个节点和铬,它给出了同样的结果差异。
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));
发布于 2022-02-06 07:08:18
有三个可能的原因导致了你所看到的“一刀切”约会的问题:
下面我将讨论每一个问题。
1.日期初始化与日期格式化之间的时区不匹配
出现停工一天错误的最常见原因(正如@RobG在上面的评论中所指出的)是声明Date
值时使用的时区与在所需日历中格式化时区时使用的时区之间的不匹配。
当您使用ISO 8601字符串初始化日期实例时,存储在Date实例中的实际值是自1970年世界协调时1月1日以来的毫秒数。根据系统时区的不同,new Date('2022-02-03')
可以是系统时区中的2月3日或2月2日。避免此问题的一种方法是在格式化时也使用UTC:
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
islamic-tbla
islamic-civil
islamic-rgsa
(也有一个不推荐的islamicc
日历,但是应该使用islamic-civil
。)
ar-SA
区域设置的默认日历是islamic-umalqura
日历,而不是islamic
日历。核实:
new Intl.DateTimeFormat('ar-SA').resolvedOptions();
// {
// calendar: "islamic-umalqura"
// day: "numeric"
// locale: "ar-SA"
// month: "numeric"
// numberingSystem: "arab"
// timeZone: "America/Los_Angeles"
// year: "numeric"
// }
不同的伊斯兰历法变体会产生不同的日历日期。例如:
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网站更新与固定的内容。
发布于 2022-02-06 11:14:23
根据贾斯汀·格兰特提供的优秀信息和数据,我对五(5)个伊斯兰日历的输出进行了比较:
对进行了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%)
=============================================================
结果提供了以下一般资料:
默认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秒才能输出;请等待它。
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)+"%)";}
https://stackoverflow.com/questions/70996839
复制相似问题