/src/icu/icu4c/source/i18n/indiancal.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // © 2016 and later: Unicode, Inc. and others. |
2 | | // License & terms of use: http://www.unicode.org/copyright.html |
3 | | /* |
4 | | * Copyright (C) 2003-2014, International Business Machines Corporation |
5 | | * and others. All Rights Reserved. |
6 | | ****************************************************************************** |
7 | | * |
8 | | * File INDIANCAL.CPP |
9 | | ***************************************************************************** |
10 | | */ |
11 | | |
12 | | #include "indiancal.h" |
13 | | #include <stdlib.h> |
14 | | #if !UCONFIG_NO_FORMATTING |
15 | | |
16 | | #include "mutex.h" |
17 | | #include <float.h> |
18 | | #include "gregoimp.h" // Math |
19 | | #include "uhash.h" |
20 | | |
21 | | // Debugging |
22 | | #ifdef U_DEBUG_INDIANCAL |
23 | | #include <stdio.h> |
24 | | #include <stdarg.h> |
25 | | |
26 | | #endif |
27 | | |
28 | | U_NAMESPACE_BEGIN |
29 | | |
30 | | // Implementation of the IndianCalendar class |
31 | | |
32 | | //------------------------------------------------------------------------- |
33 | | // Constructors... |
34 | | //------------------------------------------------------------------------- |
35 | | |
36 | | |
37 | 3.00k | IndianCalendar* IndianCalendar::clone() const { |
38 | 3.00k | return new IndianCalendar(*this); |
39 | 3.00k | } |
40 | | |
41 | | IndianCalendar::IndianCalendar(const Locale& aLocale, UErrorCode& success) |
42 | 155 | : Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success) |
43 | 155 | { |
44 | 155 | } |
45 | | |
46 | 3.00k | IndianCalendar::IndianCalendar(const IndianCalendar& other) : Calendar(other) { |
47 | 3.00k | } |
48 | | |
49 | | IndianCalendar::~IndianCalendar() |
50 | 3.10k | { |
51 | 3.10k | } |
52 | 0 | const char *IndianCalendar::getType() const { |
53 | 0 | return "indian"; |
54 | 0 | } |
55 | | |
56 | | static const int32_t LIMITS[UCAL_FIELD_COUNT][4] = { |
57 | | // Minimum Greatest Least Maximum |
58 | | // Minimum Maximum |
59 | | { 0, 0, 0, 0}, // ERA |
60 | | { -5000000, -5000000, 5000000, 5000000}, // YEAR |
61 | | { 0, 0, 11, 11}, // MONTH |
62 | | { 1, 1, 52, 53}, // WEEK_OF_YEAR |
63 | | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // WEEK_OF_MONTH |
64 | | { 1, 1, 30, 31}, // DAY_OF_MONTH |
65 | | { 1, 1, 365, 366}, // DAY_OF_YEAR |
66 | | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DAY_OF_WEEK |
67 | | { -1, -1, 5, 5}, // DAY_OF_WEEK_IN_MONTH |
68 | | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // AM_PM |
69 | | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR |
70 | | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR_OF_DAY |
71 | | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MINUTE |
72 | | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // SECOND |
73 | | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECOND |
74 | | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // ZONE_OFFSET |
75 | | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DST_OFFSET |
76 | | { -5000000, -5000000, 5000000, 5000000}, // YEAR_WOY |
77 | | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DOW_LOCAL |
78 | | { -5000000, -5000000, 5000000, 5000000}, // EXTENDED_YEAR |
79 | | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY |
80 | | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECONDS_IN_DAY |
81 | | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH |
82 | | { 0, 0, 11, 11}, // ORDINAL_MONTH |
83 | | }; |
84 | | |
85 | | static const int32_t INDIAN_ERA_START = 78; |
86 | | static const int32_t INDIAN_YEAR_START = 80; |
87 | | |
88 | 10.3k | int32_t IndianCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const { |
89 | 10.3k | return LIMITS[field][limitType]; |
90 | 10.3k | } |
91 | | |
92 | | /* |
93 | | * Determine whether the given gregorian year is a Leap year |
94 | | */ |
95 | | static UBool isGregorianLeap(int32_t year) |
96 | 35.0k | { |
97 | 35.0k | return Grego::isLeapYear(year); |
98 | 35.0k | } |
99 | | |
100 | | //---------------------------------------------------------------------- |
101 | | // Calendar framework |
102 | | //---------------------------------------------------------------------- |
103 | | |
104 | | /* |
105 | | * Return the length (in days) of the given month. |
106 | | * |
107 | | * @param eyear The year in Saka Era |
108 | | * @param month The month(0-based) in Indian calendar |
109 | | */ |
110 | 2.79k | int32_t IndianCalendar::handleGetMonthLength(int32_t eyear, int32_t month, UErrorCode& /* status */) const { |
111 | 2.79k | if (month < 0 || month > 11) { |
112 | 55 | eyear += ClockMath::floorDivide(month, 12, &month); |
113 | 55 | } |
114 | | |
115 | 2.79k | if (isGregorianLeap(eyear + INDIAN_ERA_START) && month == 0) { |
116 | 236 | return 31; |
117 | 236 | } |
118 | | |
119 | 2.56k | if (month >= 1 && month <= 5) { |
120 | 708 | return 31; |
121 | 708 | } |
122 | | |
123 | 1.85k | return 30; |
124 | 2.56k | } |
125 | | |
126 | | /* |
127 | | * Return the number of days in the given Indian year |
128 | | * |
129 | | * @param eyear The year in Saka Era. |
130 | | */ |
131 | 12.9k | int32_t IndianCalendar::handleGetYearLength(int32_t eyear, UErrorCode& status) const { |
132 | 12.9k | if (U_FAILURE(status)) return 0; |
133 | 12.9k | return isGregorianLeap(eyear + INDIAN_ERA_START) ? 366 : 365; |
134 | 12.9k | } |
135 | | /* |
136 | | * Returns the Julian Day corresponding to gregorian date |
137 | | * |
138 | | * @param year The Gregorian year |
139 | | * @param month The month in Gregorian Year, 0 based. |
140 | | * @param date The date in Gregorian day in month |
141 | | */ |
142 | 19.2k | static double gregorianToJD(int32_t year, int32_t month, int32_t date) { |
143 | 19.2k | return Grego::fieldsToDay(year, month, date) + kEpochStartAsJulianDay - 0.5; |
144 | 19.2k | } |
145 | | |
146 | | |
147 | | //------------------------------------------------------------------------- |
148 | | // Functions for converting from field values to milliseconds.... |
149 | | //------------------------------------------------------------------------- |
150 | 6.21k | static double IndianToJD(int32_t year, int32_t month, int32_t date) { |
151 | 6.21k | int32_t leapMonth, gyear, m; |
152 | 6.21k | double start, jd; |
153 | | |
154 | 6.21k | gyear = year + INDIAN_ERA_START; |
155 | | |
156 | | |
157 | 6.21k | if(isGregorianLeap(gyear)) { |
158 | 1.87k | leapMonth = 31; |
159 | 1.87k | start = gregorianToJD(gyear, 2 /* The third month in 0 based month */, 21); |
160 | 1.87k | } |
161 | 4.33k | else { |
162 | 4.33k | leapMonth = 30; |
163 | 4.33k | start = gregorianToJD(gyear, 2 /* The third month in 0 based month */, 22); |
164 | 4.33k | } |
165 | | |
166 | 6.21k | if (month == 1) { |
167 | 2.85k | jd = start + (date - 1); |
168 | 3.35k | } else { |
169 | 3.35k | jd = start + leapMonth; |
170 | 3.35k | m = month - 2; |
171 | | |
172 | | //m = Math.min(m, 5); |
173 | 3.35k | if (m > 5) { |
174 | 1.59k | m = 5; |
175 | 1.59k | } |
176 | | |
177 | 3.35k | jd += m * 31; |
178 | | |
179 | 3.35k | if (month >= 8) { |
180 | 1.59k | m = month - 7; |
181 | 1.59k | jd += m * 30; |
182 | 1.59k | } |
183 | 3.35k | jd += date - 1; |
184 | 3.35k | } |
185 | | |
186 | 6.21k | return jd; |
187 | 6.21k | } |
188 | | |
189 | | /* |
190 | | * Return JD of start of given month/year of Indian Calendar |
191 | | * @param eyear The year in Indian Calendar measured from Saka Era (78 AD). |
192 | | * @param month The month in Indian calendar |
193 | | */ |
194 | 6.22k | int64_t IndianCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, UBool /* useMonth */, UErrorCode& status) const { |
195 | 6.22k | if (U_FAILURE(status)) { |
196 | 0 | return 0; |
197 | 0 | } |
198 | | |
199 | | //month is 0 based; converting it to 1-based |
200 | 6.22k | int32_t imonth; |
201 | | |
202 | | // If the month is out of range, adjust it into range, and adjust the extended year accordingly |
203 | 6.22k | if (month < 0 || month > 11) { |
204 | 2.07k | if (uprv_add32_overflow(eyear, ClockMath::floorDivide(month, 12, &month), &eyear)) { |
205 | 10 | status = U_ILLEGAL_ARGUMENT_ERROR; |
206 | 10 | return 0; |
207 | 10 | } |
208 | 2.07k | } |
209 | | |
210 | 6.21k | if(month == 12){ |
211 | 0 | imonth = 1; |
212 | 6.21k | } else { |
213 | 6.21k | imonth = month + 1; |
214 | 6.21k | } |
215 | | |
216 | 6.21k | int64_t jd = IndianToJD(eyear ,imonth, 1); |
217 | | |
218 | 6.21k | return jd; |
219 | 6.22k | } |
220 | | |
221 | | //------------------------------------------------------------------------- |
222 | | // Functions for converting from milliseconds to field values |
223 | | //------------------------------------------------------------------------- |
224 | | |
225 | 5.84k | int32_t IndianCalendar::handleGetExtendedYear(UErrorCode& status) { |
226 | 5.84k | if (U_FAILURE(status)) { |
227 | 0 | return 0; |
228 | 0 | } |
229 | 5.84k | int32_t year; |
230 | | |
231 | 5.84k | if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) { |
232 | 4.77k | year = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1 |
233 | 4.77k | } else { |
234 | 1.07k | year = internalGet(UCAL_YEAR, 1); // Default to year 1 |
235 | 1.07k | } |
236 | | |
237 | 5.84k | return year; |
238 | 5.84k | } |
239 | | |
240 | | /* |
241 | | * Override Calendar to compute several fields specific to the Indian |
242 | | * calendar system. These are: |
243 | | * |
244 | | * <ul><li>ERA |
245 | | * <li>YEAR |
246 | | * <li>MONTH |
247 | | * <li>DAY_OF_MONTH |
248 | | * <li>EXTENDED_YEAR</ul> |
249 | | * |
250 | | * The DAY_OF_WEEK and DOW_LOCAL fields are already set when this |
251 | | * method is called. The getGregorianXxx() methods return Gregorian |
252 | | * calendar equivalents for the given Julian day. |
253 | | */ |
254 | 13.0k | void IndianCalendar::handleComputeFields(int32_t julianDay, UErrorCode& /* status */) { |
255 | 13.0k | double jdAtStartOfGregYear; |
256 | 13.0k | int32_t leapMonth, IndianYear, yday, IndianMonth, IndianDayOfMonth, mday; |
257 | | // Stores gregorian date corresponding to Julian day; |
258 | 13.0k | int32_t gregorianYear = getGregorianYear(); |
259 | | |
260 | 13.0k | IndianYear = gregorianYear - INDIAN_ERA_START; // Year in Saka era |
261 | 13.0k | jdAtStartOfGregYear = gregorianToJD(gregorianYear, 0, 1); // JD at start of Gregorian year |
262 | 13.0k | yday = static_cast<int32_t>(julianDay - jdAtStartOfGregYear); // Day number in Gregorian year (starting from 0) |
263 | | |
264 | 13.0k | if (yday < INDIAN_YEAR_START) { |
265 | | // Day is at the end of the preceding Saka year |
266 | 1.71k | IndianYear -= 1; |
267 | 1.71k | leapMonth = isGregorianLeap(gregorianYear - 1) ? 31 : 30; // Days in leapMonth this year, previous Gregorian year |
268 | 1.71k | yday += leapMonth + (31 * 5) + (30 * 3) + 10; |
269 | 11.3k | } else { |
270 | 11.3k | leapMonth = isGregorianLeap(gregorianYear) ? 31 : 30; // Days in leapMonth this year |
271 | 11.3k | yday -= INDIAN_YEAR_START; |
272 | 11.3k | } |
273 | | |
274 | 13.0k | if (yday < leapMonth) { |
275 | 6.24k | IndianMonth = 0; |
276 | 6.24k | IndianDayOfMonth = yday + 1; |
277 | 6.79k | } else { |
278 | 6.79k | mday = yday - leapMonth; |
279 | 6.79k | if (mday < (31 * 5)) { |
280 | 2.62k | IndianMonth = static_cast<int32_t>(uprv_floor(mday / 31)) + 1; |
281 | 2.62k | IndianDayOfMonth = (mday % 31) + 1; |
282 | 4.17k | } else { |
283 | 4.17k | mday -= 31 * 5; |
284 | 4.17k | IndianMonth = static_cast<int32_t>(uprv_floor(mday / 30)) + 6; |
285 | 4.17k | IndianDayOfMonth = (mday % 30) + 1; |
286 | 4.17k | } |
287 | 6.79k | } |
288 | | |
289 | 13.0k | internalSet(UCAL_ERA, 0); |
290 | 13.0k | internalSet(UCAL_EXTENDED_YEAR, IndianYear); |
291 | 13.0k | internalSet(UCAL_YEAR, IndianYear); |
292 | 13.0k | internalSet(UCAL_MONTH, IndianMonth); |
293 | 13.0k | internalSet(UCAL_ORDINAL_MONTH, IndianMonth); |
294 | 13.0k | internalSet(UCAL_DAY_OF_MONTH, IndianDayOfMonth); |
295 | 13.0k | internalSet(UCAL_DAY_OF_YEAR, yday + 1); // yday is 0-based |
296 | 13.0k | } |
297 | | |
298 | | IMPL_SYSTEM_DEFAULT_CENTURY(IndianCalendar, "@calendar=indian") |
299 | | |
300 | | UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IndianCalendar) |
301 | | |
302 | 0 | int32_t IndianCalendar::getRelatedYearDifference() const { |
303 | 0 | constexpr int32_t kIndianCalendarRelatedYearDifference = 79; |
304 | 0 | return kIndianCalendarRelatedYearDifference; |
305 | 0 | } |
306 | | |
307 | | U_NAMESPACE_END |
308 | | |
309 | | #endif |
310 | | |