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