]> git.saurik.com Git - apple/icu.git/blame - icuSources/i18n/datefmt.cpp
ICU-531.30.tar.gz
[apple/icu.git] / icuSources / i18n / datefmt.cpp
CommitLineData
b75a7d8f 1/*
46f4442e 2 *******************************************************************************
57a6839d 3 * Copyright (C) 1997-2014, International Business Machines Corporation and *
46f4442e
A
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 27#include "unicode/dtptngen.h"
57a6839d 28#include "unicode/udisplaycontext.h"
46f4442e 29#include "reldtfmt.h"
b75a7d8f 30
73c04bcf
A
31#include "cstring.h"
32#include "windtfmt.h"
33
374ca955
A
34#if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
35#include <stdio.h>
36#endif
37
b75a7d8f
A
38// *****************************************************************************
39// class DateFormat
40// *****************************************************************************
41
42U_NAMESPACE_BEGIN
43
44DateFormat::DateFormat()
45: fCalendar(0),
57a6839d
A
46 fNumberFormat(0),
47 fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE)
b75a7d8f
A
48{
49}
50
51//----------------------------------------------------------------------
52
53DateFormat::DateFormat(const DateFormat& other)
54: Format(other),
55 fCalendar(0),
57a6839d
A
56 fNumberFormat(0),
57 fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE)
b75a7d8f
A
58{
59 *this = other;
60}
61
62//----------------------------------------------------------------------
63
64DateFormat& DateFormat::operator=(const DateFormat& other)
65{
66 if (this != &other)
67 {
68 delete fCalendar;
69 delete fNumberFormat;
70 if(other.fCalendar) {
71 fCalendar = other.fCalendar->clone();
72 } else {
73 fCalendar = NULL;
74 }
75 if(other.fNumberFormat) {
76 fNumberFormat = (NumberFormat*)other.fNumberFormat->clone();
77 } else {
78 fNumberFormat = NULL;
79 }
57a6839d
A
80 fBoolFlags = other.fBoolFlags;
81 fCapitalizationContext = other.fCapitalizationContext;
b75a7d8f
A
82 }
83 return *this;
84}
85
86//----------------------------------------------------------------------
87
88DateFormat::~DateFormat()
89{
90 delete fCalendar;
91 delete fNumberFormat;
92}
93
94//----------------------------------------------------------------------
95
96UBool
97DateFormat::operator==(const Format& other) const
98{
99 // This protected comparison operator should only be called by subclasses
100 // which have confirmed that the other object being compared against is
101 // an instance of a sublcass of DateFormat. THIS IS IMPORTANT.
102
374ca955 103 // Format::operator== guarantees that this cast is safe
b75a7d8f
A
104 DateFormat* fmt = (DateFormat*)&other;
105
106 return (this == fmt) ||
374ca955 107 (Format::operator==(other) &&
b75a7d8f 108 fCalendar&&(fCalendar->isEquivalentTo(*fmt->fCalendar)) &&
57a6839d
A
109 (fNumberFormat && *fNumberFormat == *fmt->fNumberFormat) &&
110 (fCapitalizationContext == fmt->fCapitalizationContext) );
b75a7d8f
A
111}
112
113//----------------------------------------------------------------------
114
115UnicodeString&
116DateFormat::format(const Formattable& obj,
117 UnicodeString& appendTo,
118 FieldPosition& fieldPosition,
119 UErrorCode& status) const
120{
121 if (U_FAILURE(status)) return appendTo;
122
123 // if the type of the Formattable is double or long, treat it as if it were a Date
124 UDate date = 0;
125 switch (obj.getType())
126 {
127 case Formattable::kDate:
128 date = obj.getDate();
129 break;
130 case Formattable::kDouble:
131 date = (UDate)obj.getDouble();
132 break;
133 case Formattable::kLong:
134 date = (UDate)obj.getLong();
135 break;
136 default:
137 status = U_ILLEGAL_ARGUMENT_ERROR;
138 return appendTo;
139 }
140
141 // Is this right?
142 //if (fieldPosition.getBeginIndex() == fieldPosition.getEndIndex())
143 // status = U_ILLEGAL_ARGUMENT_ERROR;
144
145 return format(date, appendTo, fieldPosition);
146}
147
148//----------------------------------------------------------------------
149
729e4ab9
A
150UnicodeString&
151DateFormat::format(const Formattable& obj,
152 UnicodeString& appendTo,
153 FieldPositionIterator* posIter,
154 UErrorCode& status) const
155{
156 if (U_FAILURE(status)) return appendTo;
157
158 // if the type of the Formattable is double or long, treat it as if it were a Date
159 UDate date = 0;
160 switch (obj.getType())
161 {
162 case Formattable::kDate:
163 date = obj.getDate();
164 break;
165 case Formattable::kDouble:
166 date = (UDate)obj.getDouble();
167 break;
168 case Formattable::kLong:
169 date = (UDate)obj.getLong();
170 break;
171 default:
172 status = U_ILLEGAL_ARGUMENT_ERROR;
173 return appendTo;
174 }
175
176 // Is this right?
177 //if (fieldPosition.getBeginIndex() == fieldPosition.getEndIndex())
178 // status = U_ILLEGAL_ARGUMENT_ERROR;
179
180 return format(date, appendTo, posIter, status);
181}
182
183//----------------------------------------------------------------------
184
185// Default implementation for backwards compatibility, subclasses should implement.
186UnicodeString&
187DateFormat::format(Calendar& /* unused cal */,
188 UnicodeString& appendTo,
189 FieldPositionIterator* /* unused posIter */,
190 UErrorCode& status) const {
191 if (U_SUCCESS(status)) {
192 status = U_UNSUPPORTED_ERROR;
193 }
194 return appendTo;
195}
196
197//----------------------------------------------------------------------
198
b75a7d8f
A
199UnicodeString&
200DateFormat::format(UDate date, UnicodeString& appendTo, FieldPosition& fieldPosition) const {
201 if (fCalendar != NULL) {
4388f060
A
202 // Use a clone of our calendar instance
203 Calendar* calClone = fCalendar->clone();
204 if (calClone != NULL) {
205 UErrorCode ec = U_ZERO_ERROR;
206 calClone->setTime(date, ec);
207 if (U_SUCCESS(ec)) {
208 format(*calClone, appendTo, fieldPosition);
209 }
210 delete calClone;
b75a7d8f
A
211 }
212 }
213 return appendTo;
214}
215
216//----------------------------------------------------------------------
217
729e4ab9
A
218UnicodeString&
219DateFormat::format(UDate date, UnicodeString& appendTo, FieldPositionIterator* posIter,
220 UErrorCode& status) const {
221 if (fCalendar != NULL) {
4388f060
A
222 Calendar* calClone = fCalendar->clone();
223 if (calClone != NULL) {
224 calClone->setTime(date, status);
225 if (U_SUCCESS(status)) {
226 format(*calClone, appendTo, posIter, status);
227 }
228 delete calClone;
729e4ab9
A
229 }
230 }
231 return appendTo;
232}
233
234//----------------------------------------------------------------------
235
b75a7d8f
A
236UnicodeString&
237DateFormat::format(UDate date, UnicodeString& appendTo) const
238{
239 // Note that any error information is just lost. That's okay
240 // for this convenience method.
241 FieldPosition fpos(0);
242 return format(date, appendTo, fpos);
243}
244
245//----------------------------------------------------------------------
246
247UDate
248DateFormat::parse(const UnicodeString& text,
249 ParsePosition& pos) const
250{
46f4442e 251 UDate d = 0; // Error return UDate is 0 (the epoch)
b75a7d8f 252 if (fCalendar != NULL) {
4388f060
A
253 Calendar* calClone = fCalendar->clone();
254 if (calClone != NULL) {
255 int32_t start = pos.getIndex();
256 calClone->clear();
257 parse(text, *calClone, pos);
258 if (pos.getIndex() != start) {
259 UErrorCode ec = U_ZERO_ERROR;
260 d = calClone->getTime(ec);
261 if (U_FAILURE(ec)) {
262 // We arrive here if fCalendar => calClone is non-lenient and
263 // there is an out-of-range field. We don't know which field
264 // was illegal so we set the error index to the start.
265 pos.setIndex(start);
266 pos.setErrorIndex(start);
267 d = 0;
268 }
b75a7d8f 269 }
4388f060 270 delete calClone;
b75a7d8f
A
271 }
272 }
46f4442e 273 return d;
b75a7d8f
A
274}
275
276//----------------------------------------------------------------------
277
278UDate
279DateFormat::parse(const UnicodeString& text,
280 UErrorCode& status) const
281{
282 if (U_FAILURE(status)) return 0;
283
284 ParsePosition pos(0);
285 UDate result = parse(text, pos);
374ca955
A
286 if (pos.getIndex() == 0) {
287#if defined (U_DEBUG_CAL)
288 fprintf(stderr, "%s:%d - - failed to parse - err index %d\n"
289 , __FILE__, __LINE__, pos.getErrorIndex() );
290#endif
291 status = U_ILLEGAL_ARGUMENT_ERROR;
292 }
b75a7d8f
A
293 return result;
294}
295
296//----------------------------------------------------------------------
297
298void
299DateFormat::parseObject(const UnicodeString& source,
300 Formattable& result,
301 ParsePosition& pos) const
302{
303 result.setDate(parse(source, pos));
304}
305
306//----------------------------------------------------------------------
307
374ca955 308DateFormat* U_EXPORT2
b75a7d8f
A
309DateFormat::createTimeInstance(DateFormat::EStyle style,
310 const Locale& aLocale)
311{
312 return create(style, kNone, aLocale);
313}
314
315//----------------------------------------------------------------------
316
374ca955 317DateFormat* U_EXPORT2
b75a7d8f
A
318DateFormat::createDateInstance(DateFormat::EStyle style,
319 const Locale& aLocale)
320{
374ca955
A
321 // +4 to set the correct index for getting data out of
322 // LocaleElements.
323 if(style != kNone)
324 {
325 style = (EStyle) (style + kDateOffset);
326 }
327 return create(kNone, (EStyle) (style), aLocale);
b75a7d8f
A
328}
329
330//----------------------------------------------------------------------
331
374ca955 332DateFormat* U_EXPORT2
b75a7d8f
A
333DateFormat::createDateTimeInstance(EStyle dateStyle,
334 EStyle timeStyle,
335 const Locale& aLocale)
336{
374ca955
A
337 if(dateStyle != kNone)
338 {
339 dateStyle = (EStyle) (dateStyle + kDateOffset);
340 }
341 return create(timeStyle, dateStyle, aLocale);
b75a7d8f
A
342}
343
344//----------------------------------------------------------------------
345
374ca955 346DateFormat* U_EXPORT2
b75a7d8f
A
347DateFormat::createInstance()
348{
349 return create(kShort, (EStyle) (kShort + kDateOffset), Locale::getDefault());
350}
351
352//----------------------------------------------------------------------
353
374ca955 354DateFormat* U_EXPORT2
b75a7d8f
A
355DateFormat::create(EStyle timeStyle, EStyle dateStyle, const Locale& locale)
356{
b75a7d8f 357 UErrorCode status = U_ZERO_ERROR;
4388f060 358#if U_PLATFORM_HAS_WIN32_API
73c04bcf
A
359 char buffer[8];
360 int32_t count = locale.getKeywordValue("compat", buffer, sizeof(buffer), status);
361
362 // if the locale has "@compat=host", create a host-specific DateFormat...
363 if (count > 0 && uprv_strcmp(buffer, "host") == 0) {
364 Win32DateFormat *f = new Win32DateFormat(timeStyle, dateStyle, locale, status);
365
366 if (U_SUCCESS(status)) {
367 return f;
368 }
369
370 delete f;
371 }
372#endif
373
46f4442e
A
374 // is it relative?
375 if(/*((timeStyle!=UDAT_NONE)&&(timeStyle & UDAT_RELATIVE)) || */((dateStyle!=kNone)&&((dateStyle-kDateOffset) & UDAT_RELATIVE))) {
376 RelativeDateFormat *r = new RelativeDateFormat((UDateFormatStyle)timeStyle, (UDateFormatStyle)(dateStyle-kDateOffset), locale, status);
377 if(U_SUCCESS(status)) return r;
378 delete r;
379 status = U_ZERO_ERROR;
380 }
73c04bcf
A
381
382 // Try to create a SimpleDateFormat of the desired style.
b75a7d8f
A
383 SimpleDateFormat *f = new SimpleDateFormat(timeStyle, dateStyle, locale, status);
384 if (U_SUCCESS(status)) return f;
385 delete f;
386
387 // If that fails, try to create a format using the default pattern and
388 // the DateFormatSymbols for this locale.
389 status = U_ZERO_ERROR;
390 f = new SimpleDateFormat(locale, status);
391 if (U_SUCCESS(status)) return f;
392 delete f;
393
394 // This should never really happen, because the preceding constructor
395 // should always succeed. If the resource data is unavailable, a last
396 // resort object should be returned.
397 return 0;
398}
399
400//----------------------------------------------------------------------
401
374ca955 402const Locale* U_EXPORT2
b75a7d8f
A
403DateFormat::getAvailableLocales(int32_t& count)
404{
405 // Get the list of installed locales.
406 // Even if root has the correct date format for this locale,
407 // it's still a valid locale (we don't worry about data fallbacks).
408 return Locale::getAvailableLocales(count);
409}
410
411//----------------------------------------------------------------------
412
413void
414DateFormat::adoptCalendar(Calendar* newCalendar)
415{
416 delete fCalendar;
417 fCalendar = newCalendar;
418}
419
420//----------------------------------------------------------------------
421void
422DateFormat::setCalendar(const Calendar& newCalendar)
423{
46f4442e
A
424 Calendar* newCalClone = newCalendar.clone();
425 if (newCalClone != NULL) {
426 adoptCalendar(newCalClone);
427 }
b75a7d8f
A
428}
429
430//----------------------------------------------------------------------
431
432const Calendar*
433DateFormat::getCalendar() const
434{
435 return fCalendar;
436}
437
438//----------------------------------------------------------------------
439
440void
441DateFormat::adoptNumberFormat(NumberFormat* newNumberFormat)
442{
443 delete fNumberFormat;
444 fNumberFormat = newNumberFormat;
445 newNumberFormat->setParseIntegerOnly(TRUE);
446}
447//----------------------------------------------------------------------
448
449void
450DateFormat::setNumberFormat(const NumberFormat& newNumberFormat)
451{
46f4442e
A
452 NumberFormat* newNumFmtClone = (NumberFormat*)newNumberFormat.clone();
453 if (newNumFmtClone != NULL) {
454 adoptNumberFormat(newNumFmtClone);
455 }
b75a7d8f
A
456}
457
458//----------------------------------------------------------------------
459
460const NumberFormat*
461DateFormat::getNumberFormat() const
462{
463 return fNumberFormat;
464}
465
466//----------------------------------------------------------------------
467
468void
469DateFormat::adoptTimeZone(TimeZone* zone)
470{
46f4442e
A
471 if (fCalendar != NULL) {
472 fCalendar->adoptTimeZone(zone);
473 }
b75a7d8f
A
474}
475//----------------------------------------------------------------------
476
477void
478DateFormat::setTimeZone(const TimeZone& zone)
479{
46f4442e
A
480 if (fCalendar != NULL) {
481 fCalendar->setTimeZone(zone);
482 }
b75a7d8f
A
483}
484
485//----------------------------------------------------------------------
486
487const TimeZone&
488DateFormat::getTimeZone() const
489{
46f4442e
A
490 if (fCalendar != NULL) {
491 return fCalendar->getTimeZone();
492 }
493 // If calendar doesn't exists, create default timezone.
494 // fCalendar is rarely null
495 return *(TimeZone::createDefault());
b75a7d8f
A
496}
497
498//----------------------------------------------------------------------
499
500void
501DateFormat::setLenient(UBool lenient)
502{
46f4442e
A
503 if (fCalendar != NULL) {
504 fCalendar->setLenient(lenient);
505 }
57a6839d
A
506 UErrorCode status = U_ZERO_ERROR;
507 setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, lenient, status);
508 setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, lenient, status);
b75a7d8f
A
509}
510
511//----------------------------------------------------------------------
512
513UBool
514DateFormat::isLenient() const
57a6839d
A
515{
516 UBool lenient = TRUE;
517 if (fCalendar != NULL) {
518 lenient = fCalendar->isLenient();
519 }
520 UErrorCode status = U_ZERO_ERROR;
521 return lenient
522 && getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status)
523 && getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status);
524}
525
526void
527DateFormat::setCalendarLenient(UBool lenient)
528{
529 if (fCalendar != NULL) {
530 fCalendar->setLenient(lenient);
531 }
532}
533
534//----------------------------------------------------------------------
535
536UBool
537DateFormat::isCalendarLenient() const
b75a7d8f 538{
46f4442e
A
539 if (fCalendar != NULL) {
540 return fCalendar->isLenient();
541 }
542 // fCalendar is rarely null
543 return FALSE;
b75a7d8f
A
544}
545
57a6839d
A
546
547//----------------------------------------------------------------------
548
549
550void DateFormat::setContext(UDisplayContext value, UErrorCode& status)
551{
552 if (U_FAILURE(status))
553 return;
554 if ( (UDisplayContextType)((uint32_t)value >> 8) == UDISPCTX_TYPE_CAPITALIZATION ) {
555 fCapitalizationContext = value;
556 } else {
557 status = U_ILLEGAL_ARGUMENT_ERROR;
558 }
559}
560
561
562//----------------------------------------------------------------------
563
564
565UDisplayContext DateFormat::getContext(UDisplayContextType type, UErrorCode& status) const
566{
567 if (U_FAILURE(status))
568 return (UDisplayContext)0;
569 if (type != UDISPCTX_TYPE_CAPITALIZATION) {
570 status = U_ILLEGAL_ARGUMENT_ERROR;
571 return (UDisplayContext)0;
572 }
573 return fCapitalizationContext;
574}
575
576
577//----------------------------------------------------------------------
578
579
580DateFormat&
581DateFormat::setBooleanAttribute(UDateFormatBooleanAttribute attr,
582 UBool newValue,
583 UErrorCode &status) {
584 if(!fBoolFlags.isValidValue(newValue)) {
585 status = U_ILLEGAL_ARGUMENT_ERROR;
586 } else {
587 fBoolFlags.set(attr, newValue);
588 }
589
590 return *this;
591}
592
593//----------------------------------------------------------------------
594
595UBool
596DateFormat::getBooleanAttribute(UDateFormatBooleanAttribute attr, UErrorCode &/*status*/) const {
597
598 return fBoolFlags.get(attr);
599}
600
b75a7d8f
A
601U_NAMESPACE_END
602
603#endif /* #if !UCONFIG_NO_FORMATTING */
604
605//eof