]> git.saurik.com Git - apple/icu.git/blob - icuSources/i18n/datefmt.cpp
ICU-461.12.tar.gz
[apple/icu.git] / icuSources / i18n / datefmt.cpp
1 /*
2 *******************************************************************************
3 * Copyright (C) 1997-2010, 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
43 DateFormat::DateFormat()
44 : fCalendar(0),
45 fNumberFormat(0)
46 {
47 }
48
49 //----------------------------------------------------------------------
50
51 DateFormat::DateFormat(const DateFormat& other)
52 : Format(other),
53 fCalendar(0),
54 fNumberFormat(0)
55 {
56 *this = other;
57 }
58
59 //----------------------------------------------------------------------
60
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
83 DateFormat::~DateFormat()
84 {
85 delete fCalendar;
86 delete fNumberFormat;
87 }
88
89 //----------------------------------------------------------------------
90
91 UBool
92 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&
110 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&
145 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&
181 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&
194 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&
209 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&
223 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
234 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
268 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
288 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
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
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
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
336 DateFormat::createInstance()
337 {
338 return create(kShort, (EStyle) (kShort + kDateOffset), Locale::getDefault());
339 }
340
341 //----------------------------------------------------------------------
342
343 DateFormat* U_EXPORT2
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
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
403 DateFormat::adoptCalendar(Calendar* newCalendar)
404 {
405 delete fCalendar;
406 fCalendar = newCalendar;
407 }
408
409 //----------------------------------------------------------------------
410 void
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*
422 DateFormat::getCalendar() const
423 {
424 return fCalendar;
425 }
426
427 //----------------------------------------------------------------------
428
429 void
430 DateFormat::adoptNumberFormat(NumberFormat* newNumberFormat)
431 {
432 delete fNumberFormat;
433 fNumberFormat = newNumberFormat;
434 newNumberFormat->setParseIntegerOnly(TRUE);
435 }
436 //----------------------------------------------------------------------
437
438 void
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*
450 DateFormat::getNumberFormat() const
451 {
452 return fNumberFormat;
453 }
454
455 //----------------------------------------------------------------------
456
457 void
458 DateFormat::adoptTimeZone(TimeZone* zone)
459 {
460 if (fCalendar != NULL) {
461 fCalendar->adoptTimeZone(zone);
462 }
463 }
464 //----------------------------------------------------------------------
465
466 void
467 DateFormat::setTimeZone(const TimeZone& zone)
468 {
469 if (fCalendar != NULL) {
470 fCalendar->setTimeZone(zone);
471 }
472 }
473
474 //----------------------------------------------------------------------
475
476 const TimeZone&
477 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
490 DateFormat::setLenient(UBool lenient)
491 {
492 if (fCalendar != NULL) {
493 fCalendar->setLenient(lenient);
494 }
495 }
496
497 //----------------------------------------------------------------------
498
499 UBool
500 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