2 ******************************************************************************
3 * Copyright (C) 2003-2008, International Business Machines Corporation
4 * and others. All Rights Reserved.
5 ******************************************************************************
9 * Modification History:
11 * Date Name Description
12 * 9/23/2003 mehran posted to icu-design
13 *****************************************************************************
18 #if !UCONFIG_NO_FORMATTING
23 static const int8_t monthDays
[] = { 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29 };
26 jalali_to_julian(int year
, int month
, int day
)
31 year
= year
-475+2820;
34 daysNo
=(year
/2820)*1029983;
37 daysNo
+=(year
/128)* 46751;
59 daysNo
+=(year
/33)* 12053;
74 daysNo
+= 1461 * (year
/4);
78 for (i
= 0; i
< month
; i
++) {
79 daysNo
+= monthDays
[i
];
87 static void julian_to_jalali (int32_t daysNo
, int *h_y
, int *h_m
, int *h_d
)
89 int year
=0, month
=0, day
=0,scalarDays
=0;
94 year
=(daysNo
/1029983)*2820;
95 daysNo
=daysNo%1029983
;
97 if((daysNo
/46751)<=21)
99 year
+=(daysNo
/46751)* 128;
104 year
+=(daysNo
/46751)* 128;
134 else if (daysNo
> 1095)
141 year
+=(4 * (daysNo
/1461));
152 daysNo
= daysNo
% 365;
161 for (i
= 0; i
< 11 && daysNo
> monthDays
[i
]; ++i
) {
162 daysNo
-= monthDays
[i
];
176 // Implementation of the PersianCalendar class
178 //-------------------------------------------------------------------------
180 //-------------------------------------------------------------------------
182 const char *PersianCalendar::getType() const {
186 Calendar
* PersianCalendar::clone() const {
187 return new PersianCalendar(*this);
190 PersianCalendar::PersianCalendar(const Locale
& aLocale
, UErrorCode
& success
)
191 : Calendar(TimeZone::createDefault(), aLocale
, success
)
193 setTimeInMillis(getNow(), success
); // Call this again now that the vtable is set up properly.
196 PersianCalendar::PersianCalendar(const PersianCalendar
& other
) : Calendar(other
) {
199 PersianCalendar::~PersianCalendar()
203 //-------------------------------------------------------------------------
204 // Minimum / Maximum access functions
205 //-------------------------------------------------------------------------
207 static const int32_t LIMITS
[UCAL_FIELD_COUNT
][4] = {
208 // Minimum Greatest Least Maximum
210 { 0, 0, 0, 0}, // ERA
211 { -5000000, -5000000, 5000000, 5000000}, // YEAR
212 { 0, 0, 11, 11}, // MONTH
213 { 1, 1, 52, 53}, // WEEK_OF_YEAR
214 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // WEEK_OF_MONTH
215 { 1, 1, 29, 31}, // DAY_OF_MONTH
216 { 1, 1, 365, 366}, // DAY_OF_YEAR
217 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DAY_OF_WEEK
218 { 1, 1, 5, 5}, // DAY_OF_WEEK_IN_MONTH
219 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // AM_PM
220 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR
221 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR_OF_DAY
222 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MINUTE
223 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // SECOND
224 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECOND
225 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // ZONE_OFFSET
226 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DST_OFFSET
227 { -5000000, -5000000, 5000000, 5000000}, // YEAR_WOY
228 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DOW_LOCAL
229 { -5000000, -5000000, 5000000, 5000000}, // EXTENDED_YEAR
230 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY
231 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECONDS_IN_DAY
232 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH
234 static const int32_t MONTH_COUNT
[12][4] = {
236 { 31, 31, 0, 0 }, // Farvardin
237 { 31, 31, 31, 31 }, // Ordibehesht
238 { 31, 31, 62, 62 }, // Khordad
239 { 31, 31, 93, 93 }, // Tir
240 { 31, 31, 124, 124 }, // Mordad
241 { 31, 31, 155, 155 }, // Shahrivar
242 { 30, 30, 186, 186 }, // Mehr
243 { 30, 30, 216, 216 }, // Aban
244 { 30, 30, 246, 246 }, // Azar
245 { 30, 30, 276, 276 }, // Dey
246 { 30, 30, 306, 306 }, // Bahman
247 { 29, 30, 336, 336 } // Esfand
248 // len length of month
249 // len2 length of month in a leap year
250 // st days in year before start of month
251 // st2 days in year before month in leap year
254 int32_t PersianCalendar::handleGetLimit(UCalendarDateFields field
, ELimitType limitType
) const {
255 return LIMITS
[field
][limitType
];
258 //-------------------------------------------------------------------------
259 // Assorted calculation utilities
263 * Determine whether a year is a leap year in the Persian calendar
265 UBool
PersianCalendar::isLeapYear(int32_t year
)
267 return jalali_to_julian(year
+1,1,1)-jalali_to_julian(year
,1,1) == 366;
271 * Return the day # on which the given year starts. Days are counted
272 * from the Hijri epoch, origin 0.
274 int32_t PersianCalendar::yearStart(int32_t year
) {
275 return handleComputeMonthStart(year
,1,FALSE
);
279 * Return the day # on which the given month starts. Days are counted
280 * from the Hijri epoch, origin 0.
282 * @param year The hijri shamsi year
283 * @param year The hijri shamsi month, 0-based
285 int32_t PersianCalendar::monthStart(int32_t year
, int32_t month
) const {
286 return handleComputeMonthStart(year
,month
,FALSE
);
289 //----------------------------------------------------------------------
290 // Calendar framework
291 //----------------------------------------------------------------------
294 * Return the length (in days) of the given month.
296 * @param year The hijri shamsi year
297 * @param year The hijri shamsi month, 0-based
299 int32_t PersianCalendar::handleGetMonthLength(int32_t extendedYear
, int32_t month
) const {
300 return MONTH_COUNT
[month
][PersianCalendar::isLeapYear(extendedYear
)?1:0];
304 * Return the number of days in the given Persian year
306 int32_t PersianCalendar::handleGetYearLength(int32_t extendedYear
) const {
307 return 365 + (PersianCalendar::isLeapYear(extendedYear
) ? 1 : 0);
310 //-------------------------------------------------------------------------
311 // Functions for converting from field values to milliseconds....
312 //-------------------------------------------------------------------------
314 // Return JD of start of given month/year
315 int32_t PersianCalendar::handleComputeMonthStart(int32_t eyear
, int32_t month
, UBool useMonth
) const {
316 // If the month is out of range, adjust it into range, and
317 // modify the extended year value accordingly.
318 if (month
< 0 || month
> 11) {
322 return jalali_to_julian(eyear
,(useMonth
?month
+1:1),1)-1+1947955;
325 //-------------------------------------------------------------------------
326 // Functions for converting from milliseconds to field values
327 //-------------------------------------------------------------------------
329 int32_t PersianCalendar::handleGetExtendedYear() {
331 if (newerField(UCAL_EXTENDED_YEAR
, UCAL_YEAR
) == UCAL_EXTENDED_YEAR
) {
332 year
= internalGet(UCAL_EXTENDED_YEAR
, 1); // Default to year 1
334 year
= internalGet(UCAL_YEAR
, 1); // Default to year 1
340 * Override Calendar to compute several fields specific to the Persian
341 * calendar system. These are:
348 * <li>EXTENDED_YEAR</ul>
350 * The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
351 * method is called. The getGregorianXxx() methods return Gregorian
352 * calendar equivalents for the given Julian day.
354 void PersianCalendar::handleComputeFields(int32_t julianDay
, UErrorCode
&/*status*/) {
356 julian_to_jalali(julianDay
-1947955,&jy
,&jm
,&jd
);
357 internalSet(UCAL_ERA
, 0);
358 internalSet(UCAL_YEAR
, jy
);
359 internalSet(UCAL_EXTENDED_YEAR
, jy
);
360 internalSet(UCAL_MONTH
, jm
-1);
361 internalSet(UCAL_DAY_OF_MONTH
, jd
);
362 internalSet(UCAL_DAY_OF_YEAR
, jd
+ MONTH_COUNT
[jm
-1][2]);
366 PersianCalendar::inDaylightTime(UErrorCode
& status
) const
368 // copied from GregorianCalendar
369 if (U_FAILURE(status
) || !getTimeZone().useDaylightTime())
372 // Force an update of the state of the Calendar.
373 ((PersianCalendar
*)this)->complete(status
); // cast away const
375 return (UBool
)(U_SUCCESS(status
) ? (internalGet(UCAL_DST_OFFSET
) != 0) : FALSE
);
379 const UDate
PersianCalendar::fgSystemDefaultCentury
= DBL_MIN
;
380 const int32_t PersianCalendar::fgSystemDefaultCenturyYear
= -1;
382 UDate
PersianCalendar::fgSystemDefaultCenturyStart
= DBL_MIN
;
383 int32_t PersianCalendar::fgSystemDefaultCenturyStartYear
= -1;
385 UBool
PersianCalendar::haveDefaultCentury() const
390 UDate
PersianCalendar::defaultCenturyStart() const
392 return internalGetDefaultCenturyStart();
395 int32_t PersianCalendar::defaultCenturyStartYear() const
397 return internalGetDefaultCenturyStartYear();
401 PersianCalendar::internalGetDefaultCenturyStart() const
403 // lazy-evaluate systemDefaultCenturyStart
405 UMTX_CHECK(NULL
, (fgSystemDefaultCenturyStart
== fgSystemDefaultCentury
), needsUpdate
);
408 initializeSystemDefaultCentury();
411 // use defaultCenturyStart unless it's the flag value;
412 // then use systemDefaultCenturyStart
414 return fgSystemDefaultCenturyStart
;
418 PersianCalendar::internalGetDefaultCenturyStartYear() const
420 // lazy-evaluate systemDefaultCenturyStartYear
422 UMTX_CHECK(NULL
, (fgSystemDefaultCenturyStart
== fgSystemDefaultCentury
), needsUpdate
);
425 initializeSystemDefaultCentury();
428 // use defaultCenturyStart unless it's the flag value;
429 // then use systemDefaultCenturyStartYear
431 return fgSystemDefaultCenturyStartYear
;
435 PersianCalendar::initializeSystemDefaultCentury()
437 // initialize systemDefaultCentury and systemDefaultCenturyYear based
438 // on the current time. They'll be set to 80 years before
440 UErrorCode status
= U_ZERO_ERROR
;
441 PersianCalendar
calendar(Locale("@calendar=persian"),status
);
442 if (U_SUCCESS(status
))
444 calendar
.setTime(Calendar::getNow(), status
);
445 calendar
.add(UCAL_YEAR
, -80, status
);
446 UDate newStart
= calendar
.getTime(status
);
447 int32_t newYear
= calendar
.get(UCAL_YEAR
, status
);
449 if (fgSystemDefaultCenturyStart
== fgSystemDefaultCentury
)
451 fgSystemDefaultCenturyStartYear
= newYear
;
452 fgSystemDefaultCenturyStart
= newStart
;
456 // We have no recourse upon failure unless we want to propagate the failure
460 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PersianCalendar
)