/*********************************************************************
* @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));