Click here to Skip to main content
15,884,628 members
Articles / Programming Languages / C#
Article

Jalali Calendar

Rate me:
Please Sign up or sign in to vote.
4.64/5 (16 votes)
17 Mar 200610 min read 118.2K   3.4K   45   13
This article explains a more accurate method than the algorithm that the .NET Framework's PersianCalendar uses, to deal with the Persian calendar. This method covers a wider range of dates, and also years before Common Era.

The demo project, see see how PersianCalendar fails over some hundred years.

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:

C#
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)  //zero point drops one day in first three blocks 
               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:

C#
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:

C#
// +1 to make sure the value is calculated
// for the given year not its previous year
int currentYearJD0 = jalali_jd0(year) + 1;
int nextYearJD0 = jalali_jd0(year + 1) + 1;
if(nextYearJD0 – currentYearJD0 == 366) {
    //current year is a leap year
} else {
    //it is a normal year
}

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:

C#
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:

  1. Convert Jalali date to its corresponding Julian day
  2. 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:

C#
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:

C#
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:

C#
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:

C#
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)); //false: is Julian

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United Arab Emirates United Arab Emirates
I love messing around with JavaScript, my discovery of the power of JavaScript was the biggest discovery since the time I found out I like astronomy. I spent most of my life shooting heavenly bodies, studying physics, organizing or just being a nice member of amateur astronomy groups and writing about astronomy.

I believe in fast and agile development styles, things just change for a small company before almost any design could be finalized. The programs that I create evolve. An evolved program works better and better by time, but finally nobody knows how!

Seriously, I’m a software architect with wild ideas. I enjoy working on large distributed systems, anything from remotely controlling a telescope to a network of games distributed all over the internet.

Here is the latter one, Hyzonia; I invested a good amount of time on designing and developing it. You might enjoy it if you want to spice up your website with some games or if you’re looking for a good reason to develop a casual game.

Here's my blog.

Comments and Discussions

 
GeneralMy vote of 4 Pin
Amir Mohammad Nasrollahi29-Jul-13 22:10
professionalAmir Mohammad Nasrollahi29-Jul-13 22:10 
QuestionA Mini Bug in PersianDate.cs Pin
Houman Masnavi29-Sep-11 14:45
Houman Masnavi29-Sep-11 14:45 
QuestionUsing the date converter in MS Access? Pin
Inam Mischa7-Jan-09 0:06
Inam Mischa7-Jan-09 0:06 
GeneralSolid state/Nuclear Pin
Ahmad Abrishami15-Jun-08 20:29
Ahmad Abrishami15-Jun-08 20:29 
GeneralAttempting to make PHP conversion Pin
MeNot13-Jun-08 0:44
MeNot13-Jun-08 0:44 
GeneralSalnameh Pin
Bahram.M11-Oct-06 4:08
Bahram.M11-Oct-06 4:08 
GeneralRe: Salnameh Pin
Homam Hosseini11-Oct-06 7:47
Homam Hosseini11-Oct-06 7:47 
GeneralRe: Salnameh Pin
Bahram.M13-Oct-06 6:35
Bahram.M13-Oct-06 6:35 
GeneralRe: Salnameh Pin
Homam Hosseini13-Oct-06 9:07
Homam Hosseini13-Oct-06 9:07 
It would be nice if you post the modified methods in this forum.

Homam
AnswerRe: Salnameh Pin
Bahram.M16-Oct-06 0:33
Bahram.M16-Oct-06 0:33 
GeneralRe: Salnameh Pin
Homam Hosseini16-Oct-06 1:16
Homam Hosseini16-Oct-06 1:16 
General[Message Deleted] Pin
Majid Shahabfar20-Mar-06 19:07
Majid Shahabfar20-Mar-06 19:07 
GeneralRe: nice Pin
Homam Hosseini22-Mar-06 0:26
Homam Hosseini22-Mar-06 0:26 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.