The formal calendar in general use in Iran is the Solar Hijri Calendar, also called the Jalali Calendar. We call it here the Persian calendar. The Persian calendar uses a complex algorithm for calculating the leap years. The algorithm is illustrated in class PersianCalendarHelper1
, which is there just for illustrative purposes and is not used by other class (class PersianCalendarHelper
is used instead). But briefly, I can say that there are 683 leap years (366-day years) in each grand cycle of 2820 years, and the rest of the years are normal, 365-day years. The legal definition of leap years is astronomical in nature: whenever the vernal equinox is before 12:00:00 hours by the Tehran true time, that day is Nowruz (Farvardin 1st), otherwise that day is Esfand 30th, and the year is a leap year.
I have used a well-known arithmetic algorithm for calculating the leap years, which is practically equivalent to the astronomical definition for several hundreds of years. By all chances, I will also release an astronomical version in the future.
The algorithms have been rewritten and some bugs in the Java code have been corrected, but, originally, they have been based on the "Calendar Math Add-In for Excel" by Kees Couprie, whose contribution is gratefully acknowledged.
Even though I have tested this software, there may be some errors and bugs I have not noticed. If you find an error, I would be grateful if you drop me an e-mail and let me know the error.
PersianCalendar
This class is a subclass of com.ibm.icu.util.Calendar
. It is, therefore, based on the calendar framework of ICU4J. ICU4J is copyrighted by International Business Machines Corporation (IBM). Please see the ICU4J license.
This class is a full implementation and, as far as I have tested, its calendar calculations, including add and roll functions, work fine. This class uses com.ibm.icu.text.DateFormat
and com.ibm.icu.text.DateFormatSymbols
subclasses to support month and era names for the Persian calendar. A java.util.ResourceBundle
is used for i18n of these names.
I have presented quite a few demo and test classes, but here I will present simple code snippets to show you how to use this class. The following example shows how to format a date for a given locale. For complete disambiguation, I present fully qualified names of classes:
// Create a calendar with the default timezone and locale com.ibm.icu.util.Calendar cal = new com.ghasemkiani.util.icu.PersianCalendar(); // Set its time to Bahman 22, 1357 cal.set(com.ibm.icu.util.Calendar.ERA, com.ghasemkiani.util.icu.PersianCalendar.AH); cal.set(com.ibm.icu.util.Calendar.YEAR, 1357); cal.set(com.ibm.icu.util.Calendar.MONTH, com.ghasemkiani.util.icu.PersianCalendar.BAHMAN); cal.set(com.ibm.icu.util.Calendar.DAY_OF_MONTH, 22); com.ibm.icu.text.DateFormat df = cal.getDateTimeFormat( com.ibm.icu.text.DateFormat.FULL, -1, new com.ibm.icu.util.ULocale("fa", "IR", "")); String result = df.format(cal.getTime());
Now, the result
variable will contain something like this:
یکشنبه، ۲۲ بهمن ۱۳۵۷
Consider using another locale:
// ... com.ibm.icu.text.DateFormat df = cal.getDateTimeFormat( com.ibm.icu.text.DateFormat.FULL, -1, new com.ibm.icu.util.ULocale("tr", "", "")); String result = df.format(cal.getTime());
The result looks like this:
22 Behmen 1357 Pazar
For Afghanistan, I have used another version of month names. Consider using this locale:
// ... com.ibm.icu.text.DateFormat df = cal.getDateTimeFormat( com.ibm.icu.text.DateFormat.FULL, -1, new com.ibm.icu.util.ULocale("fa", "AF", "")); String result = df.format(cal.getTime());
The result is:
یکشنبه، ۲۲ دلو ۱۳۵۷
It should be noted that there is a difference between the solar calendar of Afghanistan and Iran. The calculation of leap years is different. I have not used the Afghani version of the calendar, and I don't know if this is a good idea to use the zodiacal month names in the Iranian calendar for the Afghanistan locale. Any help on this will be appreciated. Besides, the ideal solution will be to implement the Afghani version of the calendar (I don't think this is a difficult task, as far as I know).
This class can be used in conjunction with other calendar types to convert dates between calendars:
com.ibm.icu.util.Calendar cal = new com.ghasemkiani.util.icu.PersianCalendar(); com.ibm.icu.util.Calendar gcal = new com.ibm.icu.util.GregorianCalendar(); cal.set(com.ibm.icu.util.Calendar.ERA, com.ghasemkiani.util.icu.PersianCalendar.AH); cal.set(com.ibm.icu.util.Calendar.YEAR, 1357); cal.set(com.ibm.icu.util.Calendar.MONTH, com.ghasemkiani.util.icu.PersianCalendar.BAHMAN); cal.set(com.ibm.icu.util.Calendar.DAY_OF_MONTH, 22); int julianDay = cal.get(com.ibm.icu.util.Calendar.JULIAN_DAY); gcal.set(com.ibm.icu.util.Calendar.JULIAN_DAY, julianDay); com.ibm.icu.text.DateFormat df = gcal.getDateTimeFormat( com.ibm.icu.text.DateFormat.FULL, -1, new com.ibm.icu.util.ULocale("en", "US", "")); String result = df.format(cal.getTime());
And this is the result:
Sunday, February 11, 1979
The following code shows another way to get a PersianDateFormat
(note that we pass cal
as an argument):
com.ibm.icu.util.Calendar cal = new com.ghasemkiani.util.icu.PersianCalendar(); cal.set(com.ibm.icu.util.Calendar.ERA, com.ghasemkiani.util.icu.PersianCalendar.AH); cal.set(com.ibm.icu.util.Calendar.YEAR, 1357); cal.set(com.ibm.icu.util.Calendar.MONTH, com.ghasemkiani.util.icu.PersianCalendar.BAHMAN); cal.set(com.ibm.icu.util.Calendar.DAY_OF_MONTH, 22); com.ibm.icu.text.DateFormat df = com.ibm.icu.text.DateFormat.getDateInstance( cal, com.ibm.icu.text.DateFormat.FULL, new com.ibm.icu.util.ULocale("ru", "", "")); String result = df.format(cal.getTime());
And this is the result (the locale-specific data may be improved in the future if I receive any feedback):
22 Бахман 1357 г.
Of course, we can directly construct an instance of PersianDateFormat
, which is by default initialized to a PersianCalendar
:
com.ibm.icu.text.DateFormat df = new com.ghasemkiani.util.icu.PersianDateFormat( "EEEE d MMMM y G h:mm:ss a zzzz", new com.ibm.icu.util.ULocale("fa", "IR", "")); String result = df.format(new java.util.Date());
And this is the result (for the time I am doing this, of course):
یکشنبه ۹ اسفند ۱۳۸۳ ه.ش. ۱۲:۰۱:۰۱ ب.ظ. وقت استاندارد تهران
Due to the great work the developers of ICU4J have done, there are much more things that can be done, but I think this is enough to show the usage of the PersianCalendar
class. You can also check the demos.
SimplePersianCalendar
The class SimplePersianCalendar
is a subclass of java.util.GregorianCalendar
, with the added functionality that it can set/get date in the Persian calendar system. This class is kept here for backward compatibility. Now, it has a common base of functionality with the PersianCalendar
class. A new read/write property (julianDay
) has been added to this class.
One thing is worth of mentioning about this class: Year 0 has no meaning with this class. Year 1 A.H. is year 1 and year 1 B.H. is year -1. Months are zero-based and days are 1-based.
This class uses the DateFields
class to set/get the Persian date. As for calendar calculations, they can be done just like any other instance of the java.util.GregorianCalendar
class, i.e., they are not performed on Persian date fields.
Using SimplePersianCalendar
is straightforward. For example, to convert the current date into Persian date, we can write:
com.ghasemkiani.util.SimplePersianCalendar c = new com.ghasemkiani.util.SimplePersianCalendar(); com.ghasemkiani.util.DateFields t = c.getDateFields(); System.out.println( "Current date in the Persian calendar is: " + t.getYear() + "/" + (t.getMonth() + 1) + "/" + t.getDay() + ".");
See the demo app for more details.
I am using the following software environment:
Any prior versions may have problems with this software.
This software was written by Ghasem Kiani, M.D. I am a pediatrician and I do programming (mainly in Java) on a freelance basis.
ghasemkiani@yahoo.com
ghasemkiani.blogspot.com
I am grateful to: