]>
Commit | Line | Data |
---|---|---|
b75a7d8f | 1 | /* |
46f4442e | 2 | ******************************************************************************* |
4388f060 | 3 | * Copyright (C) 1997-2011, International Business Machines Corporation and * |
46f4442e A |
4 | * others. All Rights Reserved. * |
5 | ******************************************************************************* | |
6 | * | |
7 | * File DATEFMT.CPP | |
8 | * | |
9 | * Modification History: | |
10 | * | |
11 | * Date Name Description | |
12 | * 02/19/97 aliu Converted from java. | |
13 | * 03/31/97 aliu Modified extensively to work with 50 locales. | |
14 | * 04/01/97 aliu Added support for centuries. | |
15 | * 08/12/97 aliu Fixed operator== to use Calendar::equivalentTo. | |
16 | * 07/20/98 stephen Changed ParsePosition initialization | |
17 | ******************************************************************************** | |
18 | */ | |
b75a7d8f A |
19 | |
20 | #include "unicode/utypes.h" | |
21 | ||
22 | #if !UCONFIG_NO_FORMATTING | |
23 | ||
374ca955 | 24 | #include "unicode/ures.h" |
b75a7d8f A |
25 | #include "unicode/datefmt.h" |
26 | #include "unicode/smpdtfmt.h" | |
46f4442e A |
27 | #include "unicode/dtptngen.h" |
28 | #include "reldtfmt.h" | |
b75a7d8f | 29 | |
73c04bcf A |
30 | #include "cstring.h" |
31 | #include "windtfmt.h" | |
32 | ||
374ca955 A |
33 | #if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL) |
34 | #include <stdio.h> | |
35 | #endif | |
36 | ||
b75a7d8f A |
37 | // ***************************************************************************** |
38 | // class DateFormat | |
39 | // ***************************************************************************** | |
40 | ||
41 | U_NAMESPACE_BEGIN | |
42 | ||
43 | DateFormat::DateFormat() | |
44 | : fCalendar(0), | |
45 | fNumberFormat(0) | |
46 | { | |
47 | } | |
48 | ||
49 | //---------------------------------------------------------------------- | |
50 | ||
51 | DateFormat::DateFormat(const DateFormat& other) | |
52 | : Format(other), | |
53 | fCalendar(0), | |
54 | fNumberFormat(0) | |
55 | { | |
56 | *this = other; | |
57 | } | |
58 | ||
59 | //---------------------------------------------------------------------- | |
60 | ||
61 | DateFormat& DateFormat::operator=(const DateFormat& other) | |
62 | { | |
63 | if (this != &other) | |
64 | { | |
65 | delete fCalendar; | |
66 | delete fNumberFormat; | |
67 | if(other.fCalendar) { | |
68 | fCalendar = other.fCalendar->clone(); | |
69 | } else { | |
70 | fCalendar = NULL; | |
71 | } | |
72 | if(other.fNumberFormat) { | |
73 | fNumberFormat = (NumberFormat*)other.fNumberFormat->clone(); | |
74 | } else { | |
75 | fNumberFormat = NULL; | |
76 | } | |
77 | } | |
78 | return *this; | |
79 | } | |
80 | ||
81 | //---------------------------------------------------------------------- | |
82 | ||
83 | DateFormat::~DateFormat() | |
84 | { | |
85 | delete fCalendar; | |
86 | delete fNumberFormat; | |
87 | } | |
88 | ||
89 | //---------------------------------------------------------------------- | |
90 | ||
91 | UBool | |
92 | DateFormat::operator==(const Format& other) const | |
93 | { | |
94 | // This protected comparison operator should only be called by subclasses | |
95 | // which have confirmed that the other object being compared against is | |
96 | // an instance of a sublcass of DateFormat. THIS IS IMPORTANT. | |
97 | ||
374ca955 | 98 | // Format::operator== guarantees that this cast is safe |
b75a7d8f A |
99 | DateFormat* fmt = (DateFormat*)&other; |
100 | ||
101 | return (this == fmt) || | |
374ca955 | 102 | (Format::operator==(other) && |
b75a7d8f | 103 | fCalendar&&(fCalendar->isEquivalentTo(*fmt->fCalendar)) && |
374ca955 | 104 | (fNumberFormat && *fNumberFormat == *fmt->fNumberFormat)); |
b75a7d8f A |
105 | } |
106 | ||
107 | //---------------------------------------------------------------------- | |
108 | ||
109 | UnicodeString& | |
110 | DateFormat::format(const Formattable& obj, | |
111 | UnicodeString& appendTo, | |
112 | FieldPosition& fieldPosition, | |
113 | UErrorCode& status) const | |
114 | { | |
115 | if (U_FAILURE(status)) return appendTo; | |
116 | ||
117 | // if the type of the Formattable is double or long, treat it as if it were a Date | |
118 | UDate date = 0; | |
119 | switch (obj.getType()) | |
120 | { | |
121 | case Formattable::kDate: | |
122 | date = obj.getDate(); | |
123 | break; | |
124 | case Formattable::kDouble: | |
125 | date = (UDate)obj.getDouble(); | |
126 | break; | |
127 | case Formattable::kLong: | |
128 | date = (UDate)obj.getLong(); | |
129 | break; | |
130 | default: | |
131 | status = U_ILLEGAL_ARGUMENT_ERROR; | |
132 | return appendTo; | |
133 | } | |
134 | ||
135 | // Is this right? | |
136 | //if (fieldPosition.getBeginIndex() == fieldPosition.getEndIndex()) | |
137 | // status = U_ILLEGAL_ARGUMENT_ERROR; | |
138 | ||
139 | return format(date, appendTo, fieldPosition); | |
140 | } | |
141 | ||
142 | //---------------------------------------------------------------------- | |
143 | ||
729e4ab9 A |
144 | UnicodeString& |
145 | DateFormat::format(const Formattable& obj, | |
146 | UnicodeString& appendTo, | |
147 | FieldPositionIterator* posIter, | |
148 | UErrorCode& status) const | |
149 | { | |
150 | if (U_FAILURE(status)) return appendTo; | |
151 | ||
152 | // if the type of the Formattable is double or long, treat it as if it were a Date | |
153 | UDate date = 0; | |
154 | switch (obj.getType()) | |
155 | { | |
156 | case Formattable::kDate: | |
157 | date = obj.getDate(); | |
158 | break; | |
159 | case Formattable::kDouble: | |
160 | date = (UDate)obj.getDouble(); | |
161 | break; | |
162 | case Formattable::kLong: | |
163 | date = (UDate)obj.getLong(); | |
164 | break; | |
165 | default: | |
166 | status = U_ILLEGAL_ARGUMENT_ERROR; | |
167 | return appendTo; | |
168 | } | |
169 | ||
170 | // Is this right? | |
171 | //if (fieldPosition.getBeginIndex() == fieldPosition.getEndIndex()) | |
172 | // status = U_ILLEGAL_ARGUMENT_ERROR; | |
173 | ||
174 | return format(date, appendTo, posIter, status); | |
175 | } | |
176 | ||
177 | //---------------------------------------------------------------------- | |
178 | ||
179 | // Default implementation for backwards compatibility, subclasses should implement. | |
180 | UnicodeString& | |
181 | DateFormat::format(Calendar& /* unused cal */, | |
182 | UnicodeString& appendTo, | |
183 | FieldPositionIterator* /* unused posIter */, | |
184 | UErrorCode& status) const { | |
185 | if (U_SUCCESS(status)) { | |
186 | status = U_UNSUPPORTED_ERROR; | |
187 | } | |
188 | return appendTo; | |
189 | } | |
190 | ||
191 | //---------------------------------------------------------------------- | |
192 | ||
b75a7d8f A |
193 | UnicodeString& |
194 | DateFormat::format(UDate date, UnicodeString& appendTo, FieldPosition& fieldPosition) const { | |
195 | if (fCalendar != NULL) { | |
4388f060 A |
196 | // Use a clone of our calendar instance |
197 | Calendar* calClone = fCalendar->clone(); | |
198 | if (calClone != NULL) { | |
199 | UErrorCode ec = U_ZERO_ERROR; | |
200 | calClone->setTime(date, ec); | |
201 | if (U_SUCCESS(ec)) { | |
202 | format(*calClone, appendTo, fieldPosition); | |
203 | } | |
204 | delete calClone; | |
b75a7d8f A |
205 | } |
206 | } | |
207 | return appendTo; | |
208 | } | |
209 | ||
210 | //---------------------------------------------------------------------- | |
211 | ||
729e4ab9 A |
212 | UnicodeString& |
213 | DateFormat::format(UDate date, UnicodeString& appendTo, FieldPositionIterator* posIter, | |
214 | UErrorCode& status) const { | |
215 | if (fCalendar != NULL) { | |
4388f060 A |
216 | Calendar* calClone = fCalendar->clone(); |
217 | if (calClone != NULL) { | |
218 | calClone->setTime(date, status); | |
219 | if (U_SUCCESS(status)) { | |
220 | format(*calClone, appendTo, posIter, status); | |
221 | } | |
222 | delete calClone; | |
729e4ab9 A |
223 | } |
224 | } | |
225 | return appendTo; | |
226 | } | |
227 | ||
228 | //---------------------------------------------------------------------- | |
229 | ||
b75a7d8f A |
230 | UnicodeString& |
231 | DateFormat::format(UDate date, UnicodeString& appendTo) const | |
232 | { | |
233 | // Note that any error information is just lost. That's okay | |
234 | // for this convenience method. | |
235 | FieldPosition fpos(0); | |
236 | return format(date, appendTo, fpos); | |
237 | } | |
238 | ||
239 | //---------------------------------------------------------------------- | |
240 | ||
241 | UDate | |
242 | DateFormat::parse(const UnicodeString& text, | |
243 | ParsePosition& pos) const | |
244 | { | |
46f4442e | 245 | UDate d = 0; // Error return UDate is 0 (the epoch) |
b75a7d8f | 246 | if (fCalendar != NULL) { |
4388f060 A |
247 | Calendar* calClone = fCalendar->clone(); |
248 | if (calClone != NULL) { | |
249 | int32_t start = pos.getIndex(); | |
250 | calClone->clear(); | |
251 | parse(text, *calClone, pos); | |
252 | if (pos.getIndex() != start) { | |
253 | UErrorCode ec = U_ZERO_ERROR; | |
254 | d = calClone->getTime(ec); | |
255 | if (U_FAILURE(ec)) { | |
256 | // We arrive here if fCalendar => calClone is non-lenient and | |
257 | // there is an out-of-range field. We don't know which field | |
258 | // was illegal so we set the error index to the start. | |
259 | pos.setIndex(start); | |
260 | pos.setErrorIndex(start); | |
261 | d = 0; | |
262 | } | |
b75a7d8f | 263 | } |
4388f060 | 264 | delete calClone; |
b75a7d8f A |
265 | } |
266 | } | |
46f4442e | 267 | return d; |
b75a7d8f A |
268 | } |
269 | ||
270 | //---------------------------------------------------------------------- | |
271 | ||
272 | UDate | |
273 | DateFormat::parse(const UnicodeString& text, | |
274 | UErrorCode& status) const | |
275 | { | |
276 | if (U_FAILURE(status)) return 0; | |
277 | ||
278 | ParsePosition pos(0); | |
279 | UDate result = parse(text, pos); | |
374ca955 A |
280 | if (pos.getIndex() == 0) { |
281 | #if defined (U_DEBUG_CAL) | |
282 | fprintf(stderr, "%s:%d - - failed to parse - err index %d\n" | |
283 | , __FILE__, __LINE__, pos.getErrorIndex() ); | |
284 | #endif | |
285 | status = U_ILLEGAL_ARGUMENT_ERROR; | |
286 | } | |
b75a7d8f A |
287 | return result; |
288 | } | |
289 | ||
290 | //---------------------------------------------------------------------- | |
291 | ||
292 | void | |
293 | DateFormat::parseObject(const UnicodeString& source, | |
294 | Formattable& result, | |
295 | ParsePosition& pos) const | |
296 | { | |
297 | result.setDate(parse(source, pos)); | |
298 | } | |
299 | ||
300 | //---------------------------------------------------------------------- | |
301 | ||
374ca955 | 302 | DateFormat* U_EXPORT2 |
b75a7d8f A |
303 | DateFormat::createTimeInstance(DateFormat::EStyle style, |
304 | const Locale& aLocale) | |
305 | { | |
306 | return create(style, kNone, aLocale); | |
307 | } | |
308 | ||
309 | //---------------------------------------------------------------------- | |
310 | ||
374ca955 | 311 | DateFormat* U_EXPORT2 |
b75a7d8f A |
312 | DateFormat::createDateInstance(DateFormat::EStyle style, |
313 | const Locale& aLocale) | |
314 | { | |
374ca955 A |
315 | // +4 to set the correct index for getting data out of |
316 | // LocaleElements. | |
317 | if(style != kNone) | |
318 | { | |
319 | style = (EStyle) (style + kDateOffset); | |
320 | } | |
321 | return create(kNone, (EStyle) (style), aLocale); | |
b75a7d8f A |
322 | } |
323 | ||
324 | //---------------------------------------------------------------------- | |
325 | ||
374ca955 | 326 | DateFormat* U_EXPORT2 |
b75a7d8f A |
327 | DateFormat::createDateTimeInstance(EStyle dateStyle, |
328 | EStyle timeStyle, | |
329 | const Locale& aLocale) | |
330 | { | |
374ca955 A |
331 | if(dateStyle != kNone) |
332 | { | |
333 | dateStyle = (EStyle) (dateStyle + kDateOffset); | |
334 | } | |
335 | return create(timeStyle, dateStyle, aLocale); | |
b75a7d8f A |
336 | } |
337 | ||
338 | //---------------------------------------------------------------------- | |
339 | ||
374ca955 | 340 | DateFormat* U_EXPORT2 |
b75a7d8f A |
341 | DateFormat::createInstance() |
342 | { | |
343 | return create(kShort, (EStyle) (kShort + kDateOffset), Locale::getDefault()); | |
344 | } | |
345 | ||
346 | //---------------------------------------------------------------------- | |
347 | ||
374ca955 | 348 | DateFormat* U_EXPORT2 |
b75a7d8f A |
349 | DateFormat::create(EStyle timeStyle, EStyle dateStyle, const Locale& locale) |
350 | { | |
b75a7d8f | 351 | UErrorCode status = U_ZERO_ERROR; |
4388f060 | 352 | #if U_PLATFORM_HAS_WIN32_API |
73c04bcf A |
353 | char buffer[8]; |
354 | int32_t count = locale.getKeywordValue("compat", buffer, sizeof(buffer), status); | |
355 | ||
356 | // if the locale has "@compat=host", create a host-specific DateFormat... | |
357 | if (count > 0 && uprv_strcmp(buffer, "host") == 0) { | |
358 | Win32DateFormat *f = new Win32DateFormat(timeStyle, dateStyle, locale, status); | |
359 | ||
360 | if (U_SUCCESS(status)) { | |
361 | return f; | |
362 | } | |
363 | ||
364 | delete f; | |
365 | } | |
366 | #endif | |
367 | ||
46f4442e A |
368 | // is it relative? |
369 | if(/*((timeStyle!=UDAT_NONE)&&(timeStyle & UDAT_RELATIVE)) || */((dateStyle!=kNone)&&((dateStyle-kDateOffset) & UDAT_RELATIVE))) { | |
370 | RelativeDateFormat *r = new RelativeDateFormat((UDateFormatStyle)timeStyle, (UDateFormatStyle)(dateStyle-kDateOffset), locale, status); | |
371 | if(U_SUCCESS(status)) return r; | |
372 | delete r; | |
373 | status = U_ZERO_ERROR; | |
374 | } | |
73c04bcf A |
375 | |
376 | // Try to create a SimpleDateFormat of the desired style. | |
b75a7d8f A |
377 | SimpleDateFormat *f = new SimpleDateFormat(timeStyle, dateStyle, locale, status); |
378 | if (U_SUCCESS(status)) return f; | |
379 | delete f; | |
380 | ||
381 | // If that fails, try to create a format using the default pattern and | |
382 | // the DateFormatSymbols for this locale. | |
383 | status = U_ZERO_ERROR; | |
384 | f = new SimpleDateFormat(locale, status); | |
385 | if (U_SUCCESS(status)) return f; | |
386 | delete f; | |
387 | ||
388 | // This should never really happen, because the preceding constructor | |
389 | // should always succeed. If the resource data is unavailable, a last | |
390 | // resort object should be returned. | |
391 | return 0; | |
392 | } | |
393 | ||
394 | //---------------------------------------------------------------------- | |
395 | ||
374ca955 | 396 | const Locale* U_EXPORT2 |
b75a7d8f A |
397 | DateFormat::getAvailableLocales(int32_t& count) |
398 | { | |
399 | // Get the list of installed locales. | |
400 | // Even if root has the correct date format for this locale, | |
401 | // it's still a valid locale (we don't worry about data fallbacks). | |
402 | return Locale::getAvailableLocales(count); | |
403 | } | |
404 | ||
405 | //---------------------------------------------------------------------- | |
406 | ||
407 | void | |
408 | DateFormat::adoptCalendar(Calendar* newCalendar) | |
409 | { | |
410 | delete fCalendar; | |
411 | fCalendar = newCalendar; | |
412 | } | |
413 | ||
414 | //---------------------------------------------------------------------- | |
415 | void | |
416 | DateFormat::setCalendar(const Calendar& newCalendar) | |
417 | { | |
46f4442e A |
418 | Calendar* newCalClone = newCalendar.clone(); |
419 | if (newCalClone != NULL) { | |
420 | adoptCalendar(newCalClone); | |
421 | } | |
b75a7d8f A |
422 | } |
423 | ||
424 | //---------------------------------------------------------------------- | |
425 | ||
426 | const Calendar* | |
427 | DateFormat::getCalendar() const | |
428 | { | |
429 | return fCalendar; | |
430 | } | |
431 | ||
432 | //---------------------------------------------------------------------- | |
433 | ||
434 | void | |
435 | DateFormat::adoptNumberFormat(NumberFormat* newNumberFormat) | |
436 | { | |
437 | delete fNumberFormat; | |
438 | fNumberFormat = newNumberFormat; | |
439 | newNumberFormat->setParseIntegerOnly(TRUE); | |
440 | } | |
441 | //---------------------------------------------------------------------- | |
442 | ||
443 | void | |
444 | DateFormat::setNumberFormat(const NumberFormat& newNumberFormat) | |
445 | { | |
46f4442e A |
446 | NumberFormat* newNumFmtClone = (NumberFormat*)newNumberFormat.clone(); |
447 | if (newNumFmtClone != NULL) { | |
448 | adoptNumberFormat(newNumFmtClone); | |
449 | } | |
b75a7d8f A |
450 | } |
451 | ||
452 | //---------------------------------------------------------------------- | |
453 | ||
454 | const NumberFormat* | |
455 | DateFormat::getNumberFormat() const | |
456 | { | |
457 | return fNumberFormat; | |
458 | } | |
459 | ||
460 | //---------------------------------------------------------------------- | |
461 | ||
462 | void | |
463 | DateFormat::adoptTimeZone(TimeZone* zone) | |
464 | { | |
46f4442e A |
465 | if (fCalendar != NULL) { |
466 | fCalendar->adoptTimeZone(zone); | |
467 | } | |
b75a7d8f A |
468 | } |
469 | //---------------------------------------------------------------------- | |
470 | ||
471 | void | |
472 | DateFormat::setTimeZone(const TimeZone& zone) | |
473 | { | |
46f4442e A |
474 | if (fCalendar != NULL) { |
475 | fCalendar->setTimeZone(zone); | |
476 | } | |
b75a7d8f A |
477 | } |
478 | ||
479 | //---------------------------------------------------------------------- | |
480 | ||
481 | const TimeZone& | |
482 | DateFormat::getTimeZone() const | |
483 | { | |
46f4442e A |
484 | if (fCalendar != NULL) { |
485 | return fCalendar->getTimeZone(); | |
486 | } | |
487 | // If calendar doesn't exists, create default timezone. | |
488 | // fCalendar is rarely null | |
489 | return *(TimeZone::createDefault()); | |
b75a7d8f A |
490 | } |
491 | ||
492 | //---------------------------------------------------------------------- | |
493 | ||
494 | void | |
495 | DateFormat::setLenient(UBool lenient) | |
496 | { | |
46f4442e A |
497 | if (fCalendar != NULL) { |
498 | fCalendar->setLenient(lenient); | |
499 | } | |
b75a7d8f A |
500 | } |
501 | ||
502 | //---------------------------------------------------------------------- | |
503 | ||
504 | UBool | |
505 | DateFormat::isLenient() const | |
506 | { | |
46f4442e A |
507 | if (fCalendar != NULL) { |
508 | return fCalendar->isLenient(); | |
509 | } | |
510 | // fCalendar is rarely null | |
511 | return FALSE; | |
b75a7d8f A |
512 | } |
513 | ||
514 | U_NAMESPACE_END | |
515 | ||
516 | #endif /* #if !UCONFIG_NO_FORMATTING */ | |
517 | ||
518 | //eof |