• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
DateFormat()43 DateFormat::DateFormat()
44 :   fCalendar(0),
45     fNumberFormat(0)
46 {
47 }
48 
49 //----------------------------------------------------------------------
50 
DateFormat(const DateFormat & other)51 DateFormat::DateFormat(const DateFormat& other)
52 :   Format(other),
53     fCalendar(0),
54     fNumberFormat(0)
55 {
56     *this = other;
57 }
58 
59 //----------------------------------------------------------------------
60 
operator =(const DateFormat & other)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 
~DateFormat()84 DateFormat::~DateFormat()
85 {
86     delete fCalendar;
87     delete fNumberFormat;
88 }
89 
90 //----------------------------------------------------------------------
91 
92 UBool
operator ==(const Format & other) const93 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&
format(const Formattable & obj,UnicodeString & appendTo,FieldPosition & fieldPosition,UErrorCode & status) const111 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&
format(const Formattable & obj,UnicodeString & appendTo,FieldPositionIterator * posIter,UErrorCode & status) const146 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&
format(Calendar &,UnicodeString & appendTo,FieldPositionIterator *,UErrorCode & status) const182 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&
format(UDate date,UnicodeString & appendTo,FieldPosition & fieldPosition) const195 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&
format(UDate date,UnicodeString & appendTo,FieldPositionIterator * posIter,UErrorCode & status) const214 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&
format(UDate date,UnicodeString & appendTo) const232 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
parse(const UnicodeString & text,ParsePosition & pos) const243 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
parse(const UnicodeString & text,UErrorCode & status) const274 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
parseObject(const UnicodeString & source,Formattable & result,ParsePosition & pos) const294 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
createTimeInstance(DateFormat::EStyle style,const Locale & aLocale)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
createDateInstance(DateFormat::EStyle style,const Locale & aLocale)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
createDateTimeInstance(EStyle dateStyle,EStyle timeStyle,const Locale & aLocale)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
createInstance()342 DateFormat::createInstance()
343 {
344     return create(kShort, (EStyle) (kShort + kDateOffset), Locale::getDefault());
345 }
346 
347 //----------------------------------------------------------------------
348 
349 DateFormat* U_EXPORT2
create(EStyle timeStyle,EStyle dateStyle,const Locale & locale)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
getAvailableLocales(int32_t & count)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
adoptCalendar(Calendar * newCalendar)409 DateFormat::adoptCalendar(Calendar* newCalendar)
410 {
411     delete fCalendar;
412     fCalendar = newCalendar;
413 }
414 
415 //----------------------------------------------------------------------
416 void
setCalendar(const Calendar & newCalendar)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*
getCalendar() const428 DateFormat::getCalendar() const
429 {
430     return fCalendar;
431 }
432 
433 //----------------------------------------------------------------------
434 
435 void
adoptNumberFormat(NumberFormat * newNumberFormat)436 DateFormat::adoptNumberFormat(NumberFormat* newNumberFormat)
437 {
438     delete fNumberFormat;
439     fNumberFormat = newNumberFormat;
440     newNumberFormat->setParseIntegerOnly(TRUE);
441 }
442 //----------------------------------------------------------------------
443 
444 void
setNumberFormat(const NumberFormat & newNumberFormat)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*
getNumberFormat() const456 DateFormat::getNumberFormat() const
457 {
458     return fNumberFormat;
459 }
460 
461 //----------------------------------------------------------------------
462 
463 void
adoptTimeZone(TimeZone * zone)464 DateFormat::adoptTimeZone(TimeZone* zone)
465 {
466     if (fCalendar != NULL) {
467         fCalendar->adoptTimeZone(zone);
468     }
469 }
470 //----------------------------------------------------------------------
471 
472 void
setTimeZone(const TimeZone & zone)473 DateFormat::setTimeZone(const TimeZone& zone)
474 {
475     if (fCalendar != NULL) {
476         fCalendar->setTimeZone(zone);
477     }
478 }
479 
480 //----------------------------------------------------------------------
481 
482 const TimeZone&
getTimeZone() const483 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
setLenient(UBool lenient)496 DateFormat::setLenient(UBool lenient)
497 {
498     if (fCalendar != NULL) {
499         fCalendar->setLenient(lenient);
500     }
501 }
502 
503 //----------------------------------------------------------------------
504 
505 UBool
isLenient() const506 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&
setBooleanAttribute(UDateFormatBooleanAttribute attr,UBool newValue,UErrorCode & status)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
getBooleanAttribute(UDateFormatBooleanAttribute attr,UErrorCode &) const533 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