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