]> git.saurik.com Git - apple/icu.git/blame - icuSources/i18n/datefmt.cpp
ICU-400.42.tar.gz
[apple/icu.git] / icuSources / i18n / datefmt.cpp
CommitLineData
b75a7d8f 1/*
46f4442e
A
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 */
b75a7d8f
A
19
20#include "unicode/utypes.h"
21
22#if !UCONFIG_NO_FORMATTING
23
374ca955 24#include "unicode/ures.h"
b75a7d8f
A
25#include "unicode/datefmt.h"
26#include "unicode/smpdtfmt.h"
46f4442e
A
27#include "unicode/dtptngen.h"
28#include "reldtfmt.h"
b75a7d8f 29
73c04bcf
A
30#include "cstring.h"
31#include "windtfmt.h"
32
374ca955
A
33#if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
34#include <stdio.h>
35#endif
36
b75a7d8f
A
37// *****************************************************************************
38// class DateFormat
39// *****************************************************************************
40
41U_NAMESPACE_BEGIN
42
43DateFormat::DateFormat()
44: fCalendar(0),
45 fNumberFormat(0)
46{
47}
48
49//----------------------------------------------------------------------
50
51DateFormat::DateFormat(const DateFormat& other)
52: Format(other),
53 fCalendar(0),
54 fNumberFormat(0)
55{
56 *this = other;
57}
58
59//----------------------------------------------------------------------
60
61DateFormat& 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
83DateFormat::~DateFormat()
84{
85 delete fCalendar;
86 delete fNumberFormat;
87}
88
89//----------------------------------------------------------------------
90
91UBool
92DateFormat::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
374ca955 98 // Format::operator== guarantees that this cast is safe
b75a7d8f
A
99 DateFormat* fmt = (DateFormat*)&other;
100
101 return (this == fmt) ||
374ca955 102 (Format::operator==(other) &&
b75a7d8f 103 fCalendar&&(fCalendar->isEquivalentTo(*fmt->fCalendar)) &&
374ca955 104 (fNumberFormat && *fNumberFormat == *fmt->fNumberFormat));
b75a7d8f
A
105}
106
107//----------------------------------------------------------------------
108
109UnicodeString&
110DateFormat::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
144UnicodeString&
145DateFormat::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
159UnicodeString&
160DateFormat::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
170UDate
171DateFormat::parse(const UnicodeString& text,
172 ParsePosition& pos) const
173{
46f4442e 174 UDate d = 0; // Error return UDate is 0 (the epoch)
b75a7d8f
A
175 if (fCalendar != NULL) {
176 int32_t start = pos.getIndex();
46f4442e
A
177
178 // Parse may update TimeZone used by the calendar.
179 TimeZone *tzsav = (TimeZone*)fCalendar->getTimeZone().clone();
180
b75a7d8f
A
181 fCalendar->clear();
182 parse(text, *fCalendar, pos);
183 if (pos.getIndex() != start) {
184 UErrorCode ec = U_ZERO_ERROR;
46f4442e
A
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;
b75a7d8f 193 }
b75a7d8f 194 }
46f4442e
A
195
196 // Restore TimeZone
197 fCalendar->adoptTimeZone(tzsav);
b75a7d8f 198 }
46f4442e 199 return d;
b75a7d8f
A
200}
201
202//----------------------------------------------------------------------
203
204UDate
205DateFormat::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);
374ca955
A
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 }
b75a7d8f
A
219 return result;
220}
221
222//----------------------------------------------------------------------
223
224void
225DateFormat::parseObject(const UnicodeString& source,
226 Formattable& result,
227 ParsePosition& pos) const
228{
229 result.setDate(parse(source, pos));
230}
231
232//----------------------------------------------------------------------
233
374ca955 234DateFormat* U_EXPORT2
b75a7d8f
A
235DateFormat::createTimeInstance(DateFormat::EStyle style,
236 const Locale& aLocale)
237{
238 return create(style, kNone, aLocale);
239}
240
241//----------------------------------------------------------------------
242
374ca955 243DateFormat* U_EXPORT2
b75a7d8f
A
244DateFormat::createDateInstance(DateFormat::EStyle style,
245 const Locale& aLocale)
246{
374ca955
A
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);
b75a7d8f
A
254}
255
256//----------------------------------------------------------------------
257
374ca955 258DateFormat* U_EXPORT2
b75a7d8f
A
259DateFormat::createDateTimeInstance(EStyle dateStyle,
260 EStyle timeStyle,
261 const Locale& aLocale)
262{
374ca955
A
263 if(dateStyle != kNone)
264 {
265 dateStyle = (EStyle) (dateStyle + kDateOffset);
266 }
267 return create(timeStyle, dateStyle, aLocale);
b75a7d8f
A
268}
269
270//----------------------------------------------------------------------
271
374ca955 272DateFormat* U_EXPORT2
b75a7d8f
A
273DateFormat::createInstance()
274{
275 return create(kShort, (EStyle) (kShort + kDateOffset), Locale::getDefault());
276}
277
46f4442e
A
278//----------------------------------------------------------------------
279DateFormat* U_EXPORT2
280DateFormat::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
b75a7d8f
A
313//----------------------------------------------------------------------
314
374ca955 315DateFormat* U_EXPORT2
b75a7d8f
A
316DateFormat::create(EStyle timeStyle, EStyle dateStyle, const Locale& locale)
317{
b75a7d8f 318 UErrorCode status = U_ZERO_ERROR;
73c04bcf
A
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
46f4442e
A
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 }
73c04bcf
A
342
343 // Try to create a SimpleDateFormat of the desired style.
b75a7d8f
A
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
374ca955 363const Locale* U_EXPORT2
b75a7d8f
A
364DateFormat::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
374void
375DateFormat::adoptCalendar(Calendar* newCalendar)
376{
377 delete fCalendar;
378 fCalendar = newCalendar;
379}
380
381//----------------------------------------------------------------------
382void
383DateFormat::setCalendar(const Calendar& newCalendar)
384{
46f4442e
A
385 Calendar* newCalClone = newCalendar.clone();
386 if (newCalClone != NULL) {
387 adoptCalendar(newCalClone);
388 }
b75a7d8f
A
389}
390
391//----------------------------------------------------------------------
392
393const Calendar*
394DateFormat::getCalendar() const
395{
396 return fCalendar;
397}
398
399//----------------------------------------------------------------------
400
401void
402DateFormat::adoptNumberFormat(NumberFormat* newNumberFormat)
403{
404 delete fNumberFormat;
405 fNumberFormat = newNumberFormat;
406 newNumberFormat->setParseIntegerOnly(TRUE);
407}
408//----------------------------------------------------------------------
409
410void
411DateFormat::setNumberFormat(const NumberFormat& newNumberFormat)
412{
46f4442e
A
413 NumberFormat* newNumFmtClone = (NumberFormat*)newNumberFormat.clone();
414 if (newNumFmtClone != NULL) {
415 adoptNumberFormat(newNumFmtClone);
416 }
b75a7d8f
A
417}
418
419//----------------------------------------------------------------------
420
421const NumberFormat*
422DateFormat::getNumberFormat() const
423{
424 return fNumberFormat;
425}
426
427//----------------------------------------------------------------------
428
429void
430DateFormat::adoptTimeZone(TimeZone* zone)
431{
46f4442e
A
432 if (fCalendar != NULL) {
433 fCalendar->adoptTimeZone(zone);
434 }
b75a7d8f
A
435}
436//----------------------------------------------------------------------
437
438void
439DateFormat::setTimeZone(const TimeZone& zone)
440{
46f4442e
A
441 if (fCalendar != NULL) {
442 fCalendar->setTimeZone(zone);
443 }
b75a7d8f
A
444}
445
446//----------------------------------------------------------------------
447
448const TimeZone&
449DateFormat::getTimeZone() const
450{
46f4442e
A
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());
b75a7d8f
A
457}
458
459//----------------------------------------------------------------------
460
461void
462DateFormat::setLenient(UBool lenient)
463{
46f4442e
A
464 if (fCalendar != NULL) {
465 fCalendar->setLenient(lenient);
466 }
b75a7d8f
A
467}
468
469//----------------------------------------------------------------------
470
471UBool
472DateFormat::isLenient() const
473{
46f4442e
A
474 if (fCalendar != NULL) {
475 return fCalendar->isLenient();
476 }
477 // fCalendar is rarely null
478 return FALSE;
b75a7d8f
A
479}
480
481U_NAMESPACE_END
482
483#endif /* #if !UCONFIG_NO_FORMATTING */
484
485//eof