xref: /haiku/src/kits/locale/DurationFormat.cpp (revision 44f11d0982feb6ed1cc66c4d6d0a26bffd8ce4d4)
1 /*
2  * Copyright 2010, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Oliver Tappe <zooey@hirschkaefer.de>
7  */
8 
9 
10 #include <DurationFormat.h>
11 
12 #include <new>
13 
14 #include <unicode/gregocal.h>
15 #include <unicode/utypes.h>
16 
17 #include <Locale.h>
18 #include <LocaleRoster.h>
19 #include <TimeZone.h>
20 
21 #include <TimeZonePrivate.h>
22 
23 
24 // maps our unit element to the corresponding ICU unit
25 static const UCalendarDateFields skUnitMap[] = {
26 	UCAL_YEAR,
27 	UCAL_MONTH,
28 	UCAL_WEEK_OF_MONTH,
29 	UCAL_DAY_OF_WEEK,
30 	UCAL_HOUR_OF_DAY,
31 	UCAL_MINUTE,
32 	UCAL_SECOND,
33 };
34 
35 
36 BDurationFormat::BDurationFormat(const BString& separator)
37 	:
38 	Inherited(),
39 	fSeparator(separator),
40 	fTimeUnitFormat()
41 {
42 	UErrorCode icuStatus = U_ZERO_ERROR;
43 	fCalendar = new GregorianCalendar(icuStatus);
44 	if (fCalendar == NULL) {
45 		fInitStatus = B_NO_MEMORY;
46 		return;
47 	}
48 }
49 
50 
51 BDurationFormat::BDurationFormat(const BDurationFormat& other)
52 	:
53 	Inherited(other),
54 	fSeparator(other.fSeparator),
55 	fTimeUnitFormat(other.fTimeUnitFormat),
56 	fCalendar(other.fCalendar != NULL
57 		? new GregorianCalendar(*other.fCalendar) : NULL)
58 {
59 	if (fCalendar == NULL && other.fCalendar != NULL)
60 		fInitStatus = B_NO_MEMORY;
61 }
62 
63 
64 BDurationFormat::~BDurationFormat()
65 {
66 	delete fCalendar;
67 }
68 
69 
70 BDurationFormat&
71 BDurationFormat::operator=(const BDurationFormat& other)
72 {
73 	if (this == &other)
74 		return *this;
75 
76 	fSeparator = other.fSeparator;
77 	fTimeUnitFormat = other.fTimeUnitFormat;
78 	delete fCalendar;
79 	fCalendar = other.fCalendar != NULL
80 		? new GregorianCalendar(*other.fCalendar) : NULL;
81 
82 	if (fCalendar == NULL && other.fCalendar != NULL)
83 		fInitStatus = B_NO_MEMORY;
84 
85 	return *this;
86 }
87 
88 
89 void
90 BDurationFormat::SetSeparator(const BString& separator)
91 {
92 	fSeparator = separator;
93 }
94 
95 
96 status_t
97 BDurationFormat::SetLanguage(const BLanguage& language)
98 {
99 	status_t result = Inherited::SetLanguage(language);
100 	if (result != B_OK)
101 		return result;
102 
103 	return fTimeUnitFormat.SetLanguage(language);
104 }
105 
106 
107 status_t
108 BDurationFormat::SetTimeZone(const BTimeZone* timeZone)
109 {
110 	if (fCalendar == NULL)
111 		return B_NO_INIT;
112 
113 	BTimeZone::Private zonePrivate;
114 	if (timeZone == NULL) {
115 		BTimeZone defaultTimeZone;
116 		status_t result
117 			= BLocaleRoster::Default()->GetDefaultTimeZone(&defaultTimeZone);
118 		if (result != B_OK)
119 			return result;
120 		zonePrivate.SetTo(&defaultTimeZone);
121 	} else
122 		zonePrivate.SetTo(timeZone);
123 
124 	TimeZone* icuTimeZone = zonePrivate.ICUTimeZone();
125 	if (icuTimeZone != NULL)
126 		fCalendar->setTimeZone(*icuTimeZone);
127 
128 	return B_OK;
129 }
130 
131 
132 status_t
133 BDurationFormat::Format(bigtime_t startValue, bigtime_t stopValue,
134 	BString* buffer, time_unit_style style) const
135 {
136 	if (buffer == NULL)
137 		return B_BAD_VALUE;
138 
139 	UErrorCode icuStatus = U_ZERO_ERROR;
140 	fCalendar->setTime((UDate)startValue / 1000, icuStatus);
141 	if (!U_SUCCESS(icuStatus))
142 		return B_ERROR;
143 
144 	UDate stop = (UDate)stopValue / 1000;
145 	bool needSeparator = false;
146 	for (int unit = 0; unit <= B_TIME_UNIT_LAST; ++unit) {
147 		int delta
148 			= fCalendar->fieldDifference(stop, skUnitMap[unit], icuStatus);
149 		if (!U_SUCCESS(icuStatus))
150 			return B_ERROR;
151 
152 		if (delta != 0) {
153 			if (needSeparator)
154 				buffer->Append(fSeparator);
155 			else
156 				needSeparator = true;
157 			status_t status = fTimeUnitFormat.Format(delta,
158 				(time_unit_element)unit, buffer, style);
159 			if (status != B_OK)
160 				return status;
161 		}
162 	}
163 
164 	return B_OK;
165 }
166