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