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 createDateTimeInstance(kNone, style, aLocale);
    313 }
    314 
    315 //----------------------------------------------------------------------
    316 
    317 DateFormat* U_EXPORT2
    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
    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
    341 DateFormat::createInstance()
    342 {
    343     return createDateTimeInstance(kShort, kShort, Locale::getDefault());
    344 }
    345 
    346 //----------------------------------------------------------------------
    347 
    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)) {
    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
    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
    385 DateFormat::createInstanceForSkeleton(
    386         const UnicodeString& skeleton,
    387         UErrorCode &status) {
    388     return createInstanceForSkeleton(
    389             skeleton, Locale::getDefault(), status);
    390 }
    391 
    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)) {
    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
    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
    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
    478 DateFormat::adoptCalendar(Calendar* newCalendar)
    479 {
    480     delete fCalendar;
    481     fCalendar = newCalendar;
    482 }
    483 
    484 //----------------------------------------------------------------------
    485 void
    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*
    497 DateFormat::getCalendar() const
    498 {
    499     return fCalendar;
    500 }
    501 
    502 //----------------------------------------------------------------------
    503 
    504 void
    505 DateFormat::adoptNumberFormat(NumberFormat* newNumberFormat)
    506 {
    507     delete fNumberFormat;
    508     fNumberFormat = newNumberFormat;
    509     newNumberFormat->setParseIntegerOnly(TRUE);
    510 }
    511 //----------------------------------------------------------------------
    512 
    513 void
    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*
    525 DateFormat::getNumberFormat() const
    526 {
    527     return fNumberFormat;
    528 }
    529 
    530 //----------------------------------------------------------------------
    531 
    532 void
    533 DateFormat::adoptTimeZone(TimeZone* zone)
    534 {
    535     if (fCalendar != NULL) {
    536         fCalendar->adoptTimeZone(zone);
    537     }
    538 }
    539 //----------------------------------------------------------------------
    540 
    541 void
    542 DateFormat::setTimeZone(const TimeZone& zone)
    543 {
    544     if (fCalendar != NULL) {
    545         fCalendar->setTimeZone(zone);
    546     }
    547 }
    548 
    549 //----------------------------------------------------------------------
    550 
    551 const TimeZone&
    552 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
    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
    578 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
    591 DateFormat::setCalendarLenient(UBool lenient)
    592 {
    593     if (fCalendar != NULL) {
    594         fCalendar->setLenient(lenient);
    595     }
    596 }
    597 
    598 //----------------------------------------------------------------------
    599 
    600 UBool
    601 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 
    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 
    629 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&
    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
    660 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