Home | History | Annotate | Download | only in i18n
      1 /*
      2  *******************************************************************************
      3  * Copyright (C) 1997-2010, 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 our calendar instance
    197         UErrorCode ec = U_ZERO_ERROR;
    198         fCalendar->setTime(date, ec);
    199         if (U_SUCCESS(ec)) {
    200             return format(*fCalendar, appendTo, fieldPosition);
    201         }
    202     }
    203     return appendTo;
    204 }
    205 
    206 //----------------------------------------------------------------------
    207 
    208 UnicodeString&
    209 DateFormat::format(UDate date, UnicodeString& appendTo, FieldPositionIterator* posIter,
    210                    UErrorCode& status) const {
    211     if (fCalendar != NULL) {
    212         fCalendar->setTime(date, status);
    213         if (U_SUCCESS(status)) {
    214             return format(*fCalendar, appendTo, posIter, status);
    215         }
    216     }
    217     return appendTo;
    218 }
    219 
    220 //----------------------------------------------------------------------
    221 
    222 UnicodeString&
    223 DateFormat::format(UDate date, UnicodeString& appendTo) const
    224 {
    225     // Note that any error information is just lost.  That's okay
    226     // for this convenience method.
    227     FieldPosition fpos(0);
    228     return format(date, appendTo, fpos);
    229 }
    230 
    231 //----------------------------------------------------------------------
    232 
    233 UDate
    234 DateFormat::parse(const UnicodeString& text,
    235                   ParsePosition& pos) const
    236 {
    237     UDate d = 0; // Error return UDate is 0 (the epoch)
    238     if (fCalendar != NULL) {
    239         int32_t start = pos.getIndex();
    240 
    241         // Parse may update TimeZone used by the calendar.
    242         TimeZone *tzsav = (TimeZone*)fCalendar->getTimeZone().clone();
    243 
    244         fCalendar->clear();
    245         parse(text, *fCalendar, pos);
    246         if (pos.getIndex() != start) {
    247             UErrorCode ec = U_ZERO_ERROR;
    248             d = fCalendar->getTime(ec);
    249             if (U_FAILURE(ec)) {
    250                 // We arrive here if fCalendar is non-lenient and there
    251                 // is an out-of-range field.  We don't know which field
    252                 // was illegal so we set the error index to the start.
    253                 pos.setIndex(start);
    254                 pos.setErrorIndex(start);
    255                 d = 0;
    256             }
    257         }
    258 
    259         // Restore TimeZone
    260         fCalendar->adoptTimeZone(tzsav);
    261     }
    262     return d;
    263 }
    264 
    265 //----------------------------------------------------------------------
    266 
    267 UDate
    268 DateFormat::parse(const UnicodeString& text,
    269                   UErrorCode& status) const
    270 {
    271     if (U_FAILURE(status)) return 0;
    272 
    273     ParsePosition pos(0);
    274     UDate result = parse(text, pos);
    275     if (pos.getIndex() == 0) {
    276 #if defined (U_DEBUG_CAL)
    277       fprintf(stderr, "%s:%d - - failed to parse  - err index %d\n"
    278               , __FILE__, __LINE__, pos.getErrorIndex() );
    279 #endif
    280       status = U_ILLEGAL_ARGUMENT_ERROR;
    281     }
    282     return result;
    283 }
    284 
    285 //----------------------------------------------------------------------
    286 
    287 void
    288 DateFormat::parseObject(const UnicodeString& source,
    289                         Formattable& result,
    290                         ParsePosition& pos) const
    291 {
    292     result.setDate(parse(source, pos));
    293 }
    294 
    295 //----------------------------------------------------------------------
    296 
    297 DateFormat* U_EXPORT2
    298 DateFormat::createTimeInstance(DateFormat::EStyle style,
    299                                const Locale& aLocale)
    300 {
    301     return create(style, kNone, aLocale);
    302 }
    303 
    304 //----------------------------------------------------------------------
    305 
    306 DateFormat* U_EXPORT2
    307 DateFormat::createDateInstance(DateFormat::EStyle style,
    308                                const Locale& aLocale)
    309 {
    310     // +4 to set the correct index for getting data out of
    311     // LocaleElements.
    312     if(style != kNone)
    313     {
    314         style = (EStyle) (style + kDateOffset);
    315     }
    316     return create(kNone, (EStyle) (style), aLocale);
    317 }
    318 
    319 //----------------------------------------------------------------------
    320 
    321 DateFormat* U_EXPORT2
    322 DateFormat::createDateTimeInstance(EStyle dateStyle,
    323                                    EStyle timeStyle,
    324                                    const Locale& aLocale)
    325 {
    326     if(dateStyle != kNone)
    327     {
    328         dateStyle = (EStyle) (dateStyle + kDateOffset);
    329     }
    330     return create(timeStyle, dateStyle, aLocale);
    331 }
    332 
    333 //----------------------------------------------------------------------
    334 
    335 DateFormat* U_EXPORT2
    336 DateFormat::createInstance()
    337 {
    338     return create(kShort, (EStyle) (kShort + kDateOffset), Locale::getDefault());
    339 }
    340 
    341 //----------------------------------------------------------------------
    342 
    343 DateFormat* U_EXPORT2
    344 DateFormat::create(EStyle timeStyle, EStyle dateStyle, const Locale& locale)
    345 {
    346     UErrorCode status = U_ZERO_ERROR;
    347 #ifdef U_WINDOWS
    348     char buffer[8];
    349     int32_t count = locale.getKeywordValue("compat", buffer, sizeof(buffer), status);
    350 
    351     // if the locale has "@compat=host", create a host-specific DateFormat...
    352     if (count > 0 && uprv_strcmp(buffer, "host") == 0) {
    353         Win32DateFormat *f = new Win32DateFormat(timeStyle, dateStyle, locale, status);
    354 
    355         if (U_SUCCESS(status)) {
    356             return f;
    357         }
    358 
    359         delete f;
    360     }
    361 #endif
    362 
    363     // is it relative?
    364     if(/*((timeStyle!=UDAT_NONE)&&(timeStyle & UDAT_RELATIVE)) || */((dateStyle!=kNone)&&((dateStyle-kDateOffset) & UDAT_RELATIVE))) {
    365         RelativeDateFormat *r = new RelativeDateFormat((UDateFormatStyle)timeStyle, (UDateFormatStyle)(dateStyle-kDateOffset), locale, status);
    366         if(U_SUCCESS(status)) return r;
    367         delete r;
    368         status = U_ZERO_ERROR;
    369     }
    370 
    371     // Try to create a SimpleDateFormat of the desired style.
    372     SimpleDateFormat *f = new SimpleDateFormat(timeStyle, dateStyle, locale, status);
    373     if (U_SUCCESS(status)) return f;
    374     delete f;
    375 
    376     // If that fails, try to create a format using the default pattern and
    377     // the DateFormatSymbols for this locale.
    378     status = U_ZERO_ERROR;
    379     f = new SimpleDateFormat(locale, status);
    380     if (U_SUCCESS(status)) return f;
    381     delete f;
    382 
    383     // This should never really happen, because the preceding constructor
    384     // should always succeed.  If the resource data is unavailable, a last
    385     // resort object should be returned.
    386     return 0;
    387 }
    388 
    389 //----------------------------------------------------------------------
    390 
    391 const Locale* U_EXPORT2
    392 DateFormat::getAvailableLocales(int32_t& count)
    393 {
    394     // Get the list of installed locales.
    395     // Even if root has the correct date format for this locale,
    396     // it's still a valid locale (we don't worry about data fallbacks).
    397     return Locale::getAvailableLocales(count);
    398 }
    399 
    400 //----------------------------------------------------------------------
    401 
    402 void
    403 DateFormat::adoptCalendar(Calendar* newCalendar)
    404 {
    405     delete fCalendar;
    406     fCalendar = newCalendar;
    407 }
    408 
    409 //----------------------------------------------------------------------
    410 void
    411 DateFormat::setCalendar(const Calendar& newCalendar)
    412 {
    413     Calendar* newCalClone = newCalendar.clone();
    414     if (newCalClone != NULL) {
    415         adoptCalendar(newCalClone);
    416     }
    417 }
    418 
    419 //----------------------------------------------------------------------
    420 
    421 const Calendar*
    422 DateFormat::getCalendar() const
    423 {
    424     return fCalendar;
    425 }
    426 
    427 //----------------------------------------------------------------------
    428 
    429 void
    430 DateFormat::adoptNumberFormat(NumberFormat* newNumberFormat)
    431 {
    432     delete fNumberFormat;
    433     fNumberFormat = newNumberFormat;
    434     newNumberFormat->setParseIntegerOnly(TRUE);
    435 }
    436 //----------------------------------------------------------------------
    437 
    438 void
    439 DateFormat::setNumberFormat(const NumberFormat& newNumberFormat)
    440 {
    441     NumberFormat* newNumFmtClone = (NumberFormat*)newNumberFormat.clone();
    442     if (newNumFmtClone != NULL) {
    443         adoptNumberFormat(newNumFmtClone);
    444     }
    445 }
    446 
    447 //----------------------------------------------------------------------
    448 
    449 const NumberFormat*
    450 DateFormat::getNumberFormat() const
    451 {
    452     return fNumberFormat;
    453 }
    454 
    455 //----------------------------------------------------------------------
    456 
    457 void
    458 DateFormat::adoptTimeZone(TimeZone* zone)
    459 {
    460     if (fCalendar != NULL) {
    461         fCalendar->adoptTimeZone(zone);
    462     }
    463 }
    464 //----------------------------------------------------------------------
    465 
    466 void
    467 DateFormat::setTimeZone(const TimeZone& zone)
    468 {
    469     if (fCalendar != NULL) {
    470         fCalendar->setTimeZone(zone);
    471     }
    472 }
    473 
    474 //----------------------------------------------------------------------
    475 
    476 const TimeZone&
    477 DateFormat::getTimeZone() const
    478 {
    479     if (fCalendar != NULL) {
    480         return fCalendar->getTimeZone();
    481     }
    482     // If calendar doesn't exists, create default timezone.
    483     // fCalendar is rarely null
    484     return *(TimeZone::createDefault());
    485 }
    486 
    487 //----------------------------------------------------------------------
    488 
    489 void
    490 DateFormat::setLenient(UBool lenient)
    491 {
    492     if (fCalendar != NULL) {
    493         fCalendar->setLenient(lenient);
    494     }
    495 }
    496 
    497 //----------------------------------------------------------------------
    498 
    499 UBool
    500 DateFormat::isLenient() const
    501 {
    502     if (fCalendar != NULL) {
    503         return fCalendar->isLenient();
    504     }
    505     // fCalendar is rarely null
    506     return FALSE;
    507 }
    508 
    509 U_NAMESPACE_END
    510 
    511 #endif /* #if !UCONFIG_NO_FORMATTING */
    512 
    513 //eof
    514