TL;DR, 要求是能够采用波斯 (Jalali) 日期(也称为波斯阳历回历),如
Esfand 19, 1400
(即 "12/19/1400"
)并将其转换为其他日历(公历、伊斯兰历、中文、希伯来语等)无需使用外部库或复杂的天文方程。并且无需使用新日期Temporal API的未决实现到Javascript中。
Javascript 内置方法
Intl.DateTimeFormat()
将公历日期转换为各种日历的日期(18 个世界日历),包括输出字符串的格式。
但是,截至今天(2022 年 3 月),Javascript 不提供反向操作的内置方法,即将波斯日期(和其他日历的日期)转换回公历日期或其他日历。为此,您将需要使用外部日期库来进行转换,例如“moment.js”和许多其他库。
我进行日期转换的方法如下,作为 StackOverflow 推荐的这个问题的答案:我可以回答我自己的问题吗?
下面的简短 Javascript 函数不使用外部库,并提供将波斯 (Jalali) 日期(从波斯年 -272,442 AP 到 +275,139 AP)转换为以下 18 个 Javascript 日历中的任何一个,并具有以下选项:格式化结果输出:
"buddhist", "chinese", "coptic", "dangi", "ethioaa", "ethiopic", "gregory", "hebrew", "indian", "islamic", "islamic-umalqura", "islamic-tbla", "islamic-civil", "islamic-rgsa", "iso8601", "japanese", "persian", "roc", "islamicc".
该方法也不使用复杂的数学或天文公式,仅依赖于 Javascript 内置日历转换算法,而这些算法又基于 ICU 代码 [https://icu.unicode.org/]。
这种方法可确保输出始终准确且完全符合 Javascript 引擎输出。
persianToCalendars(year, month, day, [options])
以最简单的形式,该函数默认使用 ISO 日期格式将波斯日期转换为
Gregorian
日历。
示例:将波斯日期 Esfand 19, 1400(即 12/19/1400)转换为公历。
persianToCalendars(1400,12,19);
output: 2022-03-10T00:00:00.000Z // default output Gregorian ISO format
要将波斯日期转换为另一个日历(例如“伊斯兰”日历):
persianToCalendars(1400,12,19, { toCal: "islamic-umalqura" });
output: 8/7/1443 AH
要向输出添加格式,请使用 Javascript
'dateStyle'
方法中的 Intl.DateTimeFormat()
选项。
示例:将波斯日期转换为具有完整日期样式的伊斯兰日期
persianToCalendars(1400,12,19, { toCal: "islamic-umalqura", dateStyle: "full" });
output: Thursday, Shaʻban 7, 1443 AH
示例:使用波斯语区域设置将波斯语日期转换为希伯来语
persianToCalendars(1400,12,19, { toCal:"hebrew", dateStyle: "full", locale:"fa"})
output: پنجشنبه ۷ واذار الثانی ۵۷۸۲ تقویم عبری
上述操作可用于所有其他 18 个日历。
一个附加功能是能够将波斯日期格式化为任何可用的
'dateStyles'
和 'locales'
,无需转换。
为此,请将
'toCal'
指定为 persian
示例:使用波斯语区域设置格式化波斯语日期
persianToCalendars(1400,12,19,{toCal:"persian",dateStyle:"full", locale:"fa"}));
output: ۱۴۰۰ اسفند ۱۹, پنجشنبه // mind the RTL requirements
示例:在印地语区域设置波斯语日期格式
persianToCalendars(1400,12,19,{ toCal : "persian", dateStyle : "full", locale : "hi"}));
output: AP गुरुवार, 19 ईस्फन्द् 1400
您可以使用
Intl.DateTimeFormat()
中的所有可用选项来格式化输出日期。
如果将无效的波斯日期传递给函数,将会生成错误
Invalid Persian Date!
。
无效的波斯日期是指当月中的日期不正确或者日期或月份不正确的日期。
例如,波斯日期 1400/12/30 无效,因为波斯历的 12 月(“Esfand”月)是 1400 年的 29 天。
未来的 Javascript Temporal API 将使这项任务变得更简单。
/*********************************************************************
* @function : persianToCalendars(year, month, day, [options])
*
* @purpose : Converts Persian/Iranian Date (Jalali Date) to the corresponding Gregorian Date.
* Handles Persian dates from -272,442 AP to +275,139 AP.
* Uses the 'JS Calendar Conversion by Target Approximation' Method.
* No external libraries or complex mathematical/astronautical formulas.
*
* @version : 1.00
* @author : Mohsen Alyafei
* @date : 17 Feb 2022
* @licence : MIT
* @param : year : (numeric) Persian year (-272442 to 275139)
* @param : month : (numeric) Persian month (1 to 12) note: months is standard 1 based
* @param : day : (numeric) Persian day (1 to 31)
* @param : options: Object with the following optional parameters:
*
* 'toCal' : Specifies the the type of output Calendar to convert to with 18 Calendars:
* - "gregory" : (default)
* - "buddhist", "chinese", "coptic", "dangi", "ethioaa", "ethiopic",
* "hebrew", "indian", "islamic", "islamic-umalqura", "islamic-tbla",
* "islamic-civil", "islamic-rgsa", "iso8601", "japanese", "persian", "roc".
*
* 'dateStyle' Same as used in the Intl.DateTimeFormat() constructor.
* If not stated, default output is in Gregorian ISO Format: YYYY:MM:DDTHH:mm:ss.sssZ
*
* 'locale' The BCP 47 language tag for formatting (default is 'en'). If the 'locale'
* is given then no date conversion happens and the Persian date is formatted
* based on the specified 'dateStyle' and 'locale'.
*
* Other options: As used in the Intl.DateTimeFormat() constructor.
*
* @returns : Return the date in the calendar and format of the specified 'options'
**********************************************************************/
//==========================================================
function persianToCalendars(year, month, day, op={}) {
const formatOut= gD=> "toCal"in op?(op.calendar=op.toCal,new Intl.DateTimeFormat(op.locale??"en",op).format(gD)):gD,
dFormat = new Intl.DateTimeFormat('en-u-ca-persian',{dateStyle:'short',timeZone:"UTC"});
let gD = new Date(Date.UTC(2000,month,day));
gD = new Date(gD.setUTCDate(gD.getUTCDate() + 226867));
const gY = gD.getUTCFullYear()-2000+year;
gD = new Date(((gY<0)?"-":"+")+("00000"+Math.abs(gY)).slice(-6)+"-"+("0"+(gD.getUTCMonth()+1)).slice(-2)+"-"+("0"+(gD.getUTCDate())).slice(-2));
let [pM,pD,pY] = [...dFormat.format(gD).split("/")], i=0;
gD = new Date(gD.setUTCDate(gD.getUTCDate() +
~~(year*365.25+month*30.44+day-(pY.split(" ")[0]*365.25+pM*30.44+pD*1))-2));
while (i < 4) {
[pM,pD,pY]=[...dFormat.format(gD).split("/")];
if (pD==day && pM==month && pY.split(" ")[0]==year) return formatOut(gD);
gD = new Date(gD.setUTCDate(gD.getUTCDate()+1));i++;
}
throw new Error('Invalid Persian Date!');
}
//==========================================================
//==========================================================
// Test Units
//==========================================================
console.log("-".repeat(55));
console.log("Convert the Persian Date '1400-12-19' to other calendars:");
console.log("input to function: persianToCalendars(1400,12,19, options)");
console.log("-".repeat(55));
console.log("Default (Gregory) ISO format : ",persianToCalendars(1400,12,19)); // convert to default gregorian date
console.log("Gregory 'full' format : ",persianToCalendars(1400,12,19,{toCal:"gregory",dateStyle:"full"}));
console.log("Islamic 'full' format : ",persianToCalendars(1400,12,19,{toCal:"islamic",dateStyle:"full"}));
console.log("Islamic-Umaalqura 'short'format: ",persianToCalendars(1400,12,19,{toCal:"islamic-umalqura"}));
console.log("Islamic-Umaalqura 'full' format: ",persianToCalendars(1400,12,19,{toCal:"islamic-umalqura",dateStyle:"full"}));
console.log("Islamic-civil 'full' format : ",persianToCalendars(1400,12,19,{toCal:"islamic-civil",dateStyle:"full"}));
console.log("Islamic-tbla 'full' format : ",persianToCalendars(1400,12,19,{toCal:"islamic-tbla",dateStyle:"full"}));
console.log("Islamic-rgsa 'full' format : ",persianToCalendars(1400,12,19,{toCal:"islamic-rgsa",dateStyle:"full"}));
console.log("Hebrew 'full' format : ",persianToCalendars(1400,12,19,{toCal:"hebrew",dateStyle:"full"}));
console.log("Indian 'full' format : ",persianToCalendars(1400,12,19,{toCal:"indian",dateStyle:"full"}));
console.log("Buddhist 'full' format : ",persianToCalendars(1400,12,19,{toCal:"buddhist",dateStyle:"full"}));
console.log("Chinese 'full' format : ",persianToCalendars(1400,12,19,{toCal:"chinese",dateStyle:"full"}));
console.log("Dangi (Korean) 'full' format : ",persianToCalendars(1400,12,19,{toCal:"dangi",dateStyle:"full"}));
console.log("R.O.C. (Minguo) 'full' format : ",persianToCalendars(1400,12,19,{toCal:"roc",dateStyle:"full"}));
console.log("Japanese 'full' format : ",persianToCalendars(1400,12,19,{toCal:"japanese",dateStyle:"full"}));
console.log("Coptic 'full' format : ",persianToCalendars(1400,12,19,{toCal:"coptic",dateStyle:"full"}));
console.log("Ethioaa 'full' format : ",persianToCalendars(1400,12,19,{toCal:"ethioaa",dateStyle:"full"}));
console.log("Ethiopic 'full' format : ",persianToCalendars(1400,12,19,{toCal:"ethiopic",dateStyle:"full"}));
console.log("-".repeat(55));
console.log("Format the input Persian Date without conversion:");
console.log("-".repeat(55));
console.log("Persian 'full' format : ",persianToCalendars(1400,12,19,{toCal:"persian",dateStyle:"full"}));
console.log("Persian 'medium' format : ",persianToCalendars(1400,12,19,{toCal:"persian",dateStyle:"medium"}));
console.log("Persian 'short' format : ",persianToCalendars(1400,12,19,{toCal:"persian",dateStyle:"short"}));
console.log("Persian 'ar' locale : ",persianToCalendars(1400,12,19,{toCal:"persian",dateStyle:"full", locale:"ar"}));
console.log("Persian 'fa' locale : ",persianToCalendars(1400,12,19,{toCal:"persian",dateStyle:"full", locale:"fa"}));
console.log("Persian 'hi' locale : ",persianToCalendars(1400,12,19,{toCal:"persian",dateStyle:"full", locale:"hi"}));
console.log("Persian 'ur' locale : ",persianToCalendars(1400,12,19,{toCal:"persian",dateStyle:"full", locale:"ur"}));
console.log("Persian 'ps-AF' locale : ",persianToCalendars(1400,12,19,{toCal:"persian",dateStyle:"full", locale:"ps-AF"}));
console.log("Persian 'id' locale : ",persianToCalendars(1400,12,19,{toCal:"persian",dateStyle:"full", locale:"id"}));
console.log("Persian 'pa' locale : ",persianToCalendars(1400,12,19,{toCal:"persian",dateStyle:"full", locale:"pa"}));
console.log("Persian 'ma' locale : ",persianToCalendars(1400,12,19,{toCal:"persian",dateStyle:"full", locale:"ma"}));
console.log("-".repeat(55));
console.log("Convert Max Negative and Max Positive Persian Dates to Gregorian");
console.log("-".repeat(55));
console.log(persianToCalendars(-272442,12,29)); // max negative Persian date
console.log(persianToCalendars(275139,6,23)); // max positive Persian date
console.log("-".repeat(55));