]>
Commit | Line | Data |
---|---|---|
f3c0d7a5 A |
1 | // © 2016 and later: Unicode, Inc. and others. |
2 | // License & terms of use: http://www.unicode.org/copyright.html | |
b75a7d8f A |
3 | /* |
4 | ******************************************************************************* | |
2ca993e8 | 5 | * Copyright (C) 1996-2016, International Business Machines |
b75a7d8f A |
6 | * Corporation and others. All Rights Reserved. |
7 | ******************************************************************************* | |
8 | */ | |
9 | ||
51004dcb | 10 | #include "utypeinfo.h" // for 'typeid' to work |
729e4ab9 | 11 | |
b75a7d8f A |
12 | #include "unicode/utypes.h" |
13 | ||
14 | #if !UCONFIG_NO_FORMATTING | |
15 | ||
b331163b A |
16 | #include <stdlib.h> // Apple addition for uacal_getDayPeriod |
17 | ||
b75a7d8f A |
18 | #include "unicode/ucal.h" |
19 | #include "unicode/uloc.h" | |
20 | #include "unicode/calendar.h" | |
21 | #include "unicode/timezone.h" | |
73c04bcf | 22 | #include "unicode/gregocal.h" |
b75a7d8f A |
23 | #include "unicode/simpletz.h" |
24 | #include "unicode/ustring.h" | |
25 | #include "unicode/strenum.h" | |
51004dcb | 26 | #include "unicode/localpointer.h" |
b75a7d8f | 27 | #include "cmemory.h" |
46f4442e | 28 | #include "cstring.h" |
b75a7d8f | 29 | #include "ustrenum.h" |
729e4ab9 A |
30 | #include "uenumimp.h" |
31 | #include "ulist.h" | |
2ca993e8 | 32 | #include "ulocimp.h" |
b75a7d8f A |
33 | |
34 | U_NAMESPACE_USE | |
35 | ||
36 | static TimeZone* | |
37 | _createTimeZone(const UChar* zoneID, int32_t len, UErrorCode* ec) { | |
38 | TimeZone* zone = NULL; | |
340931cb | 39 | if (ec != NULL && U_SUCCESS(*ec)) { |
b75a7d8f A |
40 | // Note that if zoneID is invalid, we get back GMT. This odd |
41 | // behavior is by design and goes back to the JDK. The only | |
42 | // failure we will see is a memory allocation failure. | |
43 | int32_t l = (len<0 ? u_strlen(zoneID) : len); | |
374ca955 A |
44 | UnicodeString zoneStrID; |
45 | zoneStrID.setTo((UBool)(len < 0), zoneID, l); /* temporary read-only alias */ | |
46 | zone = TimeZone::createTimeZone(zoneStrID); | |
b75a7d8f A |
47 | if (zone == NULL) { |
48 | *ec = U_MEMORY_ALLOCATION_ERROR; | |
49 | } | |
50 | } | |
51 | return zone; | |
52 | } | |
53 | ||
4388f060 A |
54 | U_CAPI UEnumeration* U_EXPORT2 |
55 | ucal_openTimeZoneIDEnumeration(USystemTimeZoneType zoneType, const char* region, | |
56 | const int32_t* rawOffset, UErrorCode* ec) { | |
57 | return uenum_openFromStringEnumeration(TimeZone::createTimeZoneIDEnumeration( | |
58 | zoneType, region, rawOffset, *ec), ec); | |
59 | } | |
60 | ||
b75a7d8f A |
61 | U_CAPI UEnumeration* U_EXPORT2 |
62 | ucal_openTimeZones(UErrorCode* ec) { | |
729e4ab9 | 63 | return uenum_openFromStringEnumeration(TimeZone::createEnumeration(), ec); |
b75a7d8f A |
64 | } |
65 | ||
66 | U_CAPI UEnumeration* U_EXPORT2 | |
67 | ucal_openCountryTimeZones(const char* country, UErrorCode* ec) { | |
729e4ab9 | 68 | return uenum_openFromStringEnumeration(TimeZone::createEnumeration(country), ec); |
b75a7d8f A |
69 | } |
70 | ||
71 | U_CAPI int32_t U_EXPORT2 | |
72 | ucal_getDefaultTimeZone(UChar* result, int32_t resultCapacity, UErrorCode* ec) { | |
73 | int32_t len = 0; | |
340931cb | 74 | if (ec != NULL && U_SUCCESS(*ec)) { |
b75a7d8f A |
75 | TimeZone* zone = TimeZone::createDefault(); |
76 | if (zone == NULL) { | |
77 | *ec = U_MEMORY_ALLOCATION_ERROR; | |
78 | } else { | |
79 | UnicodeString id; | |
80 | zone->getID(id); | |
81 | delete zone; | |
82 | len = id.extract(result, resultCapacity, *ec); | |
83 | } | |
84 | } | |
85 | return len; | |
86 | } | |
87 | ||
88 | U_CAPI void U_EXPORT2 | |
89 | ucal_setDefaultTimeZone(const UChar* zoneID, UErrorCode* ec) { | |
90 | TimeZone* zone = _createTimeZone(zoneID, -1, ec); | |
91 | if (zone != NULL) { | |
92 | TimeZone::adoptDefault(zone); | |
93 | } | |
94 | } | |
95 | ||
340931cb A |
96 | U_DRAFT int32_t U_EXPORT2 |
97 | ucal_getHostTimeZone(UChar* result, int32_t resultCapacity, UErrorCode* ec) { | |
98 | int32_t len = 0; | |
99 | if (ec != NULL && U_SUCCESS(*ec)) { | |
100 | TimeZone *zone = TimeZone::detectHostTimeZone(); | |
101 | if (zone == NULL) { | |
102 | *ec = U_MEMORY_ALLOCATION_ERROR; | |
103 | } else { | |
104 | UnicodeString id; | |
105 | zone->getID(id); | |
106 | delete zone; | |
107 | len = id.extract(result, resultCapacity, *ec); | |
108 | } | |
109 | } | |
110 | return len; | |
111 | } | |
112 | ||
b75a7d8f A |
113 | U_CAPI int32_t U_EXPORT2 |
114 | ucal_getDSTSavings(const UChar* zoneID, UErrorCode* ec) { | |
115 | int32_t result = 0; | |
116 | TimeZone* zone = _createTimeZone(zoneID, -1, ec); | |
374ca955 | 117 | if (U_SUCCESS(*ec)) { |
729e4ab9 A |
118 | SimpleTimeZone* stz = dynamic_cast<SimpleTimeZone*>(zone); |
119 | if (stz != NULL) { | |
120 | result = stz->getDSTSavings(); | |
374ca955 A |
121 | } else { |
122 | // Since there is no getDSTSavings on TimeZone, we use a | |
123 | // heuristic: Starting with the current time, march | |
124 | // forwards for one year, looking for DST savings. | |
125 | // Stepping by weeks is sufficient. | |
126 | UDate d = Calendar::getNow(); | |
127 | for (int32_t i=0; i<53; ++i, d+=U_MILLIS_PER_DAY*7.0) { | |
128 | int32_t raw, dst; | |
129 | zone->getOffset(d, FALSE, raw, dst, *ec); | |
130 | if (U_FAILURE(*ec)) { | |
131 | break; | |
132 | } else if (dst != 0) { | |
133 | result = dst; | |
134 | break; | |
135 | } | |
136 | } | |
137 | } | |
b75a7d8f A |
138 | } |
139 | delete zone; | |
140 | return result; | |
141 | } | |
142 | ||
b75a7d8f A |
143 | U_CAPI UDate U_EXPORT2 |
144 | ucal_getNow() | |
145 | { | |
146 | ||
147 | return Calendar::getNow(); | |
148 | } | |
149 | ||
46f4442e A |
150 | #define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY) |
151 | ||
b75a7d8f | 152 | U_CAPI UCalendar* U_EXPORT2 |
46f4442e A |
153 | ucal_open( const UChar* zoneID, |
154 | int32_t len, | |
155 | const char* locale, | |
156 | UCalendarType caltype, | |
157 | UErrorCode* status) | |
b75a7d8f A |
158 | { |
159 | ||
160 | if(U_FAILURE(*status)) return 0; | |
161 | ||
340931cb A |
162 | LocalPointer<TimeZone> zone( (zoneID==NULL) ? TimeZone::createDefault() |
163 | : _createTimeZone(zoneID, len, status), *status); | |
b75a7d8f A |
164 | |
165 | if (U_FAILURE(*status)) { | |
166 | return NULL; | |
167 | } | |
46f4442e A |
168 | |
169 | if ( caltype == UCAL_GREGORIAN ) { | |
170 | char localeBuf[ULOC_LOCALE_IDENTIFIER_CAPACITY]; | |
729e4ab9 A |
171 | if ( locale == NULL ) { |
172 | locale = uloc_getDefault(); | |
173 | } | |
46f4442e A |
174 | uprv_strncpy(localeBuf, locale, ULOC_LOCALE_IDENTIFIER_CAPACITY); |
175 | uloc_setKeywordValue("calendar", "gregorian", localeBuf, ULOC_LOCALE_IDENTIFIER_CAPACITY, status); | |
176 | if (U_FAILURE(*status)) { | |
177 | return NULL; | |
178 | } | |
340931cb | 179 | return (UCalendar*)Calendar::createInstance(zone.orphan(), Locale(localeBuf), *status); |
46f4442e | 180 | } |
340931cb | 181 | return (UCalendar*)Calendar::createInstance(zone.orphan(), Locale(locale), *status); |
b75a7d8f A |
182 | } |
183 | ||
184 | U_CAPI void U_EXPORT2 | |
185 | ucal_close(UCalendar *cal) | |
186 | { | |
187 | ||
188 | delete (Calendar*) cal; | |
189 | } | |
190 | ||
46f4442e A |
191 | U_CAPI UCalendar* U_EXPORT2 |
192 | ucal_clone(const UCalendar* cal, | |
193 | UErrorCode* status) | |
194 | { | |
195 | if(U_FAILURE(*status)) return 0; | |
196 | ||
197 | Calendar* res = ((Calendar*)cal)->clone(); | |
198 | ||
199 | if(res == 0) { | |
200 | *status = U_MEMORY_ALLOCATION_ERROR; | |
201 | return 0; | |
202 | } | |
203 | ||
204 | return (UCalendar*) res; | |
205 | } | |
206 | ||
b75a7d8f A |
207 | U_CAPI void U_EXPORT2 |
208 | ucal_setTimeZone( UCalendar* cal, | |
209 | const UChar* zoneID, | |
210 | int32_t len, | |
211 | UErrorCode *status) | |
212 | { | |
213 | ||
214 | if(U_FAILURE(*status)) | |
215 | return; | |
0f5d89e8 A |
216 | |
217 | TimeZone* zone; | |
218 | if (zoneID==NULL) { | |
219 | zone = TimeZone::createDefault(); | |
220 | } else { | |
221 | UnicodeString zoneStrID, id; | |
222 | zoneStrID.setTo(len < 0, zoneID, len); /* aliasing assignment, avoids copy */ | |
223 | ((Calendar*)cal)->getTimeZone().getID(id); | |
224 | if (id == zoneStrID) { | |
225 | return; | |
226 | } | |
227 | zone = TimeZone::createTimeZone(zoneStrID); | |
228 | } | |
b75a7d8f A |
229 | |
230 | if (zone != NULL) { | |
231 | ((Calendar*)cal)->adoptTimeZone(zone); | |
0f5d89e8 A |
232 | } else { |
233 | *status = U_MEMORY_ALLOCATION_ERROR; | |
b75a7d8f A |
234 | } |
235 | } | |
236 | ||
51004dcb A |
237 | U_CAPI int32_t U_EXPORT2 |
238 | ucal_getTimeZoneID(const UCalendar *cal, | |
239 | UChar *result, | |
240 | int32_t resultLength, | |
241 | UErrorCode *status) | |
242 | { | |
243 | if (U_FAILURE(*status)) { | |
244 | return 0; | |
245 | } | |
246 | const TimeZone& tz = ((Calendar*)cal)->getTimeZone(); | |
247 | UnicodeString id; | |
248 | tz.getID(id); | |
249 | return id.extract(result, resultLength, *status); | |
250 | } | |
251 | ||
b75a7d8f A |
252 | U_CAPI int32_t U_EXPORT2 |
253 | ucal_getTimeZoneDisplayName(const UCalendar* cal, | |
254 | UCalendarDisplayNameType type, | |
255 | const char *locale, | |
256 | UChar* result, | |
257 | int32_t resultLength, | |
258 | UErrorCode* status) | |
259 | { | |
260 | ||
46f4442e | 261 | if(U_FAILURE(*status)) return -1; |
b75a7d8f | 262 | |
46f4442e A |
263 | const TimeZone& tz = ((Calendar*)cal)->getTimeZone(); |
264 | UnicodeString id; | |
265 | if(!(result==NULL && resultLength==0)) { | |
266 | // NULL destination for pure preflighting: empty dummy string | |
267 | // otherwise, alias the destination buffer | |
268 | id.setTo(result, 0, resultLength); | |
269 | } | |
b75a7d8f | 270 | |
46f4442e | 271 | switch(type) { |
b75a7d8f | 272 | case UCAL_STANDARD: |
46f4442e A |
273 | tz.getDisplayName(FALSE, TimeZone::LONG, Locale(locale), id); |
274 | break; | |
b75a7d8f A |
275 | |
276 | case UCAL_SHORT_STANDARD: | |
46f4442e A |
277 | tz.getDisplayName(FALSE, TimeZone::SHORT, Locale(locale), id); |
278 | break; | |
b75a7d8f A |
279 | |
280 | case UCAL_DST: | |
46f4442e A |
281 | tz.getDisplayName(TRUE, TimeZone::LONG, Locale(locale), id); |
282 | break; | |
b75a7d8f A |
283 | |
284 | case UCAL_SHORT_DST: | |
46f4442e A |
285 | tz.getDisplayName(TRUE, TimeZone::SHORT, Locale(locale), id); |
286 | break; | |
287 | } | |
b75a7d8f | 288 | |
46f4442e | 289 | return id.extract(result, resultLength, *status); |
b75a7d8f A |
290 | } |
291 | ||
292 | U_CAPI UBool U_EXPORT2 | |
293 | ucal_inDaylightTime( const UCalendar* cal, | |
46f4442e | 294 | UErrorCode* status ) |
b75a7d8f A |
295 | { |
296 | ||
46f4442e A |
297 | if(U_FAILURE(*status)) return (UBool) -1; |
298 | return ((Calendar*)cal)->inDaylightTime(*status); | |
b75a7d8f A |
299 | } |
300 | ||
46f4442e | 301 | U_CAPI void U_EXPORT2 |
73c04bcf | 302 | ucal_setGregorianChange(UCalendar *cal, UDate date, UErrorCode *pErrorCode) { |
46f4442e A |
303 | if(U_FAILURE(*pErrorCode)) { |
304 | return; | |
305 | } | |
306 | Calendar *cpp_cal = (Calendar *)cal; | |
729e4ab9 A |
307 | GregorianCalendar *gregocal = dynamic_cast<GregorianCalendar *>(cpp_cal); |
308 | // Not if(gregocal == NULL) { | |
309 | // because we really want to work only with a GregorianCalendar, not with | |
310 | // its subclasses like BuddhistCalendar. | |
4388f060 A |
311 | if (cpp_cal == NULL) { |
312 | // We normally don't check "this" pointers for NULL, but this here avoids | |
313 | // compiler-generated exception-throwing code in case cal == NULL. | |
314 | *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR; | |
315 | return; | |
316 | } | |
729e4ab9 | 317 | if(typeid(*cpp_cal) != typeid(GregorianCalendar)) { |
46f4442e A |
318 | *pErrorCode = U_UNSUPPORTED_ERROR; |
319 | return; | |
320 | } | |
729e4ab9 | 321 | gregocal->setGregorianChange(date, *pErrorCode); |
73c04bcf A |
322 | } |
323 | ||
46f4442e | 324 | U_CAPI UDate U_EXPORT2 |
73c04bcf | 325 | ucal_getGregorianChange(const UCalendar *cal, UErrorCode *pErrorCode) { |
46f4442e A |
326 | if(U_FAILURE(*pErrorCode)) { |
327 | return (UDate)0; | |
328 | } | |
729e4ab9 A |
329 | const Calendar *cpp_cal = (const Calendar *)cal; |
330 | const GregorianCalendar *gregocal = dynamic_cast<const GregorianCalendar *>(cpp_cal); | |
331 | // Not if(gregocal == NULL) { | |
332 | // see comments in ucal_setGregorianChange(). | |
4388f060 A |
333 | if (cpp_cal == NULL) { |
334 | // We normally don't check "this" pointers for NULL, but this here avoids | |
335 | // compiler-generated exception-throwing code in case cal == NULL. | |
336 | *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR; | |
337 | return (UDate)0; | |
338 | } | |
729e4ab9 | 339 | if(typeid(*cpp_cal) != typeid(GregorianCalendar)) { |
46f4442e A |
340 | *pErrorCode = U_UNSUPPORTED_ERROR; |
341 | return (UDate)0; | |
342 | } | |
729e4ab9 | 343 | return gregocal->getGregorianChange(); |
73c04bcf A |
344 | } |
345 | ||
b75a7d8f A |
346 | U_CAPI int32_t U_EXPORT2 |
347 | ucal_getAttribute( const UCalendar* cal, | |
46f4442e | 348 | UCalendarAttribute attr) |
b75a7d8f A |
349 | { |
350 | ||
46f4442e | 351 | switch(attr) { |
b75a7d8f | 352 | case UCAL_LENIENT: |
46f4442e A |
353 | return ((Calendar*)cal)->isLenient(); |
354 | ||
b75a7d8f | 355 | case UCAL_FIRST_DAY_OF_WEEK: |
46f4442e A |
356 | return ((Calendar*)cal)->getFirstDayOfWeek(); |
357 | ||
b75a7d8f | 358 | case UCAL_MINIMAL_DAYS_IN_FIRST_WEEK: |
46f4442e | 359 | return ((Calendar*)cal)->getMinimalDaysInFirstWeek(); |
b75a7d8f | 360 | |
4388f060 A |
361 | case UCAL_REPEATED_WALL_TIME: |
362 | return ((Calendar*)cal)->getRepeatedWallTimeOption(); | |
363 | ||
364 | case UCAL_SKIPPED_WALL_TIME: | |
365 | return ((Calendar*)cal)->getSkippedWallTimeOption(); | |
366 | ||
b75a7d8f | 367 | default: |
46f4442e A |
368 | break; |
369 | } | |
370 | return -1; | |
b75a7d8f A |
371 | } |
372 | ||
373 | U_CAPI void U_EXPORT2 | |
374 | ucal_setAttribute( UCalendar* cal, | |
46f4442e A |
375 | UCalendarAttribute attr, |
376 | int32_t newValue) | |
b75a7d8f A |
377 | { |
378 | ||
46f4442e | 379 | switch(attr) { |
b75a7d8f | 380 | case UCAL_LENIENT: |
46f4442e A |
381 | ((Calendar*)cal)->setLenient((UBool)newValue); |
382 | break; | |
383 | ||
b75a7d8f | 384 | case UCAL_FIRST_DAY_OF_WEEK: |
46f4442e A |
385 | ((Calendar*)cal)->setFirstDayOfWeek((UCalendarDaysOfWeek)newValue); |
386 | break; | |
387 | ||
b75a7d8f | 388 | case UCAL_MINIMAL_DAYS_IN_FIRST_WEEK: |
46f4442e A |
389 | ((Calendar*)cal)->setMinimalDaysInFirstWeek((uint8_t)newValue); |
390 | break; | |
4388f060 A |
391 | |
392 | case UCAL_REPEATED_WALL_TIME: | |
393 | ((Calendar*)cal)->setRepeatedWallTimeOption((UCalendarWallTimeOption)newValue); | |
394 | break; | |
395 | ||
396 | case UCAL_SKIPPED_WALL_TIME: | |
397 | ((Calendar*)cal)->setSkippedWallTimeOption((UCalendarWallTimeOption)newValue); | |
398 | break; | |
46f4442e | 399 | } |
b75a7d8f A |
400 | } |
401 | ||
402 | U_CAPI const char* U_EXPORT2 | |
403 | ucal_getAvailable(int32_t index) | |
404 | { | |
405 | ||
46f4442e | 406 | return uloc_getAvailable(index); |
b75a7d8f A |
407 | } |
408 | ||
409 | U_CAPI int32_t U_EXPORT2 | |
410 | ucal_countAvailable() | |
411 | { | |
412 | ||
46f4442e | 413 | return uloc_countAvailable(); |
b75a7d8f A |
414 | } |
415 | ||
416 | U_CAPI UDate U_EXPORT2 | |
417 | ucal_getMillis( const UCalendar* cal, | |
46f4442e | 418 | UErrorCode* status) |
b75a7d8f A |
419 | { |
420 | ||
46f4442e | 421 | if(U_FAILURE(*status)) return (UDate) 0; |
b75a7d8f | 422 | |
46f4442e | 423 | return ((Calendar*)cal)->getTime(*status); |
b75a7d8f A |
424 | } |
425 | ||
426 | U_CAPI void U_EXPORT2 | |
427 | ucal_setMillis( UCalendar* cal, | |
46f4442e A |
428 | UDate dateTime, |
429 | UErrorCode* status ) | |
b75a7d8f | 430 | { |
46f4442e | 431 | if(U_FAILURE(*status)) return; |
b75a7d8f | 432 | |
46f4442e | 433 | ((Calendar*)cal)->setTime(dateTime, *status); |
b75a7d8f A |
434 | } |
435 | ||
436 | // TBD: why does this take an UErrorCode? | |
437 | U_CAPI void U_EXPORT2 | |
438 | ucal_setDate( UCalendar* cal, | |
46f4442e A |
439 | int32_t year, |
440 | int32_t month, | |
441 | int32_t date, | |
442 | UErrorCode *status) | |
b75a7d8f A |
443 | { |
444 | ||
46f4442e | 445 | if(U_FAILURE(*status)) return; |
b75a7d8f | 446 | |
46f4442e | 447 | ((Calendar*)cal)->set(year, month, date); |
b75a7d8f A |
448 | } |
449 | ||
450 | // TBD: why does this take an UErrorCode? | |
451 | U_CAPI void U_EXPORT2 | |
452 | ucal_setDateTime( UCalendar* cal, | |
46f4442e A |
453 | int32_t year, |
454 | int32_t month, | |
455 | int32_t date, | |
456 | int32_t hour, | |
457 | int32_t minute, | |
458 | int32_t second, | |
459 | UErrorCode *status) | |
b75a7d8f | 460 | { |
46f4442e | 461 | if(U_FAILURE(*status)) return; |
b75a7d8f | 462 | |
46f4442e | 463 | ((Calendar*)cal)->set(year, month, date, hour, minute, second); |
b75a7d8f A |
464 | } |
465 | ||
466 | U_CAPI UBool U_EXPORT2 | |
467 | ucal_equivalentTo( const UCalendar* cal1, | |
46f4442e | 468 | const UCalendar* cal2) |
b75a7d8f A |
469 | { |
470 | ||
46f4442e | 471 | return ((Calendar*)cal1)->isEquivalentTo(*((Calendar*)cal2)); |
b75a7d8f A |
472 | } |
473 | ||
474 | U_CAPI void U_EXPORT2 | |
475 | ucal_add( UCalendar* cal, | |
46f4442e A |
476 | UCalendarDateFields field, |
477 | int32_t amount, | |
478 | UErrorCode* status) | |
b75a7d8f A |
479 | { |
480 | ||
46f4442e | 481 | if(U_FAILURE(*status)) return; |
b75a7d8f | 482 | |
46f4442e | 483 | ((Calendar*)cal)->add(field, amount, *status); |
b75a7d8f A |
484 | } |
485 | ||
486 | U_CAPI void U_EXPORT2 | |
487 | ucal_roll( UCalendar* cal, | |
46f4442e A |
488 | UCalendarDateFields field, |
489 | int32_t amount, | |
490 | UErrorCode* status) | |
b75a7d8f A |
491 | { |
492 | ||
46f4442e | 493 | if(U_FAILURE(*status)) return; |
b75a7d8f | 494 | |
46f4442e | 495 | ((Calendar*)cal)->roll(field, amount, *status); |
b75a7d8f A |
496 | } |
497 | ||
498 | U_CAPI int32_t U_EXPORT2 | |
499 | ucal_get( const UCalendar* cal, | |
46f4442e A |
500 | UCalendarDateFields field, |
501 | UErrorCode* status ) | |
b75a7d8f A |
502 | { |
503 | ||
46f4442e | 504 | if(U_FAILURE(*status)) return -1; |
b75a7d8f | 505 | |
46f4442e | 506 | return ((Calendar*)cal)->get(field, *status); |
b75a7d8f A |
507 | } |
508 | ||
509 | U_CAPI void U_EXPORT2 | |
510 | ucal_set( UCalendar* cal, | |
46f4442e A |
511 | UCalendarDateFields field, |
512 | int32_t value) | |
b75a7d8f A |
513 | { |
514 | ||
46f4442e | 515 | ((Calendar*)cal)->set(field, value); |
b75a7d8f A |
516 | } |
517 | ||
518 | U_CAPI UBool U_EXPORT2 | |
519 | ucal_isSet( const UCalendar* cal, | |
46f4442e | 520 | UCalendarDateFields field) |
b75a7d8f A |
521 | { |
522 | ||
46f4442e | 523 | return ((Calendar*)cal)->isSet(field); |
b75a7d8f A |
524 | } |
525 | ||
526 | U_CAPI void U_EXPORT2 | |
527 | ucal_clearField( UCalendar* cal, | |
46f4442e | 528 | UCalendarDateFields field) |
b75a7d8f A |
529 | { |
530 | ||
46f4442e | 531 | ((Calendar*)cal)->clear(field); |
b75a7d8f A |
532 | } |
533 | ||
534 | U_CAPI void U_EXPORT2 | |
535 | ucal_clear(UCalendar* calendar) | |
536 | { | |
537 | ||
46f4442e | 538 | ((Calendar*)calendar)->clear(); |
b75a7d8f A |
539 | } |
540 | ||
541 | U_CAPI int32_t U_EXPORT2 | |
542 | ucal_getLimit( const UCalendar* cal, | |
46f4442e A |
543 | UCalendarDateFields field, |
544 | UCalendarLimitType type, | |
545 | UErrorCode *status) | |
b75a7d8f A |
546 | { |
547 | ||
46f4442e A |
548 | if(status==0 || U_FAILURE(*status)) { |
549 | return -1; | |
550 | } | |
551 | ||
552 | switch(type) { | |
b75a7d8f | 553 | case UCAL_MINIMUM: |
46f4442e | 554 | return ((Calendar*)cal)->getMinimum(field); |
b75a7d8f A |
555 | |
556 | case UCAL_MAXIMUM: | |
46f4442e | 557 | return ((Calendar*)cal)->getMaximum(field); |
b75a7d8f A |
558 | |
559 | case UCAL_GREATEST_MINIMUM: | |
46f4442e | 560 | return ((Calendar*)cal)->getGreatestMinimum(field); |
b75a7d8f A |
561 | |
562 | case UCAL_LEAST_MAXIMUM: | |
46f4442e | 563 | return ((Calendar*)cal)->getLeastMaximum(field); |
b75a7d8f A |
564 | |
565 | case UCAL_ACTUAL_MINIMUM: | |
46f4442e A |
566 | return ((Calendar*)cal)->getActualMinimum(field, |
567 | *status); | |
b75a7d8f A |
568 | |
569 | case UCAL_ACTUAL_MAXIMUM: | |
46f4442e A |
570 | return ((Calendar*)cal)->getActualMaximum(field, |
571 | *status); | |
b75a7d8f A |
572 | |
573 | default: | |
46f4442e A |
574 | break; |
575 | } | |
576 | return -1; | |
b75a7d8f A |
577 | } |
578 | ||
374ca955 A |
579 | U_CAPI const char * U_EXPORT2 |
580 | ucal_getLocaleByType(const UCalendar *cal, ULocDataLocaleType type, UErrorCode* status) | |
581 | { | |
582 | if (cal == NULL) { | |
583 | if (U_SUCCESS(*status)) { | |
584 | *status = U_ILLEGAL_ARGUMENT_ERROR; | |
585 | } | |
586 | return NULL; | |
587 | } | |
588 | return ((Calendar*)cal)->getLocaleID(type, *status); | |
589 | } | |
590 | ||
46f4442e A |
591 | U_CAPI const char * U_EXPORT2 |
592 | ucal_getTZDataVersion(UErrorCode* status) | |
593 | { | |
594 | return TimeZone::getTZDataVersion(*status); | |
595 | } | |
596 | ||
597 | U_CAPI int32_t U_EXPORT2 | |
598 | ucal_getCanonicalTimeZoneID(const UChar* id, int32_t len, | |
599 | UChar* result, int32_t resultCapacity, UBool *isSystemID, UErrorCode* status) { | |
600 | if(status == 0 || U_FAILURE(*status)) { | |
601 | return 0; | |
602 | } | |
603 | if (isSystemID) { | |
604 | *isSystemID = FALSE; | |
605 | } | |
606 | if (id == 0 || len == 0 || result == 0 || resultCapacity <= 0) { | |
607 | *status = U_ILLEGAL_ARGUMENT_ERROR; | |
608 | return 0; | |
609 | } | |
610 | int32_t reslen = 0; | |
611 | UnicodeString canonical; | |
612 | UBool systemID = FALSE; | |
613 | TimeZone::getCanonicalID(UnicodeString(id, len), canonical, systemID, *status); | |
614 | if (U_SUCCESS(*status)) { | |
615 | if (isSystemID) { | |
616 | *isSystemID = systemID; | |
617 | } | |
618 | reslen = canonical.extract(result, resultCapacity, *status); | |
619 | } | |
620 | return reslen; | |
621 | } | |
622 | ||
623 | U_CAPI const char * U_EXPORT2 | |
624 | ucal_getType(const UCalendar *cal, UErrorCode* status) | |
625 | { | |
626 | if (U_FAILURE(*status)) { | |
627 | return NULL; | |
628 | } | |
629 | return ((Calendar*)cal)->getType(); | |
630 | } | |
631 | ||
729e4ab9 A |
632 | U_CAPI UCalendarWeekdayType U_EXPORT2 |
633 | ucal_getDayOfWeekType(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode* status) | |
634 | { | |
635 | if (U_FAILURE(*status)) { | |
636 | return UCAL_WEEKDAY; | |
637 | } | |
638 | return ((Calendar*)cal)->getDayOfWeekType(dayOfWeek, *status); | |
639 | } | |
640 | ||
641 | U_CAPI int32_t U_EXPORT2 | |
642 | ucal_getWeekendTransition(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode *status) | |
643 | { | |
644 | if (U_FAILURE(*status)) { | |
645 | return 0; | |
646 | } | |
647 | return ((Calendar*)cal)->getWeekendTransition(dayOfWeek, *status); | |
648 | } | |
649 | ||
650 | U_CAPI UBool U_EXPORT2 | |
651 | ucal_isWeekend(const UCalendar *cal, UDate date, UErrorCode *status) | |
46f4442e | 652 | { |
729e4ab9 A |
653 | if (U_FAILURE(*status)) { |
654 | return FALSE; | |
655 | } | |
656 | return ((Calendar*)cal)->isWeekend(date, *status); | |
657 | } | |
658 | ||
659 | U_CAPI int32_t U_EXPORT2 | |
660 | ucal_getFieldDifference(UCalendar* cal, UDate target, | |
661 | UCalendarDateFields field, | |
662 | UErrorCode* status ) | |
663 | { | |
664 | if (U_FAILURE(*status)) { | |
665 | return 0; | |
666 | } | |
667 | return ((Calendar*)cal)->fieldDifference(target, field, *status); | |
668 | } | |
669 | ||
670 | ||
671 | static const UEnumeration defaultKeywordValues = { | |
672 | NULL, | |
673 | NULL, | |
674 | ulist_close_keyword_values_iterator, | |
675 | ulist_count_keyword_values, | |
676 | uenum_unextDefault, | |
677 | ulist_next_keyword_value, | |
678 | ulist_reset_keyword_values_iterator | |
679 | }; | |
680 | ||
681 | static const char * const CAL_TYPES[] = { | |
682 | "gregorian", | |
683 | "japanese", | |
684 | "buddhist", | |
685 | "roc", | |
686 | "persian", | |
687 | "islamic-civil", | |
688 | "islamic", | |
689 | "hebrew", | |
690 | "chinese", | |
691 | "indian", | |
692 | "coptic", | |
693 | "ethiopic", | |
694 | "ethiopic-amete-alem", | |
57a6839d A |
695 | "iso8601", |
696 | "dangi", | |
697 | "islamic-umalqura", | |
698 | "islamic-tbla", | |
699 | "islamic-rgsa", | |
729e4ab9 A |
700 | NULL |
701 | }; | |
702 | ||
703 | U_CAPI UEnumeration* U_EXPORT2 | |
704 | ucal_getKeywordValuesForLocale(const char * /* key */, const char* locale, UBool commonlyUsed, UErrorCode *status) { | |
705 | // Resolve region | |
2ca993e8 A |
706 | char prefRegion[ULOC_COUNTRY_CAPACITY]; |
707 | (void)ulocimp_getRegionForSupplementalData(locale, TRUE, prefRegion, sizeof(prefRegion), status); | |
729e4ab9 A |
708 | |
709 | // Read preferred calendar values from supplementalData calendarPreference | |
710 | UResourceBundle *rb = ures_openDirect(NULL, "supplementalData", status); | |
711 | ures_getByKey(rb, "calendarPreferenceData", rb, status); | |
712 | UResourceBundle *order = ures_getByKey(rb, prefRegion, NULL, status); | |
713 | if (*status == U_MISSING_RESOURCE_ERROR && rb != NULL) { | |
714 | *status = U_ZERO_ERROR; | |
715 | order = ures_getByKey(rb, "001", NULL, status); | |
716 | } | |
717 | ||
718 | // Create a list of calendar type strings | |
719 | UList *values = NULL; | |
720 | if (U_SUCCESS(*status)) { | |
721 | values = ulist_createEmptyList(status); | |
722 | if (U_SUCCESS(*status)) { | |
723 | for (int i = 0; i < ures_getSize(order); i++) { | |
724 | int32_t len; | |
725 | const UChar *type = ures_getStringByIndex(order, i, &len, status); | |
726 | char *caltype = (char*)uprv_malloc(len + 1); | |
727 | if (caltype == NULL) { | |
728 | *status = U_MEMORY_ALLOCATION_ERROR; | |
729 | break; | |
730 | } | |
731 | u_UCharsToChars(type, caltype, len); | |
732 | *(caltype + len) = 0; | |
733 | ||
734 | ulist_addItemEndList(values, caltype, TRUE, status); | |
735 | if (U_FAILURE(*status)) { | |
736 | break; | |
737 | } | |
738 | } | |
739 | ||
740 | if (U_SUCCESS(*status) && !commonlyUsed) { | |
741 | // If not commonlyUsed, add other available values | |
742 | for (int32_t i = 0; CAL_TYPES[i] != NULL; i++) { | |
743 | if (!ulist_containsString(values, CAL_TYPES[i], (int32_t)uprv_strlen(CAL_TYPES[i]))) { | |
744 | ulist_addItemEndList(values, CAL_TYPES[i], FALSE, status); | |
745 | if (U_FAILURE(*status)) { | |
746 | break; | |
747 | } | |
748 | } | |
749 | } | |
750 | } | |
751 | if (U_FAILURE(*status)) { | |
752 | ulist_deleteList(values); | |
753 | values = NULL; | |
754 | } | |
755 | } | |
756 | } | |
757 | ||
758 | ures_close(order); | |
759 | ures_close(rb); | |
760 | ||
761 | if (U_FAILURE(*status) || values == NULL) { | |
762 | return NULL; | |
763 | } | |
764 | ||
765 | // Create string enumeration | |
766 | UEnumeration *en = (UEnumeration*)uprv_malloc(sizeof(UEnumeration)); | |
767 | if (en == NULL) { | |
768 | *status = U_MEMORY_ALLOCATION_ERROR; | |
769 | ulist_deleteList(values); | |
770 | return NULL; | |
771 | } | |
772 | ulist_resetList(values); | |
773 | memcpy(en, &defaultKeywordValues, sizeof(UEnumeration)); | |
774 | en->context = values; | |
775 | return en; | |
46f4442e A |
776 | } |
777 | ||
51004dcb A |
778 | U_CAPI UBool U_EXPORT2 |
779 | ucal_getTimeZoneTransitionDate(const UCalendar* cal, UTimeZoneTransitionType type, | |
780 | UDate* transition, UErrorCode* status) | |
781 | { | |
782 | if (U_FAILURE(*status)) { | |
783 | return FALSE; | |
784 | } | |
785 | UDate base = ((Calendar*)cal)->getTime(*status); | |
786 | const TimeZone& tz = ((Calendar*)cal)->getTimeZone(); | |
787 | const BasicTimeZone * btz = dynamic_cast<const BasicTimeZone *>(&tz); | |
788 | if (btz != NULL && U_SUCCESS(*status)) { | |
789 | TimeZoneTransition tzt; | |
790 | UBool inclusive = (type == UCAL_TZ_TRANSITION_NEXT_INCLUSIVE || type == UCAL_TZ_TRANSITION_PREVIOUS_INCLUSIVE); | |
791 | UBool result = (type == UCAL_TZ_TRANSITION_NEXT || type == UCAL_TZ_TRANSITION_NEXT_INCLUSIVE)? | |
792 | btz->getNextTransition(base, inclusive, tzt): | |
793 | btz->getPreviousTransition(base, inclusive, tzt); | |
794 | if (result) { | |
795 | *transition = tzt.getTime(); | |
796 | return TRUE; | |
797 | } | |
798 | } | |
799 | return FALSE; | |
800 | } | |
801 | ||
57a6839d A |
802 | U_CAPI int32_t U_EXPORT2 |
803 | ucal_getWindowsTimeZoneID(const UChar* id, int32_t len, UChar* winid, int32_t winidCapacity, UErrorCode* status) { | |
804 | if (U_FAILURE(*status)) { | |
805 | return 0; | |
806 | } | |
807 | ||
808 | int32_t resultLen = 0; | |
809 | UnicodeString resultWinID; | |
810 | ||
811 | TimeZone::getWindowsID(UnicodeString(id, len), resultWinID, *status); | |
812 | if (U_SUCCESS(*status) && resultWinID.length() > 0) { | |
813 | resultLen = resultWinID.length(); | |
814 | resultWinID.extract(winid, winidCapacity, *status); | |
815 | } | |
816 | ||
817 | return resultLen; | |
818 | } | |
819 | ||
820 | U_CAPI int32_t U_EXPORT2 | |
821 | ucal_getTimeZoneIDForWindowsID(const UChar* winid, int32_t len, const char* region, UChar* id, int32_t idCapacity, UErrorCode* status) { | |
822 | if (U_FAILURE(*status)) { | |
823 | return 0; | |
824 | } | |
825 | ||
826 | int32_t resultLen = 0; | |
827 | UnicodeString resultID; | |
828 | ||
829 | TimeZone::getIDForWindowsID(UnicodeString(winid, len), region, resultID, *status); | |
830 | if (U_SUCCESS(*status) && resultID.length() > 0) { | |
831 | resultLen = resultID.length(); | |
832 | resultID.extract(id, idCapacity, *status); | |
833 | } | |
834 | ||
835 | return resultLen; | |
836 | } | |
837 | ||
b331163b A |
838 | // Apple-specific function uacal_getDayPeriod and helper functions/data |
839 | typedef struct { | |
840 | const char* name; | |
841 | UADayPeriod value; | |
842 | } DayPeriodNameToValue; | |
843 | ||
844 | static const DayPeriodNameToValue dpNameToValue[] = { | |
845 | { "afternoon1", UADAYPERIOD_AFTERNOON1 }, | |
846 | { "afternoon2", UADAYPERIOD_AFTERNOON2 }, | |
847 | { "evening1", UADAYPERIOD_EVENING1 }, | |
848 | { "evening2", UADAYPERIOD_EVENING2 }, | |
849 | { "midnight", UADAYPERIOD_MIDNIGHT }, | |
850 | { "morning1", UADAYPERIOD_MORNING1 }, | |
851 | { "morning2", UADAYPERIOD_MORNING2 }, | |
852 | { "night1", UADAYPERIOD_NIGHT1 }, | |
853 | { "night2", UADAYPERIOD_NIGHT2 }, | |
854 | { "noon", UADAYPERIOD_NOON }, | |
855 | }; | |
856 | ||
857 | static UADayPeriod dayPeriodFromName(const char* name) { | |
858 | const DayPeriodNameToValue * dpNameToValuePtr = dpNameToValue; | |
859 | const DayPeriodNameToValue * dpNameToValueLim = dpNameToValue + UPRV_LENGTHOF(dpNameToValue); | |
860 | // simple linear search, dpNameToValue is small enough | |
861 | for (; dpNameToValuePtr < dpNameToValueLim; dpNameToValuePtr++) { | |
862 | if (uprv_strcmp(name, dpNameToValuePtr->name) == 0) { | |
863 | return dpNameToValuePtr->value; | |
864 | } | |
865 | } | |
866 | return UADAYPERIOD_UNKNOWN; | |
867 | } | |
868 | ||
869 | typedef struct { | |
870 | int32_t startHour; | |
871 | int32_t startMin; | |
872 | UADayPeriod value; | |
873 | } DayPeriodEntry; | |
874 | ||
875 | int CompareDayPeriodEntries(const void* entry1Ptr, const void* entry2Ptr) { | |
876 | const DayPeriodEntry * dpEntry1Ptr = (const DayPeriodEntry *)entry1Ptr; | |
877 | const DayPeriodEntry * dpEntry2Ptr = (const DayPeriodEntry *)entry2Ptr; | |
878 | if (dpEntry1Ptr->startHour < dpEntry2Ptr->startHour) return -1; | |
879 | if (dpEntry1Ptr->startHour > dpEntry2Ptr->startHour) return 1; | |
880 | // here hours are equal | |
881 | if (dpEntry1Ptr->startMin < dpEntry2Ptr->startMin) return -1; | |
882 | if (dpEntry1Ptr->startMin > dpEntry2Ptr->startMin) return 1; | |
883 | return 0; | |
884 | } | |
885 | ||
886 | enum { kSetNameMaxLen = 8, kBoundaryTimeMaxLen = 6, kDayPeriodEntriesMax = 12 }; | |
887 | ||
888 | U_CAPI UADayPeriod U_EXPORT2 | |
889 | uacal_getDayPeriod( const char* locale, | |
890 | int32_t hour, | |
891 | int32_t minute, | |
892 | UBool formatStyle, | |
893 | UErrorCode* status ) { | |
894 | UADayPeriod dayPeriod = UADAYPERIOD_UNKNOWN; | |
895 | DayPeriodEntry dpEntries[kDayPeriodEntriesMax]; | |
896 | int32_t dpEntriesCount = 0; | |
897 | ||
898 | if (U_FAILURE(*status)) { | |
899 | return dayPeriod; | |
900 | } | |
901 | if (hour < 0 || hour > 23 || minute < 0 || minute > 59) { | |
902 | *status = U_ILLEGAL_ARGUMENT_ERROR; | |
903 | return dayPeriod; | |
904 | } | |
905 | // get dayPeriods bundle | |
906 | LocalUResourceBundlePointer rb(ures_openDirect(NULL, "dayPeriods", status)); | |
907 | if (U_FAILURE(*status)) { | |
908 | return dayPeriod; | |
909 | } | |
910 | // get locales/locales_selection subbundle | |
911 | LocalUResourceBundlePointer rbSub(ures_getByKey(rb.getAlias(), formatStyle? "locales": "locales_selection", NULL, status)); | |
912 | if (U_FAILURE(*status)) { | |
913 | return dayPeriod; | |
914 | } | |
915 | // get bundle for language (maps to setName) | |
916 | char lang[ULOC_LANG_CAPACITY] = {0}; | |
917 | if (locale != NULL) { | |
918 | UErrorCode tempStatus = U_ZERO_ERROR; | |
919 | uloc_getLanguage(locale, lang, ULOC_LANG_CAPACITY, &tempStatus); | |
920 | if (U_FAILURE(*status) || *status == U_STRING_NOT_TERMINATED_WARNING) { | |
921 | lang[0] = 0; | |
922 | } | |
923 | } | |
924 | if (lang[0] == 0) { | |
2ca993e8 | 925 | uprv_strcpy(lang, "en"); // should be "root" but the data for root was missing |
b331163b A |
926 | } |
927 | LocalUResourceBundlePointer rbLang(ures_getByKey(rbSub.getAlias(), lang, NULL, status)); | |
928 | if (U_FAILURE(*status)) { | |
929 | // should only happen if lang was not [root] en | |
2ca993e8 | 930 | // fallback should be "root" but the data for root was missing, use "en" |
b331163b A |
931 | *status = U_ZERO_ERROR; |
932 | rbLang.adoptInstead(ures_getByKey(rbSub.getAlias(), "en", rbLang.orphan(), status)); | |
933 | } | |
934 | if (U_FAILURE(*status)) { | |
935 | return dayPeriod; | |
936 | } | |
937 | // get setName from language bundle | |
938 | char setName[kSetNameMaxLen] = {0}; | |
939 | int32_t setNameLen = kSetNameMaxLen; | |
940 | ures_getUTF8String(rbLang.getAlias(), setName, &setNameLen, TRUE, status); | |
941 | if (U_FAILURE(*status)) { | |
942 | return dayPeriod; | |
943 | } | |
944 | // get rules subbundle | |
945 | rbSub.adoptInstead(ures_getByKey(rb.getAlias(), "rules", rbSub.orphan(), status)); | |
946 | if (U_FAILURE(*status)) { | |
947 | return dayPeriod; | |
948 | } | |
949 | // get ruleset from rules subbundle | |
950 | rb.adoptInstead(ures_getByKey(rbSub.getAlias(), setName, rb.orphan(), status)); | |
951 | if (U_FAILURE(*status)) { | |
952 | return dayPeriod; | |
953 | } | |
954 | // OK, we should finally have a ruleset (works to here). | |
955 | // Iterate over it to collect entries | |
956 | LocalUResourceBundlePointer rbBound; | |
957 | while (ures_hasNext(rb.getAlias())) { | |
958 | rbSub.adoptInstead(ures_getNextResource(rb.getAlias(), rbSub.orphan(), status)); | |
959 | if (U_FAILURE(*status)) { | |
960 | return dayPeriod; | |
961 | } | |
962 | // rbSub now has the bundle for a particular dayPeriod such as morning1, afternoon2, noon | |
963 | UADayPeriod dpForBundle = dayPeriodFromName(ures_getKey(rbSub.getAlias())); | |
2ca993e8 | 964 | int32_t dpLimit = 24; |
b331163b A |
965 | while (ures_hasNext(rbSub.getAlias())) { |
966 | rbBound.adoptInstead(ures_getNextResource(rbSub.getAlias(), rbBound.orphan(), status)); | |
967 | if (U_FAILURE(*status)) { | |
968 | return dayPeriod; | |
969 | } | |
2ca993e8 | 970 | // rbBound now has the bundle for a particular time period boundary such as at, from, before. |
b331163b A |
971 | // This is either of type URES_STRING (size=1) or of type URES_ARRAY (size > 1) |
972 | const char *boundaryType = ures_getKey(rbBound.getAlias()); | |
2ca993e8 A |
973 | char boundaryTimeStr[kBoundaryTimeMaxLen]; |
974 | int32_t boundaryTimeStrLen = kBoundaryTimeMaxLen; | |
975 | ures_getUTF8String(rbBound.getAlias(), boundaryTimeStr, &boundaryTimeStrLen, TRUE, status); | |
976 | if (U_FAILURE(*status)) { | |
977 | return dayPeriod; | |
978 | } | |
979 | int32_t startHour = atoi(boundaryTimeStr); // can depend on POSIX locale (fortunately no decimal sep here) | |
b331163b | 980 | if (uprv_strcmp(boundaryType, "before") == 0) { |
2ca993e8 | 981 | dpLimit = startHour; |
b331163b A |
982 | continue; |
983 | } | |
2ca993e8 A |
984 | int32_t startMinute = 0; |
985 | if (uprv_strcmp(boundaryType, "from") == 0) { | |
986 | startMinute = 1; | |
987 | if (startHour > dpLimit && dpEntriesCount < kDayPeriodEntriesMax) { | |
988 | dpEntries[dpEntriesCount].startHour = 0; | |
989 | dpEntries[dpEntriesCount].startMin = startMinute; | |
b331163b A |
990 | dpEntries[dpEntriesCount].value = dpForBundle; |
991 | dpEntriesCount++; | |
992 | } | |
993 | } | |
2ca993e8 A |
994 | if (dpEntriesCount < kDayPeriodEntriesMax) { |
995 | dpEntries[dpEntriesCount].startHour = startHour; | |
996 | dpEntries[dpEntriesCount].startMin = startMinute; | |
997 | dpEntries[dpEntriesCount].value = dpForBundle; | |
998 | dpEntriesCount++; | |
999 | } | |
b331163b A |
1000 | } |
1001 | } | |
1002 | if (dpEntriesCount < kDayPeriodEntriesMax) { | |
1003 | dpEntries[dpEntriesCount].startHour = 24; | |
1004 | dpEntries[dpEntriesCount].startMin = 0; | |
1005 | dpEntries[dpEntriesCount].value = UADAYPERIOD_UNKNOWN; | |
1006 | dpEntriesCount++; | |
1007 | } | |
1008 | // We have collected all of the rule data, now sort by time | |
1009 | qsort(dpEntries, dpEntriesCount, sizeof(DayPeriodEntry), CompareDayPeriodEntries); | |
2ca993e8 A |
1010 | |
1011 | // now fix start minute for the non-"at" entries | |
1012 | int32_t dpIndex; | |
1013 | for (dpIndex = 0; dpIndex < dpEntriesCount; dpIndex++) { | |
1014 | if (dpIndex == 0 || (dpEntries[dpIndex-1].value != UADAYPERIOD_MIDNIGHT && dpEntries[dpIndex-1].value != UADAYPERIOD_NOON)) { | |
1015 | dpEntries[dpIndex].startMin = 0; | |
1016 | } | |
1017 | } | |
1018 | ||
b331163b A |
1019 | // OK, all of the above is what we would do in an "open" function if we were using an |
1020 | // open/use/close model for this; the object would just have the sorted array above. | |
1021 | ||
1022 | // Now we use the sorted array to find the dayPeriod matching the supplied time. | |
1023 | // Only a few entries, linear search OK | |
1024 | DayPeriodEntry entryToMatch = { hour, minute, UADAYPERIOD_UNKNOWN }; | |
2ca993e8 | 1025 | dpIndex = 0; |
b331163b A |
1026 | while (dpIndex < dpEntriesCount - 1 && CompareDayPeriodEntries(&entryToMatch, &dpEntries[dpIndex + 1]) >= 0) { |
1027 | dpIndex++; | |
1028 | } | |
1029 | if (CompareDayPeriodEntries(&entryToMatch, &dpEntries[dpIndex]) >= 0) { | |
1030 | dayPeriod = dpEntries[dpIndex].value; | |
1031 | } | |
1032 | ||
1033 | return dayPeriod; | |
1034 | } | |
1035 | ||
1036 | ||
57a6839d | 1037 | |
b75a7d8f | 1038 | #endif /* #if !UCONFIG_NO_FORMATTING */ |