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