• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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     }
78     return *this;
79 }
80 
81 //----------------------------------------------------------------------
82 
~DateFormat()83 DateFormat::~DateFormat()
84 {
85     delete fCalendar;
86     delete fNumberFormat;
87 }
88 
89 //----------------------------------------------------------------------
90 
91 UBool
operator ==(const Format & other) const92 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&
format(const Formattable & obj,UnicodeString & appendTo,FieldPosition & fieldPosition,UErrorCode & status) const110 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&
format(const Formattable & obj,UnicodeString & appendTo,FieldPositionIterator * posIter,UErrorCode & status) const145 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&
format(Calendar &,UnicodeString & appendTo,FieldPositionIterator *,UErrorCode & status) const181 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&
format(UDate date,UnicodeString & appendTo,FieldPosition & fieldPosition) const194 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&
format(UDate date,UnicodeString & appendTo,FieldPositionIterator * posIter,UErrorCode & status) const213 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&
format(UDate date,UnicodeString & appendTo) const231 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
parse(const UnicodeString & text,ParsePosition & pos) const242 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
parse(const UnicodeString & text,UErrorCode & status) const273 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
parseObject(const UnicodeString & source,Formattable & result,ParsePosition & pos) const293 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
createTimeInstance(DateFormat::EStyle style,const Locale & aLocale)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
createDateInstance(DateFormat::EStyle style,const Locale & aLocale)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
createDateTimeInstance(EStyle dateStyle,EStyle timeStyle,const Locale & aLocale)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
createInstance()341 DateFormat::createInstance()
342 {
343     return create(kShort, (EStyle) (kShort + kDateOffset), Locale::getDefault());
344 }
345 
346 //----------------------------------------------------------------------
347 
348 DateFormat* U_EXPORT2
create(EStyle timeStyle,EStyle dateStyle,const Locale & locale)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
getAvailableLocales(int32_t & count)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
adoptCalendar(Calendar * newCalendar)408 DateFormat::adoptCalendar(Calendar* newCalendar)
409 {
410     delete fCalendar;
411     fCalendar = newCalendar;
412 }
413 
414 //----------------------------------------------------------------------
415 void
setCalendar(const Calendar & newCalendar)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*
getCalendar() const427 DateFormat::getCalendar() const
428 {
429     return fCalendar;
430 }
431 
432 //----------------------------------------------------------------------
433 
434 void
adoptNumberFormat(NumberFormat * newNumberFormat)435 DateFormat::adoptNumberFormat(NumberFormat* newNumberFormat)
436 {
437     delete fNumberFormat;
438     fNumberFormat = newNumberFormat;
439     newNumberFormat->setParseIntegerOnly(TRUE);
440 }
441 //----------------------------------------------------------------------
442 
443 void
setNumberFormat(const NumberFormat & newNumberFormat)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*
getNumberFormat() const455 DateFormat::getNumberFormat() const
456 {
457     return fNumberFormat;
458 }
459 
460 //----------------------------------------------------------------------
461 
462 void
adoptTimeZone(TimeZone * zone)463 DateFormat::adoptTimeZone(TimeZone* zone)
464 {
465     if (fCalendar != NULL) {
466         fCalendar->adoptTimeZone(zone);
467     }
468 }
469 //----------------------------------------------------------------------
470 
471 void
setTimeZone(const TimeZone & zone)472 DateFormat::setTimeZone(const TimeZone& zone)
473 {
474     if (fCalendar != NULL) {
475         fCalendar->setTimeZone(zone);
476     }
477 }
478 
479 //----------------------------------------------------------------------
480 
481 const TimeZone&
getTimeZone() const482 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
setLenient(UBool lenient)495 DateFormat::setLenient(UBool lenient)
496 {
497     if (fCalendar != NULL) {
498         fCalendar->setLenient(lenient);
499     }
500 }
501 
502 //----------------------------------------------------------------------
503 
504 UBool
isLenient() const505 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