2 ******************************************************************************
3 * Copyright (C) 2003-2012, 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;
93 year
=(daysNo
/1029983)*2820;
94 daysNo
=daysNo%1029983
;
96 if((daysNo
/46751)<=21)
98 year
+=(daysNo
/46751)* 128;
103 year
+=(daysNo
/46751)* 128;
133 else if (daysNo
> 1095)
140 year
+=(4 * (daysNo
/1461));
151 daysNo
= daysNo
% 365;
160 for (i
= 0; i
< 11 && daysNo
> monthDays
[i
]; ++i
) {
161 daysNo
-= monthDays
[i
];
175 // Implementation of the PersianCalendar class
177 //-------------------------------------------------------------------------
179 //-------------------------------------------------------------------------
181 const char *PersianCalendar::getType() const {
185 Calendar
* PersianCalendar::clone() const {
186 return new PersianCalendar(*this);
189 PersianCalendar::PersianCalendar(const Locale
& aLocale
, UErrorCode
& success
)
190 : Calendar(TimeZone::createDefault(), aLocale
, success
)
192 setTimeInMillis(getNow(), success
); // Call this again now that the vtable is set up properly.
195 PersianCalendar::PersianCalendar(const PersianCalendar
& other
) : Calendar(other
) {
198 PersianCalendar::~PersianCalendar()
202 //-------------------------------------------------------------------------
203 // Minimum / Maximum access functions
204 //-------------------------------------------------------------------------
206 static const int32_t LIMITS
[UCAL_FIELD_COUNT
][4] = {
207 // Minimum Greatest Least Maximum
209 { 0, 0, 0, 0}, // ERA
210 { -5000000, -5000000, 5000000, 5000000}, // YEAR
211 { 0, 0, 11, 11}, // MONTH
212 { 1, 1, 52, 53}, // WEEK_OF_YEAR
213 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // WEEK_OF_MONTH
214 { 1, 1, 29, 31}, // DAY_OF_MONTH
215 { 1, 1, 365, 366}, // DAY_OF_YEAR
216 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DAY_OF_WEEK
217 { 1, 1, 5, 5}, // DAY_OF_WEEK_IN_MONTH
218 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // AM_PM
219 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR
220 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR_OF_DAY
221 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MINUTE
222 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // SECOND
223 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECOND
224 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // ZONE_OFFSET
225 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DST_OFFSET
226 { -5000000, -5000000, 5000000, 5000000}, // YEAR_WOY
227 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DOW_LOCAL
228 { -5000000, -5000000, 5000000, 5000000}, // EXTENDED_YEAR
229 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY
230 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECONDS_IN_DAY
231 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH
233 static const int32_t MONTH_COUNT
[12][4] = {
235 { 31, 31, 0, 0 }, // Farvardin
236 { 31, 31, 31, 31 }, // Ordibehesht
237 { 31, 31, 62, 62 }, // Khordad
238 { 31, 31, 93, 93 }, // Tir
239 { 31, 31, 124, 124 }, // Mordad
240 { 31, 31, 155, 155 }, // Shahrivar
241 { 30, 30, 186, 186 }, // Mehr
242 { 30, 30, 216, 216 }, // Aban
243 { 30, 30, 246, 246 }, // Azar
244 { 30, 30, 276, 276 }, // Dey
245 { 30, 30, 306, 306 }, // Bahman
246 { 29, 30, 336, 336 } // Esfand
247 // len length of month
248 // len2 length of month in a leap year
249 // st days in year before start of month
250 // st2 days in year before month in leap year
253 int32_t PersianCalendar::handleGetLimit(UCalendarDateFields field
, ELimitType limitType
) const {
254 return LIMITS
[field
][limitType
];
257 //-------------------------------------------------------------------------
258 // Assorted calculation utilities
262 * Determine whether a year is a leap year in the Persian calendar
264 UBool
PersianCalendar::isLeapYear(int32_t year
)
266 return jalali_to_julian(year
+1,1,1)-jalali_to_julian(year
,1,1) == 366;
270 * Return the day # on which the given year starts. Days are counted
271 * from the Hijri epoch, origin 0.
273 int32_t PersianCalendar::yearStart(int32_t year
) {
274 return handleComputeMonthStart(year
,1,FALSE
);
278 * Return the day # on which the given month starts. Days are counted
279 * from the Hijri epoch, origin 0.
281 * @param year The hijri shamsi year
282 * @param year The hijri shamsi month, 0-based
284 int32_t PersianCalendar::monthStart(int32_t year
, int32_t month
) const {
285 return handleComputeMonthStart(year
,month
,FALSE
);
288 //----------------------------------------------------------------------
289 // Calendar framework
290 //----------------------------------------------------------------------
293 * Return the length (in days) of the given month.
295 * @param year The hijri shamsi year
296 * @param year The hijri shamsi month, 0-based
298 int32_t PersianCalendar::handleGetMonthLength(int32_t extendedYear
, int32_t month
) const {
299 return MONTH_COUNT
[month
][PersianCalendar::isLeapYear(extendedYear
)?1:0];
303 * Return the number of days in the given Persian year
305 int32_t PersianCalendar::handleGetYearLength(int32_t extendedYear
) const {
306 return 365 + (PersianCalendar::isLeapYear(extendedYear
) ? 1 : 0);
309 //-------------------------------------------------------------------------
310 // Functions for converting from field values to milliseconds....
311 //-------------------------------------------------------------------------
313 // Return JD of start of given month/year
314 int32_t PersianCalendar::handleComputeMonthStart(int32_t eyear
, int32_t month
, UBool useMonth
) const {
315 // If the month is out of range, adjust it into range, and
316 // modify the extended year value accordingly.
317 if (month
< 0 || month
> 11) {
321 return jalali_to_julian(eyear
,(useMonth
?month
+1:1),1)-1+1947955;
324 //-------------------------------------------------------------------------
325 // Functions for converting from milliseconds to field values
326 //-------------------------------------------------------------------------
328 int32_t PersianCalendar::handleGetExtendedYear() {
330 if (newerField(UCAL_EXTENDED_YEAR
, UCAL_YEAR
) == UCAL_EXTENDED_YEAR
) {
331 year
= internalGet(UCAL_EXTENDED_YEAR
, 1); // Default to year 1
333 year
= internalGet(UCAL_YEAR
, 1); // Default to year 1
339 * Override Calendar to compute several fields specific to the Persian
340 * calendar system. These are:
347 * <li>EXTENDED_YEAR</ul>
349 * The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
350 * method is called. The getGregorianXxx() methods return Gregorian
351 * calendar equivalents for the given Julian day.
353 void PersianCalendar::handleComputeFields(int32_t julianDay
, UErrorCode
&/*status*/) {
355 julian_to_jalali(julianDay
-1947955,&jy
,&jm
,&jd
);
356 internalSet(UCAL_ERA
, 0);
357 internalSet(UCAL_YEAR
, jy
);
358 internalSet(UCAL_EXTENDED_YEAR
, jy
);
359 internalSet(UCAL_MONTH
, jm
-1);
360 internalSet(UCAL_DAY_OF_MONTH
, jd
);
361 internalSet(UCAL_DAY_OF_YEAR
, jd
+ MONTH_COUNT
[jm
-1][2]);
365 PersianCalendar::inDaylightTime(UErrorCode
& status
) const
367 // copied from GregorianCalendar
368 if (U_FAILURE(status
) || !getTimeZone().useDaylightTime())
371 // Force an update of the state of the Calendar.
372 ((PersianCalendar
*)this)->complete(status
); // cast away const
374 return (UBool
)(U_SUCCESS(status
) ? (internalGet(UCAL_DST_OFFSET
) != 0) : FALSE
);
378 const UDate
PersianCalendar::fgSystemDefaultCentury
= DBL_MIN
;
379 const int32_t PersianCalendar::fgSystemDefaultCenturyYear
= -1;
381 UDate
PersianCalendar::fgSystemDefaultCenturyStart
= DBL_MIN
;
382 int32_t PersianCalendar::fgSystemDefaultCenturyStartYear
= -1;
384 UBool
PersianCalendar::haveDefaultCentury() const
389 UDate
PersianCalendar::defaultCenturyStart() const
391 return internalGetDefaultCenturyStart();
394 int32_t PersianCalendar::defaultCenturyStartYear() const
396 return internalGetDefaultCenturyStartYear();
400 PersianCalendar::internalGetDefaultCenturyStart() const
402 // lazy-evaluate systemDefaultCenturyStart
404 UMTX_CHECK(NULL
, (fgSystemDefaultCenturyStart
== fgSystemDefaultCentury
), needsUpdate
);
407 initializeSystemDefaultCentury();
410 // use defaultCenturyStart unless it's the flag value;
411 // then use systemDefaultCenturyStart
413 return fgSystemDefaultCenturyStart
;
417 PersianCalendar::internalGetDefaultCenturyStartYear() const
419 // lazy-evaluate systemDefaultCenturyStartYear
421 UMTX_CHECK(NULL
, (fgSystemDefaultCenturyStart
== fgSystemDefaultCentury
), needsUpdate
);
424 initializeSystemDefaultCentury();
427 // use defaultCenturyStart unless it's the flag value;
428 // then use systemDefaultCenturyStartYear
430 return fgSystemDefaultCenturyStartYear
;
434 PersianCalendar::initializeSystemDefaultCentury()
436 // initialize systemDefaultCentury and systemDefaultCenturyYear based
437 // on the current time. They'll be set to 80 years before
439 UErrorCode status
= U_ZERO_ERROR
;
440 PersianCalendar
calendar(Locale("@calendar=persian"),status
);
441 if (U_SUCCESS(status
))
443 calendar
.setTime(Calendar::getNow(), status
);
444 calendar
.add(UCAL_YEAR
, -80, status
);
445 UDate newStart
= calendar
.getTime(status
);
446 int32_t newYear
= calendar
.get(UCAL_YEAR
, status
);
448 if (fgSystemDefaultCenturyStart
== fgSystemDefaultCentury
)
450 fgSystemDefaultCenturyStartYear
= newYear
;
451 fgSystemDefaultCenturyStart
= newStart
;
455 // We have no recourse upon failure unless we want to propagate the failure
459 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PersianCalendar
)