2 *******************************************************************************
3 * Copyright (C) 1996-2012, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
8 package com.ibm.icu.util;
10 import java.util.Date;
11 import java.util.Locale;
13 import com.ibm.icu.util.ULocale.Category;
16 * <code>PersianCalendar</code> is a subclass of <code>Calendar</code> that
17 * that implements the Persian calendar. It is used as the main civil
18 * calendar in Iran and Afghanistan, and by Iranians and Afghans worldwide.
20 * The Persian calendar is solar, and is similar to the Gregorian calendar
21 * in various ways, except its leap year rule, which is determined
22 * astronomically. The Persian year starts around the March equinox.
24 * The modern Persian calendar (used in Iran since 1925 CE and in
25 * Afghanistan since 1957 CE), has the lengths of the months fixed. The
26 * first six months are 31 days each, the next five months are 30 days each,
27 * and the final month is 29 days in non-leap years and 30 days in leap
28 * ones. Historically, the lengths of the month differed in different
29 * years, but they were finally fixed at the times mentioned above. Partial
30 * information is available about the historical lengths.
32 * The official rule for determination of the beginning of the Persian year
33 * is locale dependent, but at the same time, it has not specified a locale.
34 * Iranians around the world traditionally follow the calendar authorities
35 * of Iran, which haven't officially specified the locale. Some
36 * calendarists use some point in Tehran as the locale, while others have
37 * tried the more neutral 52.5 degrees east meridian. It is not clear which
38 * locale should be used for the Persian calendar of Afghanistan, but it is
39 * expected that for about one year in every twenty-four years, the Afghan
40 * calendar may become different from the Iranian one.
42 * The exact locale to be used for the Iranian calendar starts to make a
43 * difference at around 2090 CE. The specific arithmetic method implemented
44 * here, commonly known as the 33-year cycle rule, matches the astronomical
45 * calendar at least for the whole period that the calendar has been both
46 * well-defined and official, from 1925 to around 2090 CE. The other
47 * commonly known algorithm, the 2820-year cycle, has been incorrectly
48 * designed to follow the tropical year instead of the spring equinoctial
49 * year, and fails to match the astronomical one as early as 2025 CE.
51 * This class should not be subclassed.</p>
53 * PersianCalendar usually should be instantiated using
54 * {@link com.ibm.icu.util.Calendar#getInstance(ULocale)} passing in a
55 * <code>ULocale</code> with the tag <code>"@calendar=persian"</code>.</p>
57 * @see com.ibm.icu.util.GregorianCalendar
58 * @see com.ibm.icu.util.Calendar
60 * @author Roozbeh Pournader
63 * @deprecated This API is ICU internal only.
65 public class PersianCalendar extends Calendar {
66 private static final long serialVersionUID = -6727306982975111643L;
68 //-------------------------------------------------------------------------
70 //-------------------------------------------------------------------------
72 private static final int[][] MONTH_COUNT = {
74 { 31, 31, 0 }, // Farvardin
75 { 31, 31, 31 }, // Ordibehesht
76 { 31, 31, 62 }, // Khordad
77 { 31, 31, 93 }, // Tir
78 { 31, 31, 124 }, // Mordad
79 { 31, 31, 155 }, // Shahrivar
80 { 30, 30, 186 }, // Mehr
81 { 30, 30, 216 }, // Aban
82 { 30, 30, 246 }, // Azar
83 { 30, 30, 276 }, // Dey
84 { 30, 30, 306 }, // Bahman
85 { 29, 30, 336 } // Esfand
86 // len length of month
87 // len2 length of month in a leap year
88 // st days in year before start of month
91 private static final int PERSIAN_EPOCH = 1948320;
93 //-------------------------------------------------------------------------
95 //-------------------------------------------------------------------------
98 * Constructs a default <code>PersianCalendar</code> using the current time
99 * in the default time zone with the default <code>FORMAT</code> locale.
100 * @see Category#FORMAT
103 * @deprecated This API is ICU internal only.
105 public PersianCalendar()
107 this(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT));
111 * Constructs a <code>PersianCalendar</code> based on the current time
112 * in the given time zone with the default <code>FORMAT</code> locale.
113 * @param zone the given time zone.
114 * @see Category#FORMAT
117 * @deprecated This API is ICU internal only.
119 public PersianCalendar(TimeZone zone)
121 this(zone, ULocale.getDefault(Category.FORMAT));
125 * Constructs a <code>PersianCalendar</code> based on the current time
126 * in the default time zone with the given locale.
128 * @param aLocale the given locale.
131 * @deprecated This API is ICU internal only.
133 public PersianCalendar(Locale aLocale)
135 this(TimeZone.getDefault(), aLocale);
139 * Constructs a <code>PersianCalendar</code> based on the current time
140 * in the default time zone with the given locale.
142 * @param locale the given ulocale.
145 * @deprecated This API is ICU internal only.
147 public PersianCalendar(ULocale locale)
149 this(TimeZone.getDefault(), locale);
153 * Constructs a <code>PersianCalendar</code> based on the current time
154 * in the given time zone with the given locale.
156 * @param zone the given time zone.
157 * @param aLocale the given locale.
160 * @deprecated This API is ICU internal only.
162 public PersianCalendar(TimeZone zone, Locale aLocale)
164 super(zone, aLocale);
165 setTimeInMillis(System.currentTimeMillis());
169 * Constructs a <code>PersianCalendar</code> based on the current time
170 * in the given time zone with the given locale.
172 * @param zone the given time zone.
173 * @param locale the given ulocale.
176 * @deprecated This API is ICU internal only.
178 public PersianCalendar(TimeZone zone, ULocale locale)
181 setTimeInMillis(System.currentTimeMillis());
185 * Constructs a <code>PersianCalendar</code> with the given date set
186 * in the default time zone with the default <code>FORMAT</code> locale.
188 * @param date The date to which the new calendar is set.
189 * @see Category#FORMAT
192 * @deprecated This API is ICU internal only.
194 public PersianCalendar(Date date) {
195 super(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT));
200 * Constructs a <code>PersianCalendar</code> with the given date set
201 * in the default time zone with the default <code>FORMAT</code> locale.
203 * @param year the value used to set the {@link #YEAR YEAR} time field in the calendar.
204 * @param month the value used to set the {@link #MONTH MONTH} time field in the calendar.
205 * Note that the month value is 0-based. e.g., 0 for Farvardin.
206 * @param date the value used to set the {@link #DATE DATE} time field in the calendar.
207 * @see Category#FORMAT
210 * @deprecated This API is ICU internal only.
212 public PersianCalendar(int year, int month, int date)
214 super(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT));
215 this.set(Calendar.YEAR, year);
216 this.set(Calendar.MONTH, month);
217 this.set(Calendar.DATE, date);
221 * Constructs a <code>PersianCalendar</code> with the given date
222 * and time set for the default time zone with the default <code>FORMAT</code> locale.
224 * @param year the value used to set the {@link #YEAR YEAR} time field in the calendar.
225 * @param month the value used to set the {@link #MONTH MONTH} time field in the calendar.
226 * Note that the month value is 0-based. e.g., 0 for Farvardin.
227 * @param date the value used to set the {@link #DATE DATE} time field in the calendar.
228 * @param hour the value used to set the {@link #HOUR_OF_DAY HOUR_OF_DAY} time field
230 * @param minute the value used to set the {@link #MINUTE MINUTE} time field
232 * @param second the value used to set the {@link #SECOND SECOND} time field
234 * @see Category#FORMAT
237 * @deprecated This API is ICU internal only.
239 public PersianCalendar(int year, int month, int date, int hour,
240 int minute, int second)
242 super(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT));
243 this.set(Calendar.YEAR, year);
244 this.set(Calendar.MONTH, month);
245 this.set(Calendar.DATE, date);
246 this.set(Calendar.HOUR_OF_DAY, hour);
247 this.set(Calendar.MINUTE, minute);
248 this.set(Calendar.SECOND, second);
251 //-------------------------------------------------------------------------
252 // Minimum / Maximum access functions
253 //-------------------------------------------------------------------------
255 private static final int LIMITS[][] = {
256 // Minimum Greatest Least Maximum
258 { 0, 0, 0, 0}, // ERA
259 { -5000000, -5000000, 5000000, 5000000}, // YEAR
260 { 0, 0, 11, 11}, // MONTH
261 { 1, 1, 52, 53}, // WEEK_OF_YEAR
262 {/* */}, // WEEK_OF_MONTH
263 { 1, 1, 29, 31}, // DAY_OF_MONTH
264 { 1, 1, 365, 366}, // DAY_OF_YEAR
265 {/* */}, // DAY_OF_WEEK
266 { -1, -1, 5, 5}, // DAY_OF_WEEK_IN_MONTH
269 {/* */}, // HOUR_OF_DAY
272 {/* */}, // MILLISECOND
273 {/* */}, // ZONE_OFFSET
274 {/* */}, // DST_OFFSET
275 { -5000000, -5000000, 5000000, 5000000}, // YEAR_WOY
276 {/* */}, // DOW_LOCAL
277 { -5000000, -5000000, 5000000, 5000000}, // EXTENDED_YEAR
278 {/* */}, // JULIAN_DAY
279 {/* */}, // MILLISECONDS_IN_DAY
284 * @deprecated This API is ICU internal only.
286 protected int handleGetLimit(int field, int limitType) {
287 return LIMITS[field][limitType];
290 //-------------------------------------------------------------------------
291 // Assorted calculation utilities
295 * Determine whether a year is a leap year in the Persian calendar
297 private final static boolean isLeapYear(int year)
299 int[] remainder = new int[1];
300 floorDivide(25 * year + 11, 33, remainder);
301 return remainder[0] < 8;
305 //----------------------------------------------------------------------
306 // Calendar framework
307 //----------------------------------------------------------------------
310 * Return the length (in days) of the given month.
312 * @param extendedYear The Persian year
313 * @param month The Persian month, 0-based
316 * @deprecated This API is ICU internal only.
318 protected int handleGetMonthLength(int extendedYear, int month) {
319 // If the month is out of range, adjust it into range, and
320 // modify the extended year value accordingly.
321 if (month < 0 || month > 11) {
322 int[] rem = new int[1];
323 extendedYear += floorDivide(month, 12, rem);
327 return MONTH_COUNT[month][isLeapYear(extendedYear)?1:0];
331 * Return the number of days in the given Persian year
334 * @deprecated This API is ICU internal only.
336 protected int handleGetYearLength(int extendedYear) {
337 return isLeapYear(extendedYear) ? 366 : 365;
340 //-------------------------------------------------------------------------
341 // Functions for converting from field values to milliseconds....
342 //-------------------------------------------------------------------------
345 * Return JD of start of given month/year
348 * @deprecated This API is ICU internal only.
350 protected int handleComputeMonthStart(int eyear, int month, boolean useMonth) {
351 // If the month is out of range, adjust it into range, and
352 // modify the extended year value accordingly.
353 if (month < 0 || month > 11) {
354 int[] rem = new int[1];
355 eyear += floorDivide(month, 12, rem);
359 int julianDay = PERSIAN_EPOCH - 1 + 365 * (eyear - 1) + floorDivide(8 * eyear + 21, 33);
361 julianDay += MONTH_COUNT[month][2];
366 //-------------------------------------------------------------------------
367 // Functions for converting from milliseconds to field values
368 //-------------------------------------------------------------------------
372 * @deprecated This API is ICU internal only.
374 protected int handleGetExtendedYear() {
376 if (newerField(EXTENDED_YEAR, YEAR) == EXTENDED_YEAR) {
377 year = internalGet(EXTENDED_YEAR, 1); // Default to year 1
379 year = internalGet(YEAR, 1); // Default to year 1
385 * Override Calendar to compute several fields specific to the Persian
386 * calendar system. These are:
393 * <li>EXTENDED_YEAR</ul>
395 * The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
399 * @deprecated This API is ICU internal only.
401 protected void handleComputeFields(int julianDay) {
402 int year, month, dayOfMonth, dayOfYear;
404 long daysSinceEpoch = julianDay - PERSIAN_EPOCH;
405 year = 1 + (int) floorDivide(33 * daysSinceEpoch + 3, 12053);
407 long farvardin1 = 365 * (year - 1) + floorDivide(8 * year + 21, 33);
408 dayOfYear = (int)(daysSinceEpoch - farvardin1); // 0-based
409 if (dayOfYear < 216) { // Compute 0-based month
410 month = dayOfYear / 31;
412 month = (dayOfYear - 6) / 30;
414 dayOfMonth = dayOfYear - MONTH_COUNT[month][2] + 1;
415 ++dayOfYear; // Make it 1-based now
418 internalSet(YEAR, year);
419 internalSet(EXTENDED_YEAR, year);
420 internalSet(MONTH, month);
421 internalSet(DAY_OF_MONTH, dayOfMonth);
422 internalSet(DAY_OF_YEAR, dayOfYear);
429 * @deprecated This API is ICU internal only.
431 public String getType() {