Introduction
Jalali (Persian) calendar is the official calendar in Iran and some neighbor territories. Although Jalali is a solar calendar with strict rules, it has always been a challenge for programmers to provide some means of conversions for it and the Gregorian calendar. If you search CodeProject for terms like “jalali”, “persian” or “shamsi”, you’ll find some good codes that try to present a method for converting dates in Gregorian to dates in Persian calendar and vice versa. The Microsoft .NET Framework 2 contains the PersianCalendar
class in the System.Globalization
namespace. It should have solved all the problems but the truth is that the Persian calendar is not a simple periodic one as the algorithm used in the PersianCalendar
class supposes.
The main problem is in leap years. Jalali calendar is based on the actual observation of the sun, other than established mathematical principals. The PersianCalendar
uses an algorithm sometimes called Khayam. It assumes that a given Jalali year is a leap year if the remainder of it divided by 33 be 1, 5, 9, 13, 17, 22, or 30. This simple pattern fails for 1634, just 250 years by now. In fact the algorithm is correct for the years 1178 to 1634 Jalali (1799 to 2256 Gregorian). Here I will describe another method that covers a much wider range.
The codes and the algorithm that would be described in this article are originally written by Bill J. Gray. He kindly allowed me to port his C codes to this .NET class.
Jalali Calendar in Details
The Jalali calendar is named after king Jalal-al-Din Malek-Shah Saljouqi. The Iranian mathematician and poet Omar Khayam has done much of the works to designate the rules of the calendar.
The new year of Jalali begins at the astronomical moment of the beginning of spring. Since not all programmers are astronomers, I will explain some astronomical terms in this article. Everybody knows that the sun moves east to west in the sky, because the earth is spinning. But if the sun was too dim that we could see other stars around it, we would have noticed another motion: the sun slowly moving from west to east across the sky. This motion is caused by the earth orbiting the sun, and it has a period of nearly 365.24 days. The fraction (0.24) is why we must have leap years in calendars; and because 0.24 is not exactly 0.25 (a quarter), the periods of leap years in the Jalali calendar are so complex. Anyway, a new year in Jalali calendar begins just exactly when the sun is located in a point in the sky we call Vernal Equinox. For simplicity, I call this moment Norooz (Norooz is the name of the new year celebrations in Iran).
Jalali calendar rules say that if Norooz happens before local midday, that day is the first day of the new year, else the following day is. Each Jalali year has 12 months. The first 6 months are all 31-days long, the remaining 5 months have 30 days, and the last month is also a 30-day month in leap years, or has 29 days otherwise.
This pattern is so interesting; at the first half of the year, the earth is farther from the sun, so it moves slower than the second half of the year when the months are 30-days long. This resembles Kepler’s third law.
How Does It Work
All we need to do is to find the instance of vernal equinox (Norooz). If we know this moment for a given year (and its following year), then we can make that year’s calendar. There is a term in astronomy called Julian day (it has nothing to do with the Julian calendar). A Julian day is a means to express dates in real numbers other than the common y-m-d format. It would be more useful for mathematical purposes if we express dates by numbers like 2453823.92452 instead of March 29, 2006 10:11:18 UT. The .NET framework supports TimeSpan
and Ticks
but a Julian day is widely used in astronomical calculations. There is another advantage, the concept of a Julian day provides us a means to deal with BCE dates (see the Points of interest section). A Julian day is the days passed from midday (GMT) of January 1, -4712 Gregorian. Theoretically, the dates in any calendar can be converted to Julian day and back (I am not sure about “any”, but at least for Persian calendar, this can be done).
Although the motion of the earth is not completely periodic, there are algorithms for finding the instance of vernal equinox (of course, they are only accurate for a limited time but thousands of years). If we have a table of Julian days of vernal equinoxes over thousands of years, then we can have the Jalali calendar in that range. There are some books published in Persian that provide this method for conversion. Bill J. Gray had a better way; he introduced an algorithm that matches the previous method for Persian years between -1096 and +2327 (Gregorian years -457 to +2948).
It starts by finding the Julian day number of Norooz for a given year:
private static int jalali_jd0(int jalali_year)
{
int rval;
if (jalali_year < LOWER_PERSIAN_YEAR)
throw new ArgumentOutOfRangeException("jalali_year",
"the value must be bigger than " +
LOWER_PERSIAN_YEAR.ToString());
for (int i = 0; i < 12; i++)
if (jalali_year < breaks[i])
{
rval = JALALI_ZERO + jalali_year * 365 +
(deltas[i] + jalali_year * 303) / 1250;
if (i < 3)
rval--;
return (rval);
}
throw new ArgumentOutOfRangeException("jalali_year",
"the value must be bigger than " +
LOWER_PERSIAN_YEAR.ToString() +
" and less than " +
UPPER_PERSIAN_YEAR.ToString());
}
It is quite straightforward, JALALI_ZERO
is the Julian day of the first day of the Jalali year zero (which is equal to 1947954). breaks
is an array of Jalali years while deltas
is an array of constant numbers for the years in breaks.
If the year is outside the LOWER_PERSIAN_YEAR
and UPPER_PERSIAN_YEAR
values (which are -1096 and +2327), then we use another calendar system called the Modern Persian Calendar. This is completely algorithmic (and much simpler), and while it does not match Jalali, it closely follows it. The method that returns the Julian date of the first day of the year in the Modern Persian calendar is called persian_modern_jd0()
and is available in the source code.
There is a method named day_to_dmy()
that converts any Julian day to its corresponding date in Persian (or Gregorian) calendar. It starts by guessing the approximate calendar year for the given Julian day:
year = (jd - JALALI_ZERO) / 365;
Then in a loop, it finds the exact year and calculates the Julian days of the first days of that year and its following year (using the jalali_jd0()
method), and determines if the current year is a leap year:
int currentYearJD0 = jalali_jd0(year) + 1;
int nextYearJD0 = jalali_jd0(year + 1) + 1;
if(nextYearJD0 – currentYearJD0 == 366) {
} else {
}
The same methods exist for the Gregorian calendar. We can convert any Gregorian date to its corresponding Julian day using a simple formula provided by Jean Meeus in Astronomical Algorithms:
double JulianDate(double y, double m, double d, double h)
{
double a,b;
h = h / 24; d = d + h;
if(m==1 || m==2)
{
m += 12; y-=1;
}
a = (int)(y / 100); b = 2 - a + (int)(a / 4);
return (int)(365.25 * y) + (int)(30.6001 * (m + 1)) + d + 1720994.5 + b;
}
There is a reverse method that converts Julian days back to Gregorian dates. The algorithm could be found in the book. I have kept Gray’s implementation in the source code.
And now we’ve done! We can conclude the method described above as:
- Convert Jalali date to its corresponding Julian day
- Convert the calculated Julian day to Gregorian date
And vice versa.
What If You Want a Jalali Calendar Out of This Range
The Jalali year range -1096 to 2327 fits all my historical needs. The Persian year of 2327 is equal to the Gregorian year 2949 and is the maximum year that the .NET Framework’s DateTime
supports. But it may happen for you that you want date conversations out of this range. The code provided in this article simply uses the Modern Persian Calendar when it gets a date out of this range. But it is possible to provide exact conversions for dates over thousands years, actually as long as the astronomical formulae that calculate the position of the sun in the sky permits, and also as long as the variable we call Delta-T is accurate enough. I will not go farther, just know that Delta-T varies by time and its value is not known for the future years.
Again, all we need to do is to populate a table of Julian days of spring equinoxes, but instead of using the simple jalali_jd0()
method, we need to find the moment by calculating the position of the sun in the sky. Meeus has provided some nice algorithms in his book. You can also take a look at the nice method Gray posted in his website. Dealing with Jalali calendar over a wide range of years is complex enough to be the subject of another article. If I get time, I’ll write it for CodeProject, otherwise you can find all the methods in Gray’s pages (see the Resources section).
Using The Code
To make it all work with the .NET Framework, I made the JalaliCalendar
class that inherits System.Globalization.Calendar
. I also included a structure type in the source code, named PersianDate
, which mimics the functionality of System.DateTime
. I had written the structure about a year ago to use with the PersianCalendar
class, and although the code is quite funny, it was a handy tool for me. I changed it a little to work with the Jalali calendar. Using the type is straightforward:
PersianDate pd1 = new PersianDate(DateTime.Today);
PersianDate pd2 = new PersianDate(1385, 1, 13);
The PersianDate
type provides many properties and methods such as: AddDays()
…, ToString()
, WeekOfYear
, DaysInMonth()
, IsLeapYear()
, GetMonthName()
, StaringDateOfWeek()
, and so on.
The following code demonstrates how to use JalaliCalendar
:
JalaliCalendar jcal = new JalaliCalendar();
DateTime dt = jcal.ToDateTime(1385, 1, 13, 18, 15, 20, 0);
Console.WriteLine("Gregorian date correspoding " +
"to 13/1/1385 18:15:20 == " + dt);
Console.WriteLine("The length of the last month in 1387 is == "
+ jcal.GetDaysInMonth(1387, 12));
Console.WriteLine("So 1387 is a leap year == " +
jcal.IsLeapYear(1387));
Prints:
Gregorian date correspoding
to 13/1/1385 18:15:20 == 4/2/2006 6:15:20 PM
The length of the last month in 1387 is == 30
So 1387 is a leap year == True
The Demo Project
I had originally written the program for my Pocket PC. Here I have slightly modified it to become a test program for Persian date conversation for .NET Framework’s PersianCalendar
and the JalaliCalendar
introduced here. Its source code demonstrates the usage of my PersianDate
structure type.
Points of Interest
The main purpose for using this JalaiCalendar
in place of the .NET Framework’s PersianCalendar
must be the need of date conversation for historical events. If you just want to display the current date in your website, PersianCalendar
is sufficient. But the .NET Framework has limitations for dates before the common era (dates with a negative year), System.DateTime
just supports dates after January 1, 1 AC. To overcome this problem, I made a structure type named XDateTime
that supports dates in both common and before common eras. This type uses Julian days at the heart of the algorithm instead of Ticks
. Using this method, XDateTime
can deal with any date after January 1, 4712 BC.
The type initializes by some overridden constructors, but all of them calls one of these two methods: one that constructs the type using a calendar date (year, month …) values, and one that makes the type using a Julian day value. The methods ask you to specify if the date you are working on is expressed (or should be expressed) in Gregorian or Julian calendar. Note that the Julian calendar does not relate to a Julian day at all. For common historical uses, you must consider that the days before October 15, 1582 are in Julian calendar. There’s another thing to be mentioned, there is no year zero in history! The year before year 1 is considered to be year -1. This is why when you call the XDateTime.ToString()
method, you’ll get something like: 4/18/53 BC, while XDateTime.Year
property returns -52. The algorithms used here take year zero into effect, thus XDateTime(-52,4,18)
is the constructor for 4/18/53 BC. Here are some examples:
XDateTime xdt = new XDateTime(-400, 5, 8, 2, 25, 30, false);
Console.WriteLine(xdt);
Console.WriteLine(xdt.DayOfWeek);
xdt = xdt.AddDays(3.5);
Console.WriteLine(xdt);
Console.WriteLine(xdt.DayOfWeek);
Prints:
5/8/401 BC 2:25:30
Wednesday
5/11/401 BC 14:25:30
Saturday
The last argument of the XDateTime
constructor is set to false
to indicate that the date is expressed in Julian calendar.
I have coded an XPersianDate
structure in the same manner. This type uses the same algorithm that JalaliCalendar
uses, to convert any Jalali date to its corresponding Julian day and Gregorian date. Here is a sample:
XDateTime xdt = new XDateTime(-400, 5, 8, 2, 25, 30, false);
Console.WriteLine(xdt);
XPersianDate xpd = new XPersianDate(xdt.JulianDay);
Console.WriteLine(xpd);
Console.WriteLine(xpd.ToXDateTime(false));
Prints:
5/8/401 BC 2:25:30
13/2/1022 BH 2:25:30
5/8/401 BC 2:25:30
I used the term “BH” to express “Before Hijrat”.
Conclusion
Here, an accurate date conversation method for Jalali and Gregorian calendars was explained. This method is useful for special purposes such as date conversation for historical events. I also provided two structure types to deal with dates in Before Common Era.
Resources
- Here is Bill J. Gray's algorithm[^]. I just ported his C code into C#.
- Jean Meeus’ Astronomical Algorithms[^]. The first edition of this book has been translated in Persian and published under the title of “فرمولهای ستارهشناسی برای محاسبها”.
- I believe this[^] is the origin of the .NET Framework’s
PersianCalendar
class. This is a nice project written by Omid K. Rad, I have used his idea and his routines in the JalaliCalendar
class.
- Here is another article titled The Persian Calendar for 3000 years[^] that explains a similar method to Gray’s algorithm.