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
DateFormat()44 DateFormat::DateFormat()
45 : fCalendar(0),
46 fNumberFormat(0),
47 fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE)
48 {
49 }
50
51 //----------------------------------------------------------------------
52
DateFormat(const DateFormat & other)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
operator =(const DateFormat & other)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
~DateFormat()88 DateFormat::~DateFormat()
89 {
90 delete fCalendar;
91 delete fNumberFormat;
92 }
93
94 //----------------------------------------------------------------------
95
96 UBool
operator ==(const Format & other) const97 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&
format(const Formattable & obj,UnicodeString & appendTo,FieldPosition & fieldPosition,UErrorCode & status) const116 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&
format(const Formattable & obj,UnicodeString & appendTo,FieldPositionIterator * posIter,UErrorCode & status) const151 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&
format(Calendar &,UnicodeString & appendTo,FieldPositionIterator *,UErrorCode & status) const187 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&
format(UDate date,UnicodeString & appendTo,FieldPosition & fieldPosition) const200 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&
format(UDate date,UnicodeString & appendTo,FieldPositionIterator * posIter,UErrorCode & status) const219 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&
format(UDate date,UnicodeString & appendTo) const237 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
parse(const UnicodeString & text,ParsePosition & pos) const248 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
parse(const UnicodeString & text,UErrorCode & status) const279 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
parseObject(const UnicodeString & source,Formattable & result,ParsePosition & pos) const299 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
createTimeInstance(DateFormat::EStyle style,const Locale & aLocale)309 DateFormat::createTimeInstance(DateFormat::EStyle style,
310 const Locale& aLocale)
311 {
312 return createDateTimeInstance(kNone, style, aLocale);
313 }
314
315 //----------------------------------------------------------------------
316
317 DateFormat* U_EXPORT2
createDateInstance(DateFormat::EStyle style,const Locale & aLocale)318 DateFormat::createDateInstance(DateFormat::EStyle style,
319 const Locale& aLocale)
320 {
321 return createDateTimeInstance(style, kNone, aLocale);
322 }
323
324 //----------------------------------------------------------------------
325
326 DateFormat* U_EXPORT2
createDateTimeInstance(EStyle dateStyle,EStyle timeStyle,const Locale & aLocale)327 DateFormat::createDateTimeInstance(EStyle dateStyle,
328 EStyle timeStyle,
329 const Locale& aLocale)
330 {
331 if(dateStyle != kNone)
332 {
333 dateStyle = (EStyle) (dateStyle + kDateOffset);
334 }
335 return create(timeStyle, dateStyle, aLocale);
336 }
337
338 //----------------------------------------------------------------------
339
340 DateFormat* U_EXPORT2
createInstance()341 DateFormat::createInstance()
342 {
343 return createDateTimeInstance(kShort, kShort, Locale::getDefault());
344 }
345
346 //----------------------------------------------------------------------
347
348 DateFormat* U_EXPORT2
createInstanceForSkeleton(Calendar * calendarToAdopt,const UnicodeString & skeleton,const Locale & locale,UErrorCode & status)349 DateFormat::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
370 DateFormat* U_EXPORT2
createInstanceForSkeleton(const UnicodeString & skeleton,const Locale & locale,UErrorCode & status)371 DateFormat::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
384 DateFormat* U_EXPORT2
createInstanceForSkeleton(const UnicodeString & skeleton,UErrorCode & status)385 DateFormat::createInstanceForSkeleton(
386 const UnicodeString& skeleton,
387 UErrorCode &status) {
388 return createInstanceForSkeleton(
389 skeleton, Locale::getDefault(), status);
390 }
391
392 DateFormat* U_EXPORT2
internalCreateInstanceForSkeleton(const UnicodeString & skeleton,const Locale & locale,DateTimePatternGenerator & gen,UErrorCode & status)393 DateFormat::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;
414 }
415
416 //----------------------------------------------------------------------
417
418 DateFormat* U_EXPORT2
create(EStyle timeStyle,EStyle dateStyle,const Locale & locale)419 DateFormat::create(EStyle timeStyle, EStyle dateStyle, const Locale& locale)
420 {
421 UErrorCode status = U_ZERO_ERROR;
422 #if U_PLATFORM_HAS_WIN32_API
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
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 }
445
446 // Try to create a SimpleDateFormat of the desired style.
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
466 const Locale* U_EXPORT2
getAvailableLocales(int32_t & count)467 DateFormat::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
477 void
adoptCalendar(Calendar * newCalendar)478 DateFormat::adoptCalendar(Calendar* newCalendar)
479 {
480 delete fCalendar;
481 fCalendar = newCalendar;
482 }
483
484 //----------------------------------------------------------------------
485 void
setCalendar(const Calendar & newCalendar)486 DateFormat::setCalendar(const Calendar& newCalendar)
487 {
488 Calendar* newCalClone = newCalendar.clone();
489 if (newCalClone != NULL) {
490 adoptCalendar(newCalClone);
491 }
492 }
493
494 //----------------------------------------------------------------------
495
496 const Calendar*
getCalendar() const497 DateFormat::getCalendar() const
498 {
499 return fCalendar;
500 }
501
502 //----------------------------------------------------------------------
503
504 void
adoptNumberFormat(NumberFormat * newNumberFormat)505 DateFormat::adoptNumberFormat(NumberFormat* newNumberFormat)
506 {
507 delete fNumberFormat;
508 fNumberFormat = newNumberFormat;
509 newNumberFormat->setParseIntegerOnly(TRUE);
510 }
511 //----------------------------------------------------------------------
512
513 void
setNumberFormat(const NumberFormat & newNumberFormat)514 DateFormat::setNumberFormat(const NumberFormat& newNumberFormat)
515 {
516 NumberFormat* newNumFmtClone = (NumberFormat*)newNumberFormat.clone();
517 if (newNumFmtClone != NULL) {
518 adoptNumberFormat(newNumFmtClone);
519 }
520 }
521
522 //----------------------------------------------------------------------
523
524 const NumberFormat*
getNumberFormat() const525 DateFormat::getNumberFormat() const
526 {
527 return fNumberFormat;
528 }
529
530 //----------------------------------------------------------------------
531
532 void
adoptTimeZone(TimeZone * zone)533 DateFormat::adoptTimeZone(TimeZone* zone)
534 {
535 if (fCalendar != NULL) {
536 fCalendar->adoptTimeZone(zone);
537 }
538 }
539 //----------------------------------------------------------------------
540
541 void
setTimeZone(const TimeZone & zone)542 DateFormat::setTimeZone(const TimeZone& zone)
543 {
544 if (fCalendar != NULL) {
545 fCalendar->setTimeZone(zone);
546 }
547 }
548
549 //----------------------------------------------------------------------
550
551 const TimeZone&
getTimeZone() const552 DateFormat::getTimeZone() const
553 {
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());
560 }
561
562 //----------------------------------------------------------------------
563
564 void
setLenient(UBool lenient)565 DateFormat::setLenient(UBool lenient)
566 {
567 if (fCalendar != NULL) {
568 fCalendar->setLenient(lenient);
569 }
570 UErrorCode status = U_ZERO_ERROR;
571 setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, lenient, status);
572 setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, lenient, status);
573 }
574
575 //----------------------------------------------------------------------
576
577 UBool
isLenient() const578 DateFormat::isLenient() const
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
590 void
setCalendarLenient(UBool lenient)591 DateFormat::setCalendarLenient(UBool lenient)
592 {
593 if (fCalendar != NULL) {
594 fCalendar->setLenient(lenient);
595 }
596 }
597
598 //----------------------------------------------------------------------
599
600 UBool
isCalendarLenient() const601 DateFormat::isCalendarLenient() const
602 {
603 if (fCalendar != NULL) {
604 return fCalendar->isLenient();
605 }
606 // fCalendar is rarely null
607 return FALSE;
608 }
609
610
611 //----------------------------------------------------------------------
612
613
setContext(UDisplayContext value,UErrorCode & status)614 void 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
getContext(UDisplayContextType type,UErrorCode & status) const629 UDisplayContext 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
644 DateFormat&
setBooleanAttribute(UDateFormatBooleanAttribute attr,UBool newValue,UErrorCode & status)645 DateFormat::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
659 UBool
getBooleanAttribute(UDateFormatBooleanAttribute attr,UErrorCode &) const660 DateFormat::getBooleanAttribute(UDateFormatBooleanAttribute attr, UErrorCode &/*status*/) const {
661
662 return fBoolFlags.get(attr);
663 }
664
665 U_NAMESPACE_END
666
667 #endif /* #if !UCONFIG_NO_FORMATTING */
668
669 //eof
670