Home | History | Annotate | Download | only in i18n
      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
    606