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