Converting Gregorian to PersianDate: Methods & CodeConverting Gregorian dates to the Persian (Solar Hijri) calendar is a common need for applications serving Persian-speaking users or dealing with Iranian, Afghan, or regional date formats. This article explains the background of the Persian calendar, outlines several conversion methods (algorithmic, library-based, and server-side), and provides practical code examples in JavaScript, Python, and C#. You’ll also find advice on timezone handling, leap-year rules, and testing tips.
Background: What is the Persian (Solar Hijri) calendar?
The Persian calendar, also called the Solar Hijri calendar, is the official calendar in Iran and Afghanistan. It’s a solar calendar based on precise astronomical observations of the vernal equinox. Key facts:
- Year zero is the Hijra (622 CE) but Persian years are solar and align differently with Gregorian years.
- Months are: Farvardin (1) through Esfand (12). The first six months have 31 days, next five have 30 days, and Esfand has 29 days (30 in leap years).
- Leap years follow a complex 33-year cycle approximated by arithmetic rules in programming implementations. In practice, astronomical calculations give the most accurate results.
Methods for conversion
Three main approaches:
-
Algorithmic conversion (calendar arithmetic):
- Use well-known algorithms (e.g., the Iranian civil calendar algorithm) that map Gregorian dates to Julian Day Number (JDN) then to Persian date.
- Pros: No external dependencies; fast.
- Cons: Implementation details are tricky; leap rules approximated.
-
Library-based conversion:
- Use established date libraries that include Persian calendar support (e.g., moment-jalaali, persian-date, Khayyam in Python, or .NET libraries).
- Pros: Tested, maintained, easy to use.
- Cons: Dependency management; library updates.
-
Server-side / astronomical conversion:
- Use astronomical calculations to determine the true vernal equinox for higher accuracy (rarely necessary for most apps).
- Pros: Highest accuracy.
- Cons: Complex; requires astronomical data.
Algorithmic conversion: method overview
A commonly used approach:
- Convert Gregorian date to Julian Day Number (JDN).
- Convert JDN to Persian year/month/day using Iranian civil calendar arithmetic.
Key steps (high-level):
- Compute the number of days since the Persian epoch (Farvardin 1 of year 1).
- Determine the Persian year by dividing by 365 or 366 accounting for leap days.
- Compute month and day from remaining days.
Many implementations use the algorithm by Roozbeh Pournader and Mohammad Toossi or the one in “Calendrical Calculations” by Reingold & Dershowitz.
JavaScript examples
- Simple, widely used algorithm (no dependencies)
// Gregorian to Persian (algorithmic) — adapted from common implementations function gregorianToJdn(gy, gm, gd) { const a = Math.floor((14 - gm) / 12); const y = gy + 4800 - a; const m = gm + 12 * a - 3; return gd + Math.floor((153 * m + 2) / 5) + 365 * y + Math.floor(y / 4) - Math.floor(y / 100) + Math.floor(y / 400) - 32045; } function jdnToPersian(jdn) { const depoch = jdn - persianEpochJdn; const cycle = Math.floor(depoch / 1029983); let cyear = depoch % 1029983; let ycycle; if (cyear === 1029982) { ycycle = 2820; } else { const aux1 = Math.floor(cyear / 366); const aux2 = cyear % 366; ycycle = Math.floor((2134 * aux1 + 2816 * aux2 + 2815) / 1028522) + aux1 + 1; } const year = ycycle + 2820 * cycle + 474; const persianYear = year <= 0 ? year - 1 : year; const yday = jdn - persianToJdn(persianYear, 1, 1) + 1; let month = yday <= 186 ? Math.ceil(yday / 31) : Math.ceil((yday - 186) / 30) + 6; let day = jdn - persianToJdn(persianYear, month, 1) + 1; return { year: persianYear, month, day }; } function persianToJdn(py, pm, pd) { const epbase = py - (py >= 0 ? 474 : 473); const epyear = 474 + (epbase % 2820); return pd + (pm <= 7 ? (pm - 1) * 31 : ((pm - 1) * 30 + 6)) + Math.floor((epyear * 682 - 110) / 2816) + (epyear - 1) * 365 + Math.floor(epbase / 2820) * 1029983 + (persianEpochJdn - 1); } const persianEpochJdn = 1948320.5 | 0; // JDN for 622-03-19 (approx) — use integer JDN // Usage: function gregorianToPersian(gy, gm, gd) { const jdn = gregorianToJdn(gy, gm, gd); return jdnToPersian(jdn); } console.log(gregorianToPersian(2025, 8, 30)); // example
Note: The epoch constant and some integer handling may need adjustment; use tested libraries in production.
- Library approach (node)
npm install persian-date
const persianDate = require('persian-date'); const pd = new persianDate([2025, 8, 30]).toCalendar('gregorian'); // example usage patterns vary console.log(pd.format());
Check library docs for exact APIs.
Python examples
- Using algorithmic conversion (based on civil calendar formulas)
def gregorian_to_jdn(gy, gm, gd): a = (14 - gm) // 12 y = gy + 4800 - a m = gm + 12 * a - 3 return gd + (153 * m + 2) // 5 + 365 * y + y // 4 - y // 100 + y // 400 - 32045 # Implement persian conversion functions similar to JS version above # For brevity, use the 'khayyam' or 'convertdate' library in production: # pip install convertdate import convertdate persian = convertdate.jalali.from_gregorian(2025, 8, 30) print(persian) # (year, month, day)
- Library approach
pip install convertdate
from convertdate import jalali print(jalali.from_gregorian(2025, 8, 30)) # (1404, 6, 8) example
C# (.NET) examples
- Using System.Globalization (no built-in Persian conversion to Solar Hijri prior to .NET improvements) — use third-party library:
- Use NodaTime or PersianCalendar class in System.Globalization for UmAlQura? Actually .NET has PersianCalendar in System.Globalization that implements the Persian calendar.
using System; using System.Globalization; var pc = new PersianCalendar(); var gDate = new DateTime(2025, 8, 30); int py = pc.GetYear(gDate); int pm = pc.GetMonth(gDate); int pd = pc.GetDayOfMonth(gDate); Console.WriteLine($"{py}/{pm:D2}/{pd:D2}");
Note: PersianCalendar in .NET uses an arithmetic approximation; validate against requirements.
Timezone & daylight considerations
- Convert dates in UTC or the user’s local timezone consistently before converting calendars.
- Calendar conversion is date-based; clock/time rarely affects date except at midnight boundaries and when converting instants across timezones.
Leap years and edge cases
- Persian leap years follow a 33-year-ish pattern in arithmetic algorithms but actual astronomical leap years may differ slightly.
- Test conversions around:
- Persian year beginnings (Farvardin 1 — Nowruz).
- Gregorian Feb ⁄29 crossings.
- Years near epoch boundaries (e.g., years far in the past/future).
Testing checklist
- Round-trip test: Gregorian -> Persian -> Gregorian should return original date.
- Compare library outputs (convertdate, persian-date, .NET PersianCalendar) for a sample set.
- Test known historical dates (e.g., Persian new year 1400 = 2021-03-21).
When to prefer each method
- Use libraries for most apps: fewer bugs, maintained.
- Use algorithmic code if you must avoid dependencies or need embedded systems.
- Use astronomical methods only if legal/astronomical precision for Nowruz is required.
Conclusion
Converting Gregorian to PersianDate can be done accurately with well-known algorithms or by using established libraries across languages. For most applications use a tested library; for embedded or dependency-free contexts implement the algorithm carefully and validate extensively.
Leave a Reply