Home | History | Annotate | Download | only in i18n
      1 /*
      2  *******************************************************************************
      3  * Copyright (C) 1997-2013, 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 "reldtfmt.h"
     29 
     30 #include "cstring.h"
     31 #include "windtfmt.h"
     32 
     33 #if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
     34 #include <stdio.h>
     35 #endif
     36 
     37 // *****************************************************************************
     38 // class DateFormat
     39 // *****************************************************************************
     40 
     41 U_NAMESPACE_BEGIN
     42 
     43 DateFormat::DateFormat()
     44 :   fCalendar(0),
     45     fNumberFormat(0)
     46 {
     47 }
     48 
     49 //----------------------------------------------------------------------
     50 
     51 DateFormat::DateFormat(const DateFormat& other)
     52 :   Format(other),
     53     fCalendar(0),
     54     fNumberFormat(0)
     55 {
     56     *this = other;
     57 }
     58 
     59 //----------------------------------------------------------------------
     60 
     61 DateFormat& DateFormat::operator=(const DateFormat& other)
     62 {
     63     if (this != &other)
     64     {
     65         delete fCalendar;
     66         delete fNumberFormat;
     67         if(other.fCalendar) {
     68           fCalendar = other.fCalendar->clone();
     69         } else {
     70           fCalendar = NULL;
     71         }
     72         if(other.fNumberFormat) {
     73           fNumberFormat = (NumberFormat*)other.fNumberFormat->clone();
     74         } else {
     75           fNumberFormat = NULL;
     76         }
     77         fBoolFlags = other.fBoolFlags;
     78     }
     79     return *this;
     80 }
     81 
     82 //----------------------------------------------------------------------
     83 
     84 DateFormat::~DateFormat()
     85 {
     86     delete fCalendar;
     87     delete fNumberFormat;
     88 }
     89 
     90 //----------------------------------------------------------------------
     91 
     92 UBool
     93 DateFormat::operator==(const Format& other) const
     94 {
     95     // This protected comparison operator should only be called by subclasses
     96     // which have confirmed that the other object being compared against is
     97     // an instance of a sublcass of DateFormat.  THIS IS IMPORTANT.
     98 
     99     // Format::operator== guarantees that this cast is safe
    100     DateFormat* fmt = (DateFormat*)&other;
    101 
    102     return (this == fmt) ||
    103         (Format::operator==(other) &&
    104          fCalendar&&(fCalendar->isEquivalentTo(*fmt->fCalendar)) &&
    105          (fNumberFormat && *fNumberFormat == *fmt->fNumberFormat));
    106 }
    107 
    108 //----------------------------------------------------------------------
    109 
    110 UnicodeString&
    111 DateFormat::format(const Formattable& obj,
    112                    UnicodeString& appendTo,
    113                    FieldPosition& fieldPosition,
    114                    UErrorCode& status) const
    115 {
    116     if (U_FAILURE(status)) return appendTo;
    117 
    118     // if the type of the Formattable is double or long, treat it as if it were a Date
    119     UDate date = 0;
    120     switch (obj.getType())
    121     {
    122     case Formattable::kDate:
    123         date = obj.getDate();
    124         break;
    125     case Formattable::kDouble:
    126         date = (UDate)obj.getDouble();
    127         break;
    128     case Formattable::kLong:
    129         date = (UDate)obj.getLong();
    130         break;
    131     default:
    132         status = U_ILLEGAL_ARGUMENT_ERROR;
    133         return appendTo;
    134     }
    135 
    136     // Is this right?
    137     //if (fieldPosition.getBeginIndex() == fieldPosition.getEndIndex())
    138     //  status = U_ILLEGAL_ARGUMENT_ERROR;
    139 
    140     return format(date, appendTo, fieldPosition);
    141 }
    142 
    143 //----------------------------------------------------------------------
    144 
    145 UnicodeString&
    146 DateFormat::format(const Formattable& obj,
    147                    UnicodeString& appendTo,
    148                    FieldPositionIterator* posIter,
    149                    UErrorCode& status) const
    150 {
    151     if (U_FAILURE(status)) return appendTo;
    152 
    153     // if the type of the Formattable is double or long, treat it as if it were a Date
    154     UDate date = 0;
    155     switch (obj.getType())
    156     {
    157     case Formattable::kDate:
    158         date = obj.getDate();
    159         break;
    160     case Formattable::kDouble:
    161         date = (UDate)obj.getDouble();
    162         break;
    163     case Formattable::kLong:
    164         date = (UDate)obj.getLong();
    165         break;
    166     default:
    167         status = U_ILLEGAL_ARGUMENT_ERROR;
    168         return appendTo;
    169     }
    170 
    171     // Is this right?
    172     //if (fieldPosition.getBeginIndex() == fieldPosition.getEndIndex())
    173     //  status = U_ILLEGAL_ARGUMENT_ERROR;
    174 
    175     return format(date, appendTo, posIter, status);
    176 }
    177 
    178 //----------------------------------------------------------------------
    179 
    180 // Default implementation for backwards compatibility, subclasses should implement.
    181 UnicodeString&
    182 DateFormat::format(Calendar& /* unused cal */,
    183                    UnicodeString& appendTo,
    184                    FieldPositionIterator* /* unused posIter */,
    185                    UErrorCode& status) const {
    186     if (U_SUCCESS(status)) {
    187         status = U_UNSUPPORTED_ERROR;
    188     }
    189     return appendTo;
    190 }
    191 
    192 //----------------------------------------------------------------------
    193 
    194 UnicodeString&
    195 DateFormat::format(UDate date, UnicodeString& appendTo, FieldPosition& fieldPosition) const {
    196     if (fCalendar != NULL) {
    197         // Use a clone of our calendar instance
    198         Calendar* calClone = fCalendar->clone();
    199         if (calClone != NULL) {
    200             UErrorCode ec = U_ZERO_ERROR;
    201             calClone->setTime(date, ec);
    202             if (U_SUCCESS(ec)) {
    203                 format(*calClone, appendTo, fieldPosition);
    204             }
    205             delete calClone;
    206         }
    207     }
    208     return appendTo;
    209 }
    210 
    211 //----------------------------------------------------------------------
    212 
    213 UnicodeString&
    214 DateFormat::format(UDate date, UnicodeString& appendTo, FieldPositionIterator* posIter,
    215                    UErrorCode& status) const {
    216     if (fCalendar != NULL) {
    217         Calendar* calClone = fCalendar->clone();
    218         if (calClone != NULL) {
    219             calClone->setTime(date, status);
    220             if (U_SUCCESS(status)) {
    221                format(*calClone, appendTo, posIter, status);
    222             }
    223             delete calClone;
    224         }
    225     }
    226     return appendTo;
    227 }
    228 
    229 //----------------------------------------------------------------------
    230 
    231 UnicodeString&
    232 DateFormat::format(UDate date, UnicodeString& appendTo) const
    233 {
    234     // Note that any error information is just lost.  That's okay
    235     // for this convenience method.
    236     FieldPosition fpos(0);
    237     return format(date, appendTo, fpos);
    238 }
    239 
    240 //----------------------------------------------------------------------
    241 
    242 UDate
    243 DateFormat::parse(const UnicodeString& text,
    244                   ParsePosition& pos) const
    245 {
    246     UDate d = 0; // Error return UDate is 0 (the epoch)
    247     if (fCalendar != NULL) {
    248         Calendar* calClone = fCalendar->clone();
    249         if (calClone != NULL) {
    250             int32_t start = pos.getIndex();
    251             calClone->clear();
    252             parse(text, *calClone, pos);
    253             if (pos.getIndex() != start) {
    254                 UErrorCode ec = U_ZERO_ERROR;
    255                 d = calClone->getTime(ec);
    256                 if (U_FAILURE(ec)) {
    257                     // We arrive here if fCalendar => calClone is non-lenient and
    258                     // there is an out-of-range field.  We don't know which field
    259                     // was illegal so we set the error index to the start.
    260                     pos.setIndex(start);
    261                     pos.setErrorIndex(start);
    262                     d = 0;
    263                 }
    264             }
    265             delete calClone;
    266         }
    267     }
    268     return d;
    269 }
    270 
    271 //----------------------------------------------------------------------
    272 
    273 UDate
    274 DateFormat::parse(const UnicodeString& text,
    275                   UErrorCode& status) const
    276 {
    277     if (U_FAILURE(status)) return 0;
    278 
    279     ParsePosition pos(0);
    280     UDate result = parse(text, pos);
    281     if (pos.getIndex() == 0) {
    282 #if defined (U_DEBUG_CAL)
    283       fprintf(stderr, "%s:%d - - failed to parse  - err index %d\n"
    284               , __FILE__, __LINE__, pos.getErrorIndex() );
    285 #endif
    286       status = U_ILLEGAL_ARGUMENT_ERROR;
    287     }
    288     return result;
    289 }
    290 
    291 //----------------------------------------------------------------------
    292 
    293 void
    294 DateFormat::parseObject(const UnicodeString& source,
    295                         Formattable& result,
    296                         ParsePosition& pos) const
    297 {
    298     result.setDate(parse(source, pos));
    299 }
    300 
    301 //----------------------------------------------------------------------
    302 
    303 DateFormat* U_EXPORT2
    304 DateFormat::createTimeInstance(DateFormat::EStyle style,
    305                                const Locale& aLocale)
    306 {
    307     return create(style, kNone, aLocale);
    308 }
    309 
    310 //----------------------------------------------------------------------
    311 
    312 DateFormat* U_EXPORT2
    313 DateFormat::createDateInstance(DateFormat::EStyle style,
    314                                const Locale& aLocale)
    315 {
    316     // +4 to set the correct index for getting data out of
    317     // LocaleElements.
    318     if(style != kNone)
    319     {
    320         style = (EStyle) (style + kDateOffset);
    321     }
    322     return create(kNone, (EStyle) (style), aLocale);
    323 }
    324 
    325 //----------------------------------------------------------------------
    326 
    327 DateFormat* U_EXPORT2
    328 DateFormat::createDateTimeInstance(EStyle dateStyle,
    329                                    EStyle timeStyle,
    330                                    const Locale& aLocale)
    331 {
    332     if(dateStyle != kNone)
    333     {
    334         dateStyle = (EStyle) (dateStyle + kDateOffset);
    335     }
    336     return create(timeStyle, dateStyle, aLocale);
    337 }
    338 
    339 //----------------------------------------------------------------------
    340 
    341 DateFormat* U_EXPORT2
    342 DateFormat::createInstance()
    343 {
    344     return create(kShort, (EStyle) (kShort + kDateOffset), Locale::getDefault());
    345 }
    346 
    347 //----------------------------------------------------------------------
    348 
    349 DateFormat* U_EXPORT2
    350 DateFormat::create(EStyle timeStyle, EStyle dateStyle, const Locale& locale)
    351 {
    352     UErrorCode status = U_ZERO_ERROR;
    353 #if U_PLATFORM_HAS_WIN32_API
    354     char buffer[8];
    355     int32_t count = locale.getKeywordValue("compat", buffer, sizeof(buffer), status);
    356 
    357     // if the locale has "@compat=host", create a host-specific DateFormat...
    358     if (count > 0 && uprv_strcmp(buffer, "host") == 0) {
    359         Win32DateFormat *f = new Win32DateFormat(timeStyle, dateStyle, locale, status);
    360 
    361         if (U_SUCCESS(status)) {
    362             return f;
    363         }
    364 
    365         delete f;
    366     }
    367 #endif
    368 
    369     // is it relative?
    370     if(/*((timeStyle!=UDAT_NONE)&&(timeStyle & UDAT_RELATIVE)) || */((dateStyle!=kNone)&&((dateStyle-kDateOffset) & UDAT_RELATIVE))) {
    371         RelativeDateFormat *r = new RelativeDateFormat((UDateFormatStyle)timeStyle, (UDateFormatStyle)(dateStyle-kDateOffset), locale, status);
    372         if(U_SUCCESS(status)) return r;
    373         delete r;
    374         status = U_ZERO_ERROR;
    375     }
    376 
    377     // Try to create a SimpleDateFormat of the desired style.
    378     SimpleDateFormat *f = new SimpleDateFormat(timeStyle, dateStyle, locale, status);
    379     if (U_SUCCESS(status)) return f;
    380     delete f;
    381 
    382     // If that fails, try to create a format using the default pattern and
    383     // the DateFormatSymbols for this locale.
    384     status = U_ZERO_ERROR;
    385     f = new SimpleDateFormat(locale, status);
    386     if (U_SUCCESS(status)) return f;
    387     delete f;
    388 
    389     // This should never really happen, because the preceding constructor
    390     // should always succeed.  If the resource data is unavailable, a last
    391     // resort object should be returned.
    392     return 0;
    393 }
    394 
    395 //----------------------------------------------------------------------
    396 
    397 const Locale* U_EXPORT2
    398 DateFormat::getAvailableLocales(int32_t& count)
    399 {
    400     // Get the list of installed locales.
    401     // Even if root has the correct date format for this locale,
    402     // it's still a valid locale (we don't worry about data fallbacks).
    403     return Locale::getAvailableLocales(count);
    404 }
    405 
    406 //----------------------------------------------------------------------
    407 
    408 void
    409 DateFormat::adoptCalendar(Calendar* newCalendar)
    410 {
    411     delete fCalendar;
    412     fCalendar = newCalendar;
    413 }
    414 
    415 //----------------------------------------------------------------------
    416 void
    417 DateFormat::setCalendar(const Calendar& newCalendar)
    418 {
    419     Calendar* newCalClone = newCalendar.clone();
    420     if (newCalClone != NULL) {
    421         adoptCalendar(newCalClone);
    422     }
    423 }
    424 
    425 //----------------------------------------------------------------------
    426 
    427 const Calendar*
    428 DateFormat::getCalendar() const
    429 {
    430     return fCalendar;
    431 }
    432 
    433 //----------------------------------------------------------------------
    434 
    435 void
    436 DateFormat::adoptNumberFormat(NumberFormat* newNumberFormat)
    437 {
    438     delete fNumberFormat;
    439     fNumberFormat = newNumberFormat;
    440     newNumberFormat->setParseIntegerOnly(TRUE);
    441 }
    442 //----------------------------------------------------------------------
    443 
    444 void
    445 DateFormat::setNumberFormat(const NumberFormat& newNumberFormat)
    446 {
    447     NumberFormat* newNumFmtClone = (NumberFormat*)newNumberFormat.clone();
    448     if (newNumFmtClone != NULL) {
    449         adoptNumberFormat(newNumFmtClone);
    450     }
    451 }
    452 
    453 //----------------------------------------------------------------------
    454 
    455 const NumberFormat*
    456 DateFormat::getNumberFormat() const
    457 {
    458     return fNumberFormat;
    459 }
    460 
    461 //----------------------------------------------------------------------
    462 
    463 void
    464 DateFormat::adoptTimeZone(TimeZone* zone)
    465 {
    466     if (fCalendar != NULL) {
    467         fCalendar->adoptTimeZone(zone);
    468     }
    469 }
    470 //----------------------------------------------------------------------
    471 
    472 void
    473 DateFormat::setTimeZone(const TimeZone& zone)
    474 {
    475     if (fCalendar != NULL) {
    476         fCalendar->setTimeZone(zone);
    477     }
    478 }
    479 
    480 //----------------------------------------------------------------------
    481 
    482 const TimeZone&
    483 DateFormat::getTimeZone() const
    484 {
    485     if (fCalendar != NULL) {
    486         return fCalendar->getTimeZone();
    487     }
    488     // If calendar doesn't exists, create default timezone.
    489     // fCalendar is rarely null
    490     return *(TimeZone::createDefault());
    491 }
    492 
    493 //----------------------------------------------------------------------
    494 
    495 void
    496 DateFormat::setLenient(UBool lenient)
    497 {
    498     if (fCalendar != NULL) {
    499         fCalendar->setLenient(lenient);
    500     }
    501 }
    502 
    503 //----------------------------------------------------------------------
    504 
    505 UBool
    506 DateFormat::isLenient() const
    507 {
    508     if (fCalendar != NULL) {
    509         return fCalendar->isLenient();
    510     }
    511     // fCalendar is rarely null
    512     return FALSE;
    513 }
    514 
    515 //----------------------------------------------------------------------
    516 
    517 DateFormat&
    518 DateFormat::setBooleanAttribute(UDateFormatBooleanAttribute attr,
    519     									UBool newValue,
    520     									UErrorCode &status) {
    521     if(!fBoolFlags.isValidValue(newValue)) {
    522         status = U_ILLEGAL_ARGUMENT_ERROR;
    523     } else {
    524         fBoolFlags.set(attr, newValue);
    525     }
    526 
    527     return *this;
    528 }
    529 
    530 //----------------------------------------------------------------------
    531 
    532 UBool
    533 DateFormat::getBooleanAttribute(UDateFormatBooleanAttribute attr, UErrorCode &/*status*/) const {
    534 
    535     return fBoolFlags.get(attr);
    536 }
    537 
    538 U_NAMESPACE_END
    539 
    540 #endif /* #if !UCONFIG_NO_FORMATTING */
    541 
    542 //eof
    543