|
1 /* |
|
2 ********************************************************************** |
|
3 * Copyright (c) 2003-2008, International Business Machines |
|
4 * Corporation and others. All Rights Reserved. |
|
5 ********************************************************************** |
|
6 * Author: Alan Liu |
|
7 * Created: September 2 2003 |
|
8 * Since: ICU 2.8 |
|
9 ********************************************************************** |
|
10 */ |
|
11 |
|
12 #ifndef GREGOIMP_H |
|
13 #define GREGOIMP_H |
|
14 #include "unicode/utypes.h" |
|
15 #if !UCONFIG_NO_FORMATTING |
|
16 |
|
17 #include "unicode/ures.h" |
|
18 #include "unicode/locid.h" |
|
19 #include "putilimp.h" |
|
20 |
|
21 U_NAMESPACE_BEGIN |
|
22 |
|
23 /** |
|
24 * A utility class providing mathematical functions used by time zone |
|
25 * and calendar code. Do not instantiate. Formerly just named 'Math'. |
|
26 * @internal |
|
27 */ |
|
28 class ClockMath { |
|
29 public: |
|
30 /** |
|
31 * Divide two integers, returning the floor of the quotient. |
|
32 * Unlike the built-in division, this is mathematically |
|
33 * well-behaved. E.g., <code>-1/4</code> => 0 but |
|
34 * <code>floorDivide(-1,4)</code> => -1. |
|
35 * @param numerator the numerator |
|
36 * @param denominator a divisor which must be != 0 |
|
37 * @return the floor of the quotient |
|
38 */ |
|
39 static int32_t floorDivide(int32_t numerator, int32_t denominator); |
|
40 |
|
41 /** |
|
42 * Divide two numbers, returning the floor of the quotient. |
|
43 * Unlike the built-in division, this is mathematically |
|
44 * well-behaved. E.g., <code>-1/4</code> => 0 but |
|
45 * <code>floorDivide(-1,4)</code> => -1. |
|
46 * @param numerator the numerator |
|
47 * @param denominator a divisor which must be != 0 |
|
48 * @return the floor of the quotient |
|
49 */ |
|
50 static inline double floorDivide(double numerator, double denominator); |
|
51 |
|
52 /** |
|
53 * Divide two numbers, returning the floor of the quotient and |
|
54 * the modulus remainder. Unlike the built-in division, this is |
|
55 * mathematically well-behaved. E.g., <code>-1/4</code> => 0 and |
|
56 * <code>-1%4</code> => -1, but <code>floorDivide(-1,4)</code> => |
|
57 * -1 with <code>remainder</code> => 3. NOTE: If numerator is |
|
58 * too large, the returned quotient may overflow. |
|
59 * @param numerator the numerator |
|
60 * @param denominator a divisor which must be != 0 |
|
61 * @param remainder output parameter to receive the |
|
62 * remainder. Unlike <code>numerator % denominator</code>, this |
|
63 * will always be non-negative, in the half-open range <code>[0, |
|
64 * |denominator|)</code>. |
|
65 * @return the floor of the quotient |
|
66 */ |
|
67 static int32_t floorDivide(double numerator, int32_t denominator, |
|
68 int32_t& remainder); |
|
69 |
|
70 /** |
|
71 * For a positive divisor, return the quotient and remainder |
|
72 * such that dividend = quotient*divisor + remainder and |
|
73 * 0 <= remainder < divisor. |
|
74 * |
|
75 * Works around edge-case bugs. Handles pathological input |
|
76 * (divident >> divisor) reasonably. |
|
77 * |
|
78 * Calling with a divisor <= 0 is disallowed. |
|
79 */ |
|
80 static double floorDivide(double dividend, double divisor, |
|
81 double& remainder); |
|
82 }; |
|
83 |
|
84 // Useful millisecond constants |
|
85 #define kOneDay (1.0 * U_MILLIS_PER_DAY) // 86,400,000 |
|
86 #define kOneHour (60*60*1000) |
|
87 #define kOneMinute 60000 |
|
88 #define kOneSecond 1000 |
|
89 #define kOneMillisecond 1 |
|
90 #define kOneWeek (7.0 * kOneDay) // 604,800,000 |
|
91 |
|
92 // Epoch constants |
|
93 #define kJan1_1JulianDay 1721426 // January 1, year 1 (Gregorian) |
|
94 |
|
95 #define kEpochStartAsJulianDay 2440588 // January 1, 1970 (Gregorian) |
|
96 |
|
97 #define kEpochYear 1970 |
|
98 |
|
99 |
|
100 #define kEarliestViableMillis -185331720384000000.0 // minimum representable by julian day -1e17 |
|
101 |
|
102 #define kLatestViableMillis 185753453990400000.0 // max representable by julian day +1e17 |
|
103 |
|
104 /** |
|
105 * The minimum supported Julian day. This value is equivalent to |
|
106 * MIN_MILLIS. |
|
107 */ |
|
108 #define MIN_JULIAN (-0x7F000000) |
|
109 |
|
110 /** |
|
111 * The minimum supported epoch milliseconds. This value is equivalent |
|
112 * to MIN_JULIAN. |
|
113 */ |
|
114 #define MIN_MILLIS ((MIN_JULIAN - kEpochStartAsJulianDay) * kOneDay) |
|
115 |
|
116 /** |
|
117 * The maximum supported Julian day. This value is equivalent to |
|
118 * MAX_MILLIS. |
|
119 */ |
|
120 #define MAX_JULIAN (+0x7F000000) |
|
121 |
|
122 /** |
|
123 * The maximum supported epoch milliseconds. This value is equivalent |
|
124 * to MAX_JULIAN. |
|
125 */ |
|
126 #define MAX_MILLIS ((MAX_JULIAN - kEpochStartAsJulianDay) * kOneDay) |
|
127 |
|
128 /** |
|
129 * A utility class providing proleptic Gregorian calendar functions |
|
130 * used by time zone and calendar code. Do not instantiate. |
|
131 * |
|
132 * Note: Unlike GregorianCalendar, all computations performed by this |
|
133 * class occur in the pure proleptic GregorianCalendar. |
|
134 */ |
|
135 class Grego { |
|
136 public: |
|
137 /** |
|
138 * Return TRUE if the given year is a leap year. |
|
139 * @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc. |
|
140 * @return TRUE if the year is a leap year |
|
141 */ |
|
142 static inline UBool isLeapYear(int32_t year); |
|
143 |
|
144 /** |
|
145 * Return the number of days in the given month. |
|
146 * @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc. |
|
147 * @param month 0-based month, with 0==Jan |
|
148 * @return the number of days in the given month |
|
149 */ |
|
150 static inline int8_t monthLength(int32_t year, int32_t month); |
|
151 |
|
152 /** |
|
153 * Return the length of a previous month of the Gregorian calendar. |
|
154 * @param y the extended year |
|
155 * @param m the 0-based month number |
|
156 * @return the number of days in the month previous to the given month |
|
157 */ |
|
158 static inline int8_t previousMonthLength(int y, int m); |
|
159 |
|
160 /** |
|
161 * Convert a year, month, and day-of-month, given in the proleptic |
|
162 * Gregorian calendar, to 1970 epoch days. |
|
163 * @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc. |
|
164 * @param month 0-based month, with 0==Jan |
|
165 * @param dom 1-based day of month |
|
166 * @return the day number, with day 0 == Jan 1 1970 |
|
167 */ |
|
168 static double fieldsToDay(int32_t year, int32_t month, int32_t dom); |
|
169 |
|
170 /** |
|
171 * Convert a 1970-epoch day number to proleptic Gregorian year, |
|
172 * month, day-of-month, and day-of-week. |
|
173 * @param day 1970-epoch day (integral value) |
|
174 * @param year output parameter to receive year |
|
175 * @param month output parameter to receive month (0-based, 0==Jan) |
|
176 * @param dom output parameter to receive day-of-month (1-based) |
|
177 * @param dow output parameter to receive day-of-week (1-based, 1==Sun) |
|
178 * @param doy output parameter to receive day-of-year (1-based) |
|
179 */ |
|
180 static void dayToFields(double day, int32_t& year, int32_t& month, |
|
181 int32_t& dom, int32_t& dow, int32_t& doy); |
|
182 |
|
183 /** |
|
184 * Convert a 1970-epoch day number to proleptic Gregorian year, |
|
185 * month, day-of-month, and day-of-week. |
|
186 * @param day 1970-epoch day (integral value) |
|
187 * @param year output parameter to receive year |
|
188 * @param month output parameter to receive month (0-based, 0==Jan) |
|
189 * @param dom output parameter to receive day-of-month (1-based) |
|
190 * @param dow output parameter to receive day-of-week (1-based, 1==Sun) |
|
191 */ |
|
192 static inline void dayToFields(double day, int32_t& year, int32_t& month, |
|
193 int32_t& dom, int32_t& dow); |
|
194 |
|
195 /** |
|
196 * Convert a 1970-epoch milliseconds to proleptic Gregorian year, |
|
197 * month, day-of-month, and day-of-week, day of year and millis-in-day. |
|
198 * @param time 1970-epoch milliseconds |
|
199 * @param year output parameter to receive year |
|
200 * @param month output parameter to receive month (0-based, 0==Jan) |
|
201 * @param dom output parameter to receive day-of-month (1-based) |
|
202 * @param dow output parameter to receive day-of-week (1-based, 1==Sun) |
|
203 * @param doy output parameter to receive day-of-year (1-based) |
|
204 * @param mid output parameter to recieve millis-in-day |
|
205 */ |
|
206 static void timeToFields(UDate time, int32_t& year, int32_t& month, |
|
207 int32_t& dom, int32_t& dow, int32_t& doy, int32_t& mid); |
|
208 |
|
209 /** |
|
210 * Return the day of week on the 1970-epoch day |
|
211 * @param day the 1970-epoch day (integral value) |
|
212 * @return the day of week |
|
213 */ |
|
214 static int32_t dayOfWeek(double day); |
|
215 |
|
216 /** |
|
217 * Returns the ordinal number for the specified day of week within the month. |
|
218 * The valid return value is 1, 2, 3, 4 or -1. |
|
219 * @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc. |
|
220 * @param month 0-based month, with 0==Jan |
|
221 * @param dom 1-based day of month |
|
222 * @return The ordinal number for the specified day of week within the month |
|
223 */ |
|
224 static int32_t dayOfWeekInMonth(int32_t year, int32_t month, int32_t dom); |
|
225 |
|
226 /** |
|
227 * Converts Julian day to time as milliseconds. |
|
228 * @param julian the given Julian day number. |
|
229 * @return time as milliseconds. |
|
230 * @internal |
|
231 */ |
|
232 static inline double julianDayToMillis(int32_t julian); |
|
233 |
|
234 /** |
|
235 * Converts time as milliseconds to Julian day. |
|
236 * @param millis the given milliseconds. |
|
237 * @return the Julian day number. |
|
238 * @internal |
|
239 */ |
|
240 static inline int32_t millisToJulianDay(double millis); |
|
241 |
|
242 /** |
|
243 * Calculates the Gregorian day shift value for an extended year. |
|
244 * @param eyear Extended year |
|
245 * @returns number of days to ADD to Julian in order to convert from J->G |
|
246 */ |
|
247 static inline int32_t gregorianShift(int32_t eyear); |
|
248 |
|
249 private: |
|
250 static const int16_t DAYS_BEFORE[24]; |
|
251 static const int8_t MONTH_LENGTH[24]; |
|
252 }; |
|
253 |
|
254 inline double ClockMath::floorDivide(double numerator, double denominator) { |
|
255 return uprv_floor(numerator / denominator); |
|
256 } |
|
257 |
|
258 inline UBool Grego::isLeapYear(int32_t year) { |
|
259 // year&0x3 == year%4 |
|
260 return ((year&0x3) == 0) && ((year%100 != 0) || (year%400 == 0)); |
|
261 } |
|
262 |
|
263 inline int8_t |
|
264 Grego::monthLength(int32_t year, int32_t month) { |
|
265 return MONTH_LENGTH[month + (isLeapYear(year) ? 12 : 0)]; |
|
266 } |
|
267 |
|
268 inline int8_t |
|
269 Grego::previousMonthLength(int y, int m) { |
|
270 return (m > 0) ? monthLength(y, m-1) : 31; |
|
271 } |
|
272 |
|
273 inline void Grego::dayToFields(double day, int32_t& year, int32_t& month, |
|
274 int32_t& dom, int32_t& dow) { |
|
275 int32_t doy_unused; |
|
276 dayToFields(day,year,month,dom,dow,doy_unused); |
|
277 } |
|
278 |
|
279 inline double Grego::julianDayToMillis(int32_t julian) |
|
280 { |
|
281 return (julian - kEpochStartAsJulianDay) * kOneDay; |
|
282 } |
|
283 |
|
284 inline int32_t Grego::millisToJulianDay(double millis) { |
|
285 return (int32_t) (kEpochStartAsJulianDay + ClockMath::floorDivide(millis, (double)kOneDay)); |
|
286 } |
|
287 |
|
288 inline int32_t Grego::gregorianShift(int32_t eyear) { |
|
289 int32_t y = eyear-1; |
|
290 int32_t gregShift = ClockMath::floorDivide(y, 400) - ClockMath::floorDivide(y, 100) + 2; |
|
291 return gregShift; |
|
292 } |
|
293 |
|
294 /** |
|
295 * This utility class provides convenient access to the data needed for a calendar. |
|
296 * @internal ICU 3.0 |
|
297 */ |
|
298 class CalendarData : public UMemory { |
|
299 public: |
|
300 /** |
|
301 * Construct a CalendarData from the given locale. |
|
302 * @param loc locale to use. The 'calendar' keyword will be ignored. |
|
303 * @param type calendar type. NULL indicates the gregorian calendar. |
|
304 * No default lookup is done. |
|
305 * @param status error code |
|
306 */ |
|
307 CalendarData(const Locale& loc, const char *type, UErrorCode& status); |
|
308 |
|
309 /** |
|
310 * Load data for calendar. Note, this object owns the resources, do NOT call ures_close()! |
|
311 * The ResourceBundle C++ API should NOT be used because it is too slow for a low level API. |
|
312 * |
|
313 * @param key Resource key to data |
|
314 * @param status Error Status |
|
315 * @internal |
|
316 */ |
|
317 UResourceBundle* getByKey(const char *key, UErrorCode& status); |
|
318 |
|
319 /** |
|
320 * Load data for calendar. Note, this object owns the resources, do NOT call ures_close()! |
|
321 * There is an implicit key of 'format' |
|
322 * data is located in: "calendar/key/format/subKey" |
|
323 * for example, calendar/dayNames/format/abbreviated |
|
324 * The ResourceBundle C++ API should NOT be used because it is too slow for a low level API. |
|
325 * |
|
326 * @param key Resource key to data |
|
327 * @param subKey Resource key to data |
|
328 * @param status Error Status |
|
329 * @internal |
|
330 */ |
|
331 UResourceBundle* getByKey2(const char *key, const char *subKey, UErrorCode& status); |
|
332 |
|
333 /** |
|
334 * Load data for calendar. Note, this object owns the resources, do NOT call ures_close()! |
|
335 * data is located in: "calendar/key/contextKey/subKey" |
|
336 * for example, calendar/dayNames/standalone/narrow |
|
337 * The ResourceBundle C++ API should NOT be used because it is too slow for a low level API. |
|
338 * |
|
339 * @param key Resource key to data |
|
340 * @param contextKey Resource key to data |
|
341 * @param subKey Resource key to data |
|
342 * @param status Error Status |
|
343 * @internal |
|
344 */ |
|
345 UResourceBundle* getByKey3(const char *key, const char *contextKey, const char *subKey, UErrorCode& status); |
|
346 |
|
347 ~CalendarData(); |
|
348 |
|
349 private: |
|
350 void initData(const char *locale, const char *type, UErrorCode& status); |
|
351 |
|
352 UResourceBundle *fFillin; |
|
353 UResourceBundle *fOtherFillin; |
|
354 UResourceBundle *fBundle; |
|
355 UResourceBundle *fFallback; |
|
356 CalendarData(); // Not implemented. |
|
357 }; |
|
358 |
|
359 U_NAMESPACE_END |
|
360 |
|
361 #endif // !UCONFIG_NO_FORMATTING |
|
362 #endif // GREGOIMP_H |
|
363 |
|
364 //eof |