]> git.saurik.com Git - apple/icu.git/blob - icuSources/i18n/datefmt.cpp
ICU-400.42.tar.gz
[apple/icu.git] / icuSources / i18n / datefmt.cpp
1 /*
2 *******************************************************************************
3 * Copyright (C) 1997-2008, 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(UDate date, UnicodeString& appendTo, FieldPosition& fieldPosition) const {
146 if (fCalendar != NULL) {
147 // Use our calendar instance
148 UErrorCode ec = U_ZERO_ERROR;
149 fCalendar->setTime(date, ec);
150 if (U_SUCCESS(ec)) {
151 return format(*fCalendar, appendTo, fieldPosition);
152 }
153 }
154 return appendTo;
155 }
156
157 //----------------------------------------------------------------------
158
159 UnicodeString&
160 DateFormat::format(UDate date, UnicodeString& appendTo) const
161 {
162 // Note that any error information is just lost. That's okay
163 // for this convenience method.
164 FieldPosition fpos(0);
165 return format(date, appendTo, fpos);
166 }
167
168 //----------------------------------------------------------------------
169
170 UDate
171 DateFormat::parse(const UnicodeString& text,
172 ParsePosition& pos) const
173 {
174 UDate d = 0; // Error return UDate is 0 (the epoch)
175 if (fCalendar != NULL) {
176 int32_t start = pos.getIndex();
177
178 // Parse may update TimeZone used by the calendar.
179 TimeZone *tzsav = (TimeZone*)fCalendar->getTimeZone().clone();
180
181 fCalendar->clear();
182 parse(text, *fCalendar, pos);
183 if (pos.getIndex() != start) {
184 UErrorCode ec = U_ZERO_ERROR;
185 d = fCalendar->getTime(ec);
186 if (U_FAILURE(ec)) {
187 // We arrive here if fCalendar is non-lenient and there
188 // is an out-of-range field. We don't know which field
189 // was illegal so we set the error index to the start.
190 pos.setIndex(start);
191 pos.setErrorIndex(start);
192 d = 0;
193 }
194 }
195
196 // Restore TimeZone
197 fCalendar->adoptTimeZone(tzsav);
198 }
199 return d;
200 }
201
202 //----------------------------------------------------------------------
203
204 UDate
205 DateFormat::parse(const UnicodeString& text,
206 UErrorCode& status) const
207 {
208 if (U_FAILURE(status)) return 0;
209
210 ParsePosition pos(0);
211 UDate result = parse(text, pos);
212 if (pos.getIndex() == 0) {
213 #if defined (U_DEBUG_CAL)
214 fprintf(stderr, "%s:%d - - failed to parse - err index %d\n"
215 , __FILE__, __LINE__, pos.getErrorIndex() );
216 #endif
217 status = U_ILLEGAL_ARGUMENT_ERROR;
218 }
219 return result;
220 }
221
222 //----------------------------------------------------------------------
223
224 void
225 DateFormat::parseObject(const UnicodeString& source,
226 Formattable& result,
227 ParsePosition& pos) const
228 {
229 result.setDate(parse(source, pos));
230 }
231
232 //----------------------------------------------------------------------
233
234 DateFormat* U_EXPORT2
235 DateFormat::createTimeInstance(DateFormat::EStyle style,
236 const Locale& aLocale)
237 {
238 return create(style, kNone, aLocale);
239 }
240
241 //----------------------------------------------------------------------
242
243 DateFormat* U_EXPORT2
244 DateFormat::createDateInstance(DateFormat::EStyle style,
245 const Locale& aLocale)
246 {
247 // +4 to set the correct index for getting data out of
248 // LocaleElements.
249 if(style != kNone)
250 {
251 style = (EStyle) (style + kDateOffset);
252 }
253 return create(kNone, (EStyle) (style), aLocale);
254 }
255
256 //----------------------------------------------------------------------
257
258 DateFormat* U_EXPORT2
259 DateFormat::createDateTimeInstance(EStyle dateStyle,
260 EStyle timeStyle,
261 const Locale& aLocale)
262 {
263 if(dateStyle != kNone)
264 {
265 dateStyle = (EStyle) (dateStyle + kDateOffset);
266 }
267 return create(timeStyle, dateStyle, aLocale);
268 }
269
270 //----------------------------------------------------------------------
271
272 DateFormat* U_EXPORT2
273 DateFormat::createInstance()
274 {
275 return create(kShort, (EStyle) (kShort + kDateOffset), Locale::getDefault());
276 }
277
278 //----------------------------------------------------------------------
279 DateFormat* U_EXPORT2
280 DateFormat::createPatternInstance(const UnicodeString& skeleton,
281 const Locale& locale,
282 UErrorCode& status)
283 {
284 if ( U_FAILURE(status) ) {
285 return NULL;
286 }
287
288 DateTimePatternGenerator* dtptg =
289 DateTimePatternGenerator::createInstance(locale, status);
290 if ( dtptg == NULL ) {
291 status = U_MEMORY_ALLOCATION_ERROR;
292 delete dtptg;
293 return NULL;
294 }
295 if ( U_FAILURE(status) ) {
296 delete dtptg;
297 return NULL;
298 }
299
300 const UnicodeString pattern = dtptg->getBestPattern(skeleton, status);
301 delete dtptg;
302 if ( U_FAILURE(status) ) {
303 return NULL;
304 }
305 SimpleDateFormat* dtfmt = new SimpleDateFormat(pattern, locale, status);
306 if ( U_FAILURE(status) ) {
307 delete dtfmt;
308 return NULL;
309 }
310 return dtfmt;
311 }
312
313 //----------------------------------------------------------------------
314
315 DateFormat* U_EXPORT2
316 DateFormat::create(EStyle timeStyle, EStyle dateStyle, const Locale& locale)
317 {
318 UErrorCode status = U_ZERO_ERROR;
319 #ifdef U_WINDOWS
320 char buffer[8];
321 int32_t count = locale.getKeywordValue("compat", buffer, sizeof(buffer), status);
322
323 // if the locale has "@compat=host", create a host-specific DateFormat...
324 if (count > 0 && uprv_strcmp(buffer, "host") == 0) {
325 Win32DateFormat *f = new Win32DateFormat(timeStyle, dateStyle, locale, status);
326
327 if (U_SUCCESS(status)) {
328 return f;
329 }
330
331 delete f;
332 }
333 #endif
334
335 // is it relative?
336 if(/*((timeStyle!=UDAT_NONE)&&(timeStyle & UDAT_RELATIVE)) || */((dateStyle!=kNone)&&((dateStyle-kDateOffset) & UDAT_RELATIVE))) {
337 RelativeDateFormat *r = new RelativeDateFormat((UDateFormatStyle)timeStyle, (UDateFormatStyle)(dateStyle-kDateOffset), locale, status);
338 if(U_SUCCESS(status)) return r;
339 delete r;
340 status = U_ZERO_ERROR;
341 }
342
343 // Try to create a SimpleDateFormat of the desired style.
344 SimpleDateFormat *f = new SimpleDateFormat(timeStyle, dateStyle, locale, status);
345 if (U_SUCCESS(status)) return f;
346 delete f;
347
348 // If that fails, try to create a format using the default pattern and
349 // the DateFormatSymbols for this locale.
350 status = U_ZERO_ERROR;
351 f = new SimpleDateFormat(locale, status);
352 if (U_SUCCESS(status)) return f;
353 delete f;
354
355 // This should never really happen, because the preceding constructor
356 // should always succeed. If the resource data is unavailable, a last
357 // resort object should be returned.
358 return 0;
359 }
360
361 //----------------------------------------------------------------------
362
363 const Locale* U_EXPORT2
364 DateFormat::getAvailableLocales(int32_t& count)
365 {
366 // Get the list of installed locales.
367 // Even if root has the correct date format for this locale,
368 // it's still a valid locale (we don't worry about data fallbacks).
369 return Locale::getAvailableLocales(count);
370 }
371
372 //----------------------------------------------------------------------
373
374 void
375 DateFormat::adoptCalendar(Calendar* newCalendar)
376 {
377 delete fCalendar;
378 fCalendar = newCalendar;
379 }
380
381 //----------------------------------------------------------------------
382 void
383 DateFormat::setCalendar(const Calendar& newCalendar)
384 {
385 Calendar* newCalClone = newCalendar.clone();
386 if (newCalClone != NULL) {
387 adoptCalendar(newCalClone);
388 }
389 }
390
391 //----------------------------------------------------------------------
392
393 const Calendar*
394 DateFormat::getCalendar() const
395 {
396 return fCalendar;
397 }
398
399 //----------------------------------------------------------------------
400
401 void
402 DateFormat::adoptNumberFormat(NumberFormat* newNumberFormat)
403 {
404 delete fNumberFormat;
405 fNumberFormat = newNumberFormat;
406 newNumberFormat->setParseIntegerOnly(TRUE);
407 }
408 //----------------------------------------------------------------------
409
410 void
411 DateFormat::setNumberFormat(const NumberFormat& newNumberFormat)
412 {
413 NumberFormat* newNumFmtClone = (NumberFormat*)newNumberFormat.clone();
414 if (newNumFmtClone != NULL) {
415 adoptNumberFormat(newNumFmtClone);
416 }
417 }
418
419 //----------------------------------------------------------------------
420
421 const NumberFormat*
422 DateFormat::getNumberFormat() const
423 {
424 return fNumberFormat;
425 }
426
427 //----------------------------------------------------------------------
428
429 void
430 DateFormat::adoptTimeZone(TimeZone* zone)
431 {
432 if (fCalendar != NULL) {
433 fCalendar->adoptTimeZone(zone);
434 }
435 }
436 //----------------------------------------------------------------------
437
438 void
439 DateFormat::setTimeZone(const TimeZone& zone)
440 {
441 if (fCalendar != NULL) {
442 fCalendar->setTimeZone(zone);
443 }
444 }
445
446 //----------------------------------------------------------------------
447
448 const TimeZone&
449 DateFormat::getTimeZone() const
450 {
451 if (fCalendar != NULL) {
452 return fCalendar->getTimeZone();
453 }
454 // If calendar doesn't exists, create default timezone.
455 // fCalendar is rarely null
456 return *(TimeZone::createDefault());
457 }
458
459 //----------------------------------------------------------------------
460
461 void
462 DateFormat::setLenient(UBool lenient)
463 {
464 if (fCalendar != NULL) {
465 fCalendar->setLenient(lenient);
466 }
467 }
468
469 //----------------------------------------------------------------------
470
471 UBool
472 DateFormat::isLenient() const
473 {
474 if (fCalendar != NULL) {
475 return fCalendar->isLenient();
476 }
477 // fCalendar is rarely null
478 return FALSE;
479 }
480
481 U_NAMESPACE_END
482
483 #endif /* #if !UCONFIG_NO_FORMATTING */
484
485 //eof