• 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 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&
format(UDate date,UnicodeString & appendTo,FieldPositionIterator * posIter,UErrorCode & status) const209 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&
format(UDate date,UnicodeString & appendTo) const223 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
parse(const UnicodeString & text,ParsePosition & pos) const234 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
parse(const UnicodeString & text,UErrorCode & status) const268 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
parseObject(const UnicodeString & source,Formattable & result,ParsePosition & pos) const288 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
createTimeInstance(DateFormat::EStyle style,const Locale & aLocale)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
createDateInstance(DateFormat::EStyle style,const Locale & aLocale)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
createDateTimeInstance(EStyle dateStyle,EStyle timeStyle,const Locale & aLocale)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
createInstance()336 DateFormat::createInstance()
337 {
338     return create(kShort, (EStyle) (kShort + kDateOffset), Locale::getDefault());
339 }
340 
341 //----------------------------------------------------------------------
342 
343 DateFormat* U_EXPORT2
create(EStyle timeStyle,EStyle dateStyle,const Locale & locale)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
getAvailableLocales(int32_t & count)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
adoptCalendar(Calendar * newCalendar)403 DateFormat::adoptCalendar(Calendar* newCalendar)
404 {
405     delete fCalendar;
406     fCalendar = newCalendar;
407 }
408 
409 //----------------------------------------------------------------------
410 void
setCalendar(const Calendar & newCalendar)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*
getCalendar() const422 DateFormat::getCalendar() const
423 {
424     return fCalendar;
425 }
426 
427 //----------------------------------------------------------------------
428 
429 void
adoptNumberFormat(NumberFormat * newNumberFormat)430 DateFormat::adoptNumberFormat(NumberFormat* newNumberFormat)
431 {
432     delete fNumberFormat;
433     fNumberFormat = newNumberFormat;
434     newNumberFormat->setParseIntegerOnly(TRUE);
435 }
436 //----------------------------------------------------------------------
437 
438 void
setNumberFormat(const NumberFormat & newNumberFormat)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*
getNumberFormat() const450 DateFormat::getNumberFormat() const
451 {
452     return fNumberFormat;
453 }
454 
455 //----------------------------------------------------------------------
456 
457 void
adoptTimeZone(TimeZone * zone)458 DateFormat::adoptTimeZone(TimeZone* zone)
459 {
460     if (fCalendar != NULL) {
461         fCalendar->adoptTimeZone(zone);
462     }
463 }
464 //----------------------------------------------------------------------
465 
466 void
setTimeZone(const TimeZone & zone)467 DateFormat::setTimeZone(const TimeZone& zone)
468 {
469     if (fCalendar != NULL) {
470         fCalendar->setTimeZone(zone);
471     }
472 }
473 
474 //----------------------------------------------------------------------
475 
476 const TimeZone&
getTimeZone() const477 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
setLenient(UBool lenient)490 DateFormat::setLenient(UBool lenient)
491 {
492     if (fCalendar != NULL) {
493         fCalendar->setLenient(lenient);
494     }
495 }
496 
497 //----------------------------------------------------------------------
498 
499 UBool
isLenient() const500 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