2 *******************************************************************************
3 * Copyright (C) 1997-2014, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
9 * Modification History:
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 ********************************************************************************
20 #include "unicode/utypes.h"
22 #if !UCONFIG_NO_FORMATTING
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"
34 #if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
38 // *****************************************************************************
40 // *****************************************************************************
44 DateFormat::DateFormat()
47 fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE
)
51 //----------------------------------------------------------------------
53 DateFormat::DateFormat(const DateFormat
& other
)
57 fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE
)
62 //----------------------------------------------------------------------
64 DateFormat
& DateFormat::operator=(const DateFormat
& other
)
71 fCalendar
= other
.fCalendar
->clone();
75 if(other
.fNumberFormat
) {
76 fNumberFormat
= (NumberFormat
*)other
.fNumberFormat
->clone();
80 fBoolFlags
= other
.fBoolFlags
;
81 fCapitalizationContext
= other
.fCapitalizationContext
;
86 //----------------------------------------------------------------------
88 DateFormat::~DateFormat()
94 //----------------------------------------------------------------------
97 DateFormat::operator==(const Format
& other
) const
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.
103 // Format::operator== guarantees that this cast is safe
104 DateFormat
* fmt
= (DateFormat
*)&other
;
106 return (this == fmt
) ||
107 (Format::operator==(other
) &&
108 fCalendar
&&(fCalendar
->isEquivalentTo(*fmt
->fCalendar
)) &&
109 (fNumberFormat
&& *fNumberFormat
== *fmt
->fNumberFormat
) &&
110 (fCapitalizationContext
== fmt
->fCapitalizationContext
) );
113 //----------------------------------------------------------------------
116 DateFormat::format(const Formattable
& obj
,
117 UnicodeString
& appendTo
,
118 FieldPosition
& fieldPosition
,
119 UErrorCode
& status
) const
121 if (U_FAILURE(status
)) return appendTo
;
123 // if the type of the Formattable is double or long, treat it as if it were a Date
125 switch (obj
.getType())
127 case Formattable::kDate
:
128 date
= obj
.getDate();
130 case Formattable::kDouble
:
131 date
= (UDate
)obj
.getDouble();
133 case Formattable::kLong
:
134 date
= (UDate
)obj
.getLong();
137 status
= U_ILLEGAL_ARGUMENT_ERROR
;
142 //if (fieldPosition.getBeginIndex() == fieldPosition.getEndIndex())
143 // status = U_ILLEGAL_ARGUMENT_ERROR;
145 return format(date
, appendTo
, fieldPosition
);
148 //----------------------------------------------------------------------
151 DateFormat::format(const Formattable
& obj
,
152 UnicodeString
& appendTo
,
153 FieldPositionIterator
* posIter
,
154 UErrorCode
& status
) const
156 if (U_FAILURE(status
)) return appendTo
;
158 // if the type of the Formattable is double or long, treat it as if it were a Date
160 switch (obj
.getType())
162 case Formattable::kDate
:
163 date
= obj
.getDate();
165 case Formattable::kDouble
:
166 date
= (UDate
)obj
.getDouble();
168 case Formattable::kLong
:
169 date
= (UDate
)obj
.getLong();
172 status
= U_ILLEGAL_ARGUMENT_ERROR
;
177 //if (fieldPosition.getBeginIndex() == fieldPosition.getEndIndex())
178 // status = U_ILLEGAL_ARGUMENT_ERROR;
180 return format(date
, appendTo
, posIter
, status
);
183 //----------------------------------------------------------------------
185 // Default implementation for backwards compatibility, subclasses should implement.
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
;
197 //----------------------------------------------------------------------
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
);
208 format(*calClone
, appendTo
, fieldPosition
);
216 //----------------------------------------------------------------------
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
);
234 //----------------------------------------------------------------------
237 DateFormat::format(UDate date
, UnicodeString
& appendTo
) const
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
);
245 //----------------------------------------------------------------------
248 DateFormat::parse(const UnicodeString
& text
,
249 ParsePosition
& pos
) const
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();
257 parse(text
, *calClone
, pos
);
258 if (pos
.getIndex() != start
) {
259 UErrorCode ec
= U_ZERO_ERROR
;
260 d
= calClone
->getTime(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.
266 pos
.setErrorIndex(start
);
276 //----------------------------------------------------------------------
279 DateFormat::parse(const UnicodeString
& text
,
280 UErrorCode
& status
) const
282 if (U_FAILURE(status
)) return 0;
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() );
291 status
= U_ILLEGAL_ARGUMENT_ERROR
;
296 //----------------------------------------------------------------------
299 DateFormat::parseObject(const UnicodeString
& source
,
301 ParsePosition
& pos
) const
303 result
.setDate(parse(source
, pos
));
306 //----------------------------------------------------------------------
308 DateFormat
* U_EXPORT2
309 DateFormat::createTimeInstance(DateFormat::EStyle style
,
310 const Locale
& aLocale
)
312 return createDateTimeInstance(kNone
, style
, aLocale
);
315 //----------------------------------------------------------------------
317 DateFormat
* U_EXPORT2
318 DateFormat::createDateInstance(DateFormat::EStyle style
,
319 const Locale
& aLocale
)
321 return createDateTimeInstance(style
, kNone
, aLocale
);
324 //----------------------------------------------------------------------
326 DateFormat
* U_EXPORT2
327 DateFormat::createDateTimeInstance(EStyle dateStyle
,
329 const Locale
& aLocale
)
331 if(dateStyle
!= kNone
)
333 dateStyle
= (EStyle
) (dateStyle
+ kDateOffset
);
335 return create(timeStyle
, dateStyle
, aLocale
);
338 //----------------------------------------------------------------------
340 DateFormat
* U_EXPORT2
341 DateFormat::createInstance()
343 return createDateTimeInstance(kShort
, kShort
, Locale::getDefault());
346 //----------------------------------------------------------------------
348 DateFormat
* U_EXPORT2
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
)) {
358 if (calendar
.isNull()) {
359 status
= U_ILLEGAL_ARGUMENT_ERROR
;
362 DateFormat
*result
= createInstanceForSkeleton(skeleton
, locale
, status
);
363 if (U_FAILURE(status
)) {
366 result
->adoptCalendar(calendar
.orphan());
370 DateFormat
* U_EXPORT2
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
)) {
380 return internalCreateInstanceForSkeleton(
381 skeleton
, locale
, *gen
, status
);
384 DateFormat
* U_EXPORT2
385 DateFormat::createInstanceForSkeleton(
386 const UnicodeString
& skeleton
,
387 UErrorCode
&status
) {
388 return createInstanceForSkeleton(
389 skeleton
, Locale::getDefault(), status
);
392 DateFormat
* U_EXPORT2
393 DateFormat::internalCreateInstanceForSkeleton(
394 const UnicodeString
& skeleton
,
395 const Locale
&locale
,
396 DateTimePatternGenerator
&gen
,
397 UErrorCode
&status
) {
398 if (U_FAILURE(status
)) {
401 DateFormat
*fmt
= new SimpleDateFormat(
402 gen
.getBestPattern(skeleton
, status
),
406 status
= U_MEMORY_ALLOCATION_ERROR
;
409 if (U_FAILURE(status
)) {
416 //----------------------------------------------------------------------
418 DateFormat
* U_EXPORT2
419 DateFormat::create(EStyle timeStyle
, EStyle dateStyle
, const Locale
& locale
)
421 UErrorCode status
= U_ZERO_ERROR
;
422 #if U_PLATFORM_HAS_WIN32_API
424 int32_t count
= locale
.getKeywordValue("compat", buffer
, sizeof(buffer
), status
);
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
);
430 if (U_SUCCESS(status
)) {
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
;
443 status
= U_ZERO_ERROR
;
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
;
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
;
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.
464 //----------------------------------------------------------------------
466 const Locale
* U_EXPORT2
467 DateFormat::getAvailableLocales(int32_t& count
)
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
);
475 //----------------------------------------------------------------------
478 DateFormat::adoptCalendar(Calendar
* newCalendar
)
481 fCalendar
= newCalendar
;
484 //----------------------------------------------------------------------
486 DateFormat::setCalendar(const Calendar
& newCalendar
)
488 Calendar
* newCalClone
= newCalendar
.clone();
489 if (newCalClone
!= NULL
) {
490 adoptCalendar(newCalClone
);
494 //----------------------------------------------------------------------
497 DateFormat::getCalendar() const
502 //----------------------------------------------------------------------
505 DateFormat::adoptNumberFormat(NumberFormat
* newNumberFormat
)
507 delete fNumberFormat
;
508 fNumberFormat
= newNumberFormat
;
509 newNumberFormat
->setParseIntegerOnly(TRUE
);
511 //----------------------------------------------------------------------
514 DateFormat::setNumberFormat(const NumberFormat
& newNumberFormat
)
516 NumberFormat
* newNumFmtClone
= (NumberFormat
*)newNumberFormat
.clone();
517 if (newNumFmtClone
!= NULL
) {
518 adoptNumberFormat(newNumFmtClone
);
522 //----------------------------------------------------------------------
525 DateFormat::getNumberFormat() const
527 return fNumberFormat
;
530 //----------------------------------------------------------------------
533 DateFormat::adoptTimeZone(TimeZone
* zone
)
535 if (fCalendar
!= NULL
) {
536 fCalendar
->adoptTimeZone(zone
);
539 //----------------------------------------------------------------------
542 DateFormat::setTimeZone(const TimeZone
& zone
)
544 if (fCalendar
!= NULL
) {
545 fCalendar
->setTimeZone(zone
);
549 //----------------------------------------------------------------------
552 DateFormat::getTimeZone() const
554 if (fCalendar
!= NULL
) {
555 return fCalendar
->getTimeZone();
557 // If calendar doesn't exists, create default timezone.
558 // fCalendar is rarely null
559 return *(TimeZone::createDefault());
562 //----------------------------------------------------------------------
565 DateFormat::setLenient(UBool lenient
)
567 if (fCalendar
!= NULL
) {
568 fCalendar
->setLenient(lenient
);
570 UErrorCode status
= U_ZERO_ERROR
;
571 setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE
, lenient
, status
);
572 setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC
, lenient
, status
);
575 //----------------------------------------------------------------------
578 DateFormat::isLenient() const
580 UBool lenient
= TRUE
;
581 if (fCalendar
!= NULL
) {
582 lenient
= fCalendar
->isLenient();
584 UErrorCode status
= U_ZERO_ERROR
;
586 && getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE
, status
)
587 && getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC
, status
);
591 DateFormat::setCalendarLenient(UBool lenient
)
593 if (fCalendar
!= NULL
) {
594 fCalendar
->setLenient(lenient
);
598 //----------------------------------------------------------------------
601 DateFormat::isCalendarLenient() const
603 if (fCalendar
!= NULL
) {
604 return fCalendar
->isLenient();
606 // fCalendar is rarely null
611 //----------------------------------------------------------------------
614 void DateFormat::setContext(UDisplayContext value
, UErrorCode
& status
)
616 if (U_FAILURE(status
))
618 if ( (UDisplayContextType
)((uint32_t)value
>> 8) == UDISPCTX_TYPE_CAPITALIZATION
) {
619 fCapitalizationContext
= value
;
621 status
= U_ILLEGAL_ARGUMENT_ERROR
;
626 //----------------------------------------------------------------------
629 UDisplayContext
DateFormat::getContext(UDisplayContextType type
, UErrorCode
& status
) const
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;
637 return fCapitalizationContext
;
641 //----------------------------------------------------------------------
645 DateFormat::setBooleanAttribute(UDateFormatBooleanAttribute attr
,
647 UErrorCode
&status
) {
648 if(!fBoolFlags
.isValidValue(newValue
)) {
649 status
= U_ILLEGAL_ARGUMENT_ERROR
;
651 fBoolFlags
.set(attr
, newValue
);
657 //----------------------------------------------------------------------
660 DateFormat::getBooleanAttribute(UDateFormatBooleanAttribute attr
, UErrorCode
&/*status*/) const {
662 return fBoolFlags
.get(attr
);
667 #endif /* #if !UCONFIG_NO_FORMATTING */