]> git.saurik.com Git - apple/icu.git/blame - icuSources/i18n/datefmt.cpp
ICU-551.51.tar.gz
[apple/icu.git] / icuSources / i18n / datefmt.cpp
CommitLineData
b75a7d8f 1/*
46f4442e 2 *******************************************************************************
57a6839d 3 * Copyright (C) 1997-2014, 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 27#include "unicode/dtptngen.h"
57a6839d 28#include "unicode/udisplaycontext.h"
46f4442e 29#include "reldtfmt.h"
b75a7d8f 30
73c04bcf
A
31#include "cstring.h"
32#include "windtfmt.h"
33
374ca955
A
34#if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
35#include <stdio.h>
36#endif
37
b75a7d8f
A
38// *****************************************************************************
39// class DateFormat
40// *****************************************************************************
41
42U_NAMESPACE_BEGIN
43
44DateFormat::DateFormat()
45: fCalendar(0),
57a6839d
A
46 fNumberFormat(0),
47 fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE)
b75a7d8f
A
48{
49}
50
51//----------------------------------------------------------------------
52
53DateFormat::DateFormat(const DateFormat& other)
54: Format(other),
55 fCalendar(0),
57a6839d
A
56 fNumberFormat(0),
57 fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE)
b75a7d8f
A
58{
59 *this = other;
60}
61
62//----------------------------------------------------------------------
63
64DateFormat& 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 }
57a6839d
A
80 fBoolFlags = other.fBoolFlags;
81 fCapitalizationContext = other.fCapitalizationContext;
b75a7d8f
A
82 }
83 return *this;
84}
85
86//----------------------------------------------------------------------
87
88DateFormat::~DateFormat()
89{
90 delete fCalendar;
91 delete fNumberFormat;
92}
93
94//----------------------------------------------------------------------
95
96UBool
97DateFormat::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
374ca955 103 // Format::operator== guarantees that this cast is safe
b75a7d8f
A
104 DateFormat* fmt = (DateFormat*)&other;
105
106 return (this == fmt) ||
374ca955 107 (Format::operator==(other) &&
b75a7d8f 108 fCalendar&&(fCalendar->isEquivalentTo(*fmt->fCalendar)) &&
57a6839d
A
109 (fNumberFormat && *fNumberFormat == *fmt->fNumberFormat) &&
110 (fCapitalizationContext == fmt->fCapitalizationContext) );
b75a7d8f
A
111}
112
113//----------------------------------------------------------------------
114
115UnicodeString&
116DateFormat::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
729e4ab9
A
150UnicodeString&
151DateFormat::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.
186UnicodeString&
187DateFormat::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
b75a7d8f
A
199UnicodeString&
200DateFormat::format(UDate date, UnicodeString& appendTo, FieldPosition& fieldPosition) const {
201 if (fCalendar != NULL) {
4388f060
A
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;
b75a7d8f
A
211 }
212 }
213 return appendTo;
214}
215
216//----------------------------------------------------------------------
217
729e4ab9
A
218UnicodeString&
219DateFormat::format(UDate date, UnicodeString& appendTo, FieldPositionIterator* posIter,
220 UErrorCode& status) const {
221 if (fCalendar != NULL) {
4388f060
A
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;
729e4ab9
A
229 }
230 }
231 return appendTo;
232}
233
234//----------------------------------------------------------------------
235
b75a7d8f
A
236UnicodeString&
237DateFormat::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
247UDate
248DateFormat::parse(const UnicodeString& text,
249 ParsePosition& pos) const
250{
46f4442e 251 UDate d = 0; // Error return UDate is 0 (the epoch)
b75a7d8f 252 if (fCalendar != NULL) {
4388f060
A
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 }
b75a7d8f 269 }
4388f060 270 delete calClone;
b75a7d8f
A
271 }
272 }
46f4442e 273 return d;
b75a7d8f
A
274}
275
276//----------------------------------------------------------------------
277
278UDate
279DateFormat::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);
374ca955
A
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 }
b75a7d8f
A
293 return result;
294}
295
296//----------------------------------------------------------------------
297
298void
299DateFormat::parseObject(const UnicodeString& source,
300 Formattable& result,
301 ParsePosition& pos) const
302{
303 result.setDate(parse(source, pos));
304}
305
306//----------------------------------------------------------------------
307
374ca955 308DateFormat* U_EXPORT2
b75a7d8f
A
309DateFormat::createTimeInstance(DateFormat::EStyle style,
310 const Locale& aLocale)
311{
b331163b 312 return createDateTimeInstance(kNone, style, aLocale);
b75a7d8f
A
313}
314
315//----------------------------------------------------------------------
316
374ca955 317DateFormat* U_EXPORT2
b75a7d8f
A
318DateFormat::createDateInstance(DateFormat::EStyle style,
319 const Locale& aLocale)
320{
b331163b 321 return createDateTimeInstance(style, kNone, aLocale);
b75a7d8f
A
322}
323
324//----------------------------------------------------------------------
325
374ca955 326DateFormat* U_EXPORT2
b75a7d8f
A
327DateFormat::createDateTimeInstance(EStyle dateStyle,
328 EStyle timeStyle,
329 const Locale& aLocale)
330{
b331163b
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 340DateFormat* U_EXPORT2
b75a7d8f
A
341DateFormat::createInstance()
342{
b331163b
A
343 return createDateTimeInstance(kShort, kShort, Locale::getDefault());
344}
345
346//----------------------------------------------------------------------
347
348DateFormat* U_EXPORT2
349DateFormat::createInstanceForSkeleton(
350 Calendar *calendarToAdopt,
351 const UnicodeString& skeleton,
352 const Locale &locale,
353 UErrorCode &status) {
354 LocalPointer<Calendar> calendar(calendarToAdopt);
355 if (U_FAILURE(status)) {
356 return NULL;
357 }
358 if (calendar.isNull()) {
359 status = U_ILLEGAL_ARGUMENT_ERROR;
360 return NULL;
361 }
362 DateFormat *result = createInstanceForSkeleton(skeleton, locale, status);
363 if (U_FAILURE(status)) {
364 return NULL;
365 }
366 result->adoptCalendar(calendar.orphan());
367 return result;
368}
369
370DateFormat* U_EXPORT2
371DateFormat::createInstanceForSkeleton(
372 const UnicodeString& skeleton,
373 const Locale &locale,
374 UErrorCode &status) {
375 LocalPointer<DateTimePatternGenerator> gen(
376 DateTimePatternGenerator::createInstance(locale, status));
377 if (U_FAILURE(status)) {
378 return NULL;
379 }
380 return internalCreateInstanceForSkeleton(
381 skeleton, locale, *gen, status);
382}
383
384DateFormat* U_EXPORT2
385DateFormat::createInstanceForSkeleton(
386 const UnicodeString& skeleton,
387 UErrorCode &status) {
388 return createInstanceForSkeleton(
389 skeleton, Locale::getDefault(), status);
390}
391
392DateFormat* U_EXPORT2
393DateFormat::internalCreateInstanceForSkeleton(
394 const UnicodeString& skeleton,
395 const Locale &locale,
396 DateTimePatternGenerator &gen,
397 UErrorCode &status) {
398 if (U_FAILURE(status)) {
399 return NULL;
400 }
401 DateFormat *fmt = new SimpleDateFormat(
402 gen.getBestPattern(skeleton, status),
403 locale,
404 status);
405 if (fmt == NULL) {
406 status = U_MEMORY_ALLOCATION_ERROR;
407 return NULL;
408 }
409 if (U_FAILURE(status)) {
410 delete fmt;
411 return NULL;
412 }
413 return fmt;
b75a7d8f
A
414}
415
416//----------------------------------------------------------------------
417
374ca955 418DateFormat* U_EXPORT2
b75a7d8f
A
419DateFormat::create(EStyle timeStyle, EStyle dateStyle, const Locale& locale)
420{
b75a7d8f 421 UErrorCode status = U_ZERO_ERROR;
4388f060 422#if U_PLATFORM_HAS_WIN32_API
73c04bcf
A
423 char buffer[8];
424 int32_t count = locale.getKeywordValue("compat", buffer, sizeof(buffer), status);
425
426 // if the locale has "@compat=host", create a host-specific DateFormat...
427 if (count > 0 && uprv_strcmp(buffer, "host") == 0) {
428 Win32DateFormat *f = new Win32DateFormat(timeStyle, dateStyle, locale, status);
429
430 if (U_SUCCESS(status)) {
431 return f;
432 }
433
434 delete f;
435 }
436#endif
437
46f4442e
A
438 // is it relative?
439 if(/*((timeStyle!=UDAT_NONE)&&(timeStyle & UDAT_RELATIVE)) || */((dateStyle!=kNone)&&((dateStyle-kDateOffset) & UDAT_RELATIVE))) {
440 RelativeDateFormat *r = new RelativeDateFormat((UDateFormatStyle)timeStyle, (UDateFormatStyle)(dateStyle-kDateOffset), locale, status);
441 if(U_SUCCESS(status)) return r;
442 delete r;
443 status = U_ZERO_ERROR;
444 }
73c04bcf
A
445
446 // Try to create a SimpleDateFormat of the desired style.
b75a7d8f
A
447 SimpleDateFormat *f = new SimpleDateFormat(timeStyle, dateStyle, locale, status);
448 if (U_SUCCESS(status)) return f;
449 delete f;
450
451 // If that fails, try to create a format using the default pattern and
452 // the DateFormatSymbols for this locale.
453 status = U_ZERO_ERROR;
454 f = new SimpleDateFormat(locale, status);
455 if (U_SUCCESS(status)) return f;
456 delete f;
457
458 // This should never really happen, because the preceding constructor
459 // should always succeed. If the resource data is unavailable, a last
460 // resort object should be returned.
461 return 0;
462}
463
464//----------------------------------------------------------------------
465
374ca955 466const Locale* U_EXPORT2
b75a7d8f
A
467DateFormat::getAvailableLocales(int32_t& count)
468{
469 // Get the list of installed locales.
470 // Even if root has the correct date format for this locale,
471 // it's still a valid locale (we don't worry about data fallbacks).
472 return Locale::getAvailableLocales(count);
473}
474
475//----------------------------------------------------------------------
476
477void
478DateFormat::adoptCalendar(Calendar* newCalendar)
479{
480 delete fCalendar;
481 fCalendar = newCalendar;
482}
483
484//----------------------------------------------------------------------
485void
486DateFormat::setCalendar(const Calendar& newCalendar)
487{
46f4442e
A
488 Calendar* newCalClone = newCalendar.clone();
489 if (newCalClone != NULL) {
490 adoptCalendar(newCalClone);
491 }
b75a7d8f
A
492}
493
494//----------------------------------------------------------------------
495
496const Calendar*
497DateFormat::getCalendar() const
498{
499 return fCalendar;
500}
501
502//----------------------------------------------------------------------
503
504void
505DateFormat::adoptNumberFormat(NumberFormat* newNumberFormat)
506{
507 delete fNumberFormat;
508 fNumberFormat = newNumberFormat;
509 newNumberFormat->setParseIntegerOnly(TRUE);
510}
511//----------------------------------------------------------------------
512
513void
514DateFormat::setNumberFormat(const NumberFormat& newNumberFormat)
515{
46f4442e
A
516 NumberFormat* newNumFmtClone = (NumberFormat*)newNumberFormat.clone();
517 if (newNumFmtClone != NULL) {
518 adoptNumberFormat(newNumFmtClone);
519 }
b75a7d8f
A
520}
521
522//----------------------------------------------------------------------
523
524const NumberFormat*
525DateFormat::getNumberFormat() const
526{
527 return fNumberFormat;
528}
529
530//----------------------------------------------------------------------
531
532void
533DateFormat::adoptTimeZone(TimeZone* zone)
534{
46f4442e
A
535 if (fCalendar != NULL) {
536 fCalendar->adoptTimeZone(zone);
537 }
b75a7d8f
A
538}
539//----------------------------------------------------------------------
540
541void
542DateFormat::setTimeZone(const TimeZone& zone)
543{
46f4442e
A
544 if (fCalendar != NULL) {
545 fCalendar->setTimeZone(zone);
546 }
b75a7d8f
A
547}
548
549//----------------------------------------------------------------------
550
551const TimeZone&
552DateFormat::getTimeZone() const
553{
46f4442e
A
554 if (fCalendar != NULL) {
555 return fCalendar->getTimeZone();
556 }
557 // If calendar doesn't exists, create default timezone.
558 // fCalendar is rarely null
559 return *(TimeZone::createDefault());
b75a7d8f
A
560}
561
562//----------------------------------------------------------------------
563
564void
565DateFormat::setLenient(UBool lenient)
566{
46f4442e
A
567 if (fCalendar != NULL) {
568 fCalendar->setLenient(lenient);
569 }
57a6839d
A
570 UErrorCode status = U_ZERO_ERROR;
571 setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, lenient, status);
572 setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, lenient, status);
b75a7d8f
A
573}
574
575//----------------------------------------------------------------------
576
577UBool
578DateFormat::isLenient() const
57a6839d
A
579{
580 UBool lenient = TRUE;
581 if (fCalendar != NULL) {
582 lenient = fCalendar->isLenient();
583 }
584 UErrorCode status = U_ZERO_ERROR;
585 return lenient
586 && getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status)
587 && getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status);
588}
589
590void
591DateFormat::setCalendarLenient(UBool lenient)
592{
593 if (fCalendar != NULL) {
594 fCalendar->setLenient(lenient);
595 }
596}
597
598//----------------------------------------------------------------------
599
600UBool
601DateFormat::isCalendarLenient() const
b75a7d8f 602{
46f4442e
A
603 if (fCalendar != NULL) {
604 return fCalendar->isLenient();
605 }
606 // fCalendar is rarely null
607 return FALSE;
b75a7d8f
A
608}
609
57a6839d
A
610
611//----------------------------------------------------------------------
612
613
614void DateFormat::setContext(UDisplayContext value, UErrorCode& status)
615{
616 if (U_FAILURE(status))
617 return;
618 if ( (UDisplayContextType)((uint32_t)value >> 8) == UDISPCTX_TYPE_CAPITALIZATION ) {
619 fCapitalizationContext = value;
620 } else {
621 status = U_ILLEGAL_ARGUMENT_ERROR;
622 }
623}
624
625
626//----------------------------------------------------------------------
627
628
629UDisplayContext DateFormat::getContext(UDisplayContextType type, UErrorCode& status) const
630{
631 if (U_FAILURE(status))
632 return (UDisplayContext)0;
633 if (type != UDISPCTX_TYPE_CAPITALIZATION) {
634 status = U_ILLEGAL_ARGUMENT_ERROR;
635 return (UDisplayContext)0;
636 }
637 return fCapitalizationContext;
638}
639
640
641//----------------------------------------------------------------------
642
643
644DateFormat&
645DateFormat::setBooleanAttribute(UDateFormatBooleanAttribute attr,
646 UBool newValue,
647 UErrorCode &status) {
648 if(!fBoolFlags.isValidValue(newValue)) {
649 status = U_ILLEGAL_ARGUMENT_ERROR;
650 } else {
651 fBoolFlags.set(attr, newValue);
652 }
653
654 return *this;
655}
656
657//----------------------------------------------------------------------
658
659UBool
660DateFormat::getBooleanAttribute(UDateFormatBooleanAttribute attr, UErrorCode &/*status*/) const {
661
662 return fBoolFlags.get(attr);
663}
664
b75a7d8f
A
665U_NAMESPACE_END
666
667#endif /* #if !UCONFIG_NO_FORMATTING */
668
669//eof