1ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho ******************************************************************************
359d709d503bab6e2b61931737e662dd293b40578ccornelius * Copyright (C) 2003-2013, International Business Machines Corporation
4ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * and others. All Rights Reserved.
5ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru ******************************************************************************
6ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
7ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * File PERSNCAL.CPP
8ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
9ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Modification History:
10ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
11ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *   Date        Name        Description
1254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius *   9/23/2003   mehran      posted to icu-design
1354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius *   10/1/2012   roozbeh     Fixed algorithm and heavily refactored and rewrote
1454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius *                           based on the implementation of Gregorian
15ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *****************************************************************************
16ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
1785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
18ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "persncal.h"
19ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
20ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#if !UCONFIG_NO_FORMATTING
21ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho#include "umutex.h"
2354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius#include "gregoimp.h" // Math
2485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho#include <float.h>
2585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
2654dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusstatic const int16_t kPersianNumDays[]
2754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius= {0,31,62,93,124,155,186,216,246,276,306,336}; // 0-based, for day-in-year
2854dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusstatic const int8_t kPersianMonthLength[]
2954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius= {31,31,31,31,31,31,30,30,30,30,30,29}; // 0-based
3054dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusstatic const int8_t kPersianLeapMonthLength[]
3154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius= {31,31,31,31,31,31,30,30,30,30,30,30}; // 0-based
32ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
3354dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusstatic const int32_t kPersianCalendarLimits[UCAL_FIELD_COUNT][4] = {
3454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    // Minimum  Greatest     Least   Maximum
3554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    //           Minimum   Maximum
3654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    {        0,        0,        0,        0}, // ERA
3754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    { -5000000, -5000000,  5000000,  5000000}, // YEAR
3854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    {        0,        0,       11,       11}, // MONTH
3954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    {        1,        1,       52,       53}, // WEEK_OF_YEAR
4054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // WEEK_OF_MONTH
4154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    {        1,       1,        29,       31}, // DAY_OF_MONTH
4254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    {        1,       1,       365,      366}, // DAY_OF_YEAR
4354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DAY_OF_WEEK
4454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    {        1,       1,         5,        5}, // DAY_OF_WEEK_IN_MONTH
4554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // AM_PM
4654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR
4754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR_OF_DAY
4854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MINUTE
4954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // SECOND
5054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECOND
5154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // ZONE_OFFSET
5254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DST_OFFSET
5354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    { -5000000, -5000000,  5000000,  5000000}, // YEAR_WOY
5454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DOW_LOCAL
5554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    { -5000000, -5000000,  5000000,  5000000}, // EXTENDED_YEAR
5654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY
5754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECONDS_IN_DAY
5854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH
5954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius};
60ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
61ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruU_NAMESPACE_BEGIN
62ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
6354dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusstatic const int32_t PERSIAN_EPOCH = 1948320;
6454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
65ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// Implementation of the PersianCalendar class
66ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
67ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//-------------------------------------------------------------------------
68ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// Constructors...
69ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//-------------------------------------------------------------------------
70ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
71ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruconst char *PersianCalendar::getType() const {
72ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return "persian";
73ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
74ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
75ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruCalendar* PersianCalendar::clone() const {
76ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return new PersianCalendar(*this);
77ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
78ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
79ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruPersianCalendar::PersianCalendar(const Locale& aLocale, UErrorCode& success)
80ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru  :   Calendar(TimeZone::createDefault(), aLocale, success)
81ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
82ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
83ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
84ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
85ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruPersianCalendar::PersianCalendar(const PersianCalendar& other) : Calendar(other) {
86ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
87ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
88ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruPersianCalendar::~PersianCalendar()
89ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
90ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
91ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
92ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//-------------------------------------------------------------------------
93ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// Minimum / Maximum access functions
94ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//-------------------------------------------------------------------------
95ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
96ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
97ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruint32_t PersianCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const {
9854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    return kPersianCalendarLimits[field][limitType];
99ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
100ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
101ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//-------------------------------------------------------------------------
102ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// Assorted calculation utilities
103ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//
104ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
105ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
106ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Determine whether a year is a leap year in the Persian calendar
107ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
108ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUBool PersianCalendar::isLeapYear(int32_t year)
109ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
11054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    int32_t remainder;
11154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    ClockMath::floorDivide(25 * year + 11, 33, remainder);
11254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    return (remainder < 8);
113ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
114ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
115ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
116ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Return the day # on which the given year starts.  Days are counted
11754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius * from the Persian epoch, origin 0.
118ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
119ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruint32_t PersianCalendar::yearStart(int32_t year) {
12054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    return handleComputeMonthStart(year,0,FALSE);
121ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
122ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
123ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
124ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Return the day # on which the given month starts.  Days are counted
12554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius * from the Persian epoch, origin 0.
126ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
12754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius * @param year  The Persian year
12854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius * @param year  The Persian month, 0-based
129ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
130ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruint32_t PersianCalendar::monthStart(int32_t year, int32_t month) const {
13154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    return handleComputeMonthStart(year,month,TRUE);
132ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
133ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
134ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//----------------------------------------------------------------------
135ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// Calendar framework
136ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//----------------------------------------------------------------------
137ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
138ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
139ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Return the length (in days) of the given month.
140ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
14154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius * @param year  The Persian year
14254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius * @param year  The Persian month, 0-based
143ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
144ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruint32_t PersianCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const {
14554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    // If the month is out of range, adjust it into range, and
14654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    // modify the extended year value accordingly.
14754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    if (month < 0 || month > 11) {
14854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        extendedYear += ClockMath::floorDivide(month, 12, month);
14954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    }
15054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
15154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    return isLeapYear(extendedYear) ? kPersianLeapMonthLength[month] : kPersianMonthLength[month];
152ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
153ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
154ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
155ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Return the number of days in the given Persian year
156ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
157ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruint32_t PersianCalendar::handleGetYearLength(int32_t extendedYear) const {
15854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    return isLeapYear(extendedYear) ? 366 : 365;
159ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
160ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
161ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//-------------------------------------------------------------------------
162ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// Functions for converting from field values to milliseconds....
163ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//-------------------------------------------------------------------------
164ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
165ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// Return JD of start of given month/year
16654dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusint32_t PersianCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, UBool /*useMonth*/) const {
167ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // If the month is out of range, adjust it into range, and
168ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // modify the extended year value accordingly.
169ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (month < 0 || month > 11) {
17054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        eyear += ClockMath::floorDivide(month, 12, month);
17154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    }
17254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
17354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    int32_t julianDay = PERSIAN_EPOCH - 1 + 365 * (eyear - 1) + ClockMath::floorDivide(8 * eyear + 21, 33);
17454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
17554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    if (month != 0) {
17654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        julianDay += kPersianNumDays[month];
177ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
17854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
17954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    return julianDay;
180ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
181ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
182ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//-------------------------------------------------------------------------
183ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// Functions for converting from milliseconds to field values
184ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//-------------------------------------------------------------------------
185ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
186ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruint32_t PersianCalendar::handleGetExtendedYear() {
187ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t year;
188ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
189ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        year = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
190ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else {
191ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        year = internalGet(UCAL_YEAR, 1); // Default to year 1
192ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
193ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return year;
194ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
195ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
196ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
197ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Override Calendar to compute several fields specific to the Persian
198ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * calendar system.  These are:
199ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
200ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * <ul><li>ERA
201ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * <li>YEAR
202ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * <li>MONTH
203ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * <li>DAY_OF_MONTH
204ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * <li>DAY_OF_YEAR
205ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * <li>EXTENDED_YEAR</ul>
206ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
207ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
20854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius * method is called.
209ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
210ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid PersianCalendar::handleComputeFields(int32_t julianDay, UErrorCode &/*status*/) {
21154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    int32_t year, month, dayOfMonth, dayOfYear;
21254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
21354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    int32_t daysSinceEpoch = julianDay - PERSIAN_EPOCH;
21454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    year = 1 + ClockMath::floorDivide(33 * daysSinceEpoch + 3, 12053);
21554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
21654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    int32_t farvardin1 = 365 * (year - 1) + ClockMath::floorDivide(8 * year + 21, 33);
21754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    dayOfYear = (daysSinceEpoch - farvardin1); // 0-based
21854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    if (dayOfYear < 216) { // Compute 0-based month
21954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        month = dayOfYear / 31;
22054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    } else {
22154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        month = (dayOfYear - 6) / 30;
22254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    }
22354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    dayOfMonth = dayOfYear - kPersianNumDays[month] + 1;
22454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    ++dayOfYear; // Make it 1-based now
22554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
226ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    internalSet(UCAL_ERA, 0);
22754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    internalSet(UCAL_YEAR, year);
22854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    internalSet(UCAL_EXTENDED_YEAR, year);
22954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    internalSet(UCAL_MONTH, month);
23054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
23154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
232ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
233ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
234ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUBool
235ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruPersianCalendar::inDaylightTime(UErrorCode& status) const
236ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
237ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // copied from GregorianCalendar
238ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status) || !getTimeZone().useDaylightTime())
239ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return FALSE;
240ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
241ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // Force an update of the state of the Calendar.
242ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    ((PersianCalendar*)this)->complete(status); // cast away const
243ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
244ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : FALSE);
245ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
246ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
24785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho// default century
24885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
24959d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic UDate           gSystemDefaultCenturyStart       = DBL_MIN;
25059d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic int32_t         gSystemDefaultCenturyStartYear   = -1;
25159d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic icu::UInitOnce  gSystemDefaultCenturyInit        = U_INITONCE_INITIALIZER;
25285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
253ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUBool PersianCalendar::haveDefaultCentury() const
254ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
25585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    return TRUE;
256ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
257ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
25859d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic void U_CALLCONV initializeSystemDefaultCentury() {
25985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    // initialize systemDefaultCentury and systemDefaultCenturyYear based
26085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    // on the current time.  They'll be set to 80 years before
26185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    // the current time.
26285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    UErrorCode status = U_ZERO_ERROR;
26385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    PersianCalendar calendar(Locale("@calendar=persian"),status);
26485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (U_SUCCESS(status))
26585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    {
26685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        calendar.setTime(Calendar::getNow(), status);
26785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        calendar.add(UCAL_YEAR, -80, status);
26859d709d503bab6e2b61931737e662dd293b40578ccornelius
26959d709d503bab6e2b61931737e662dd293b40578ccornelius        gSystemDefaultCenturyStart = calendar.getTime(status);
27059d709d503bab6e2b61931737e662dd293b40578ccornelius        gSystemDefaultCenturyStartYear = calendar.get(UCAL_YEAR, status);
27185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
27285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    // We have no recourse upon failure unless we want to propagate the failure
27385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    // out.
274ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
275ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
27659d709d503bab6e2b61931737e662dd293b40578ccorneliusUDate PersianCalendar::defaultCenturyStart() const {
27759d709d503bab6e2b61931737e662dd293b40578ccornelius    // lazy-evaluate systemDefaultCenturyStart
27859d709d503bab6e2b61931737e662dd293b40578ccornelius    umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
27959d709d503bab6e2b61931737e662dd293b40578ccornelius    return gSystemDefaultCenturyStart;
28059d709d503bab6e2b61931737e662dd293b40578ccornelius}
28159d709d503bab6e2b61931737e662dd293b40578ccornelius
28259d709d503bab6e2b61931737e662dd293b40578ccorneliusint32_t PersianCalendar::defaultCenturyStartYear() const {
28359d709d503bab6e2b61931737e662dd293b40578ccornelius    // lazy-evaluate systemDefaultCenturyStartYear
28459d709d503bab6e2b61931737e662dd293b40578ccornelius    umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
28559d709d503bab6e2b61931737e662dd293b40578ccornelius    return gSystemDefaultCenturyStartYear;
28659d709d503bab6e2b61931737e662dd293b40578ccornelius}
28759d709d503bab6e2b61931737e662dd293b40578ccornelius
288ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUOBJECT_DEFINE_RTTI_IMPLEMENTATION(PersianCalendar)
289ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
290ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruU_NAMESPACE_END
291ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
292ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#endif
293ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
294