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