xref: /haiku/src/kits/locale/DurationFormat.cpp (revision 5e96d7d537fbec23bad4ae9b4c8e7b02e769f0c6)
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 	fInitStatus = SetLocale(fLocale);
50 }
51 
52 
53 BDurationFormat::BDurationFormat(const BDurationFormat& other)
54 	:
55 	Inherited(other),
56 	fSeparator(other.fSeparator),
57 	fTimeUnitFormat(other.fTimeUnitFormat),
58 	fCalendar(other.fCalendar != NULL
59 		? new GregorianCalendar(*other.fCalendar) : NULL)
60 {
61 	if (fCalendar == NULL && other.fCalendar != NULL)
62 		fInitStatus = B_NO_MEMORY;
63 }
64 
65 
66 BDurationFormat::~BDurationFormat()
67 {
68 	delete fCalendar;
69 }
70 
71 
72 BDurationFormat&
73 BDurationFormat::operator=(const BDurationFormat& other)
74 {
75 	if (this == &other)
76 		return *this;
77 
78 	fSeparator = other.fSeparator;
79 	fTimeUnitFormat = other.fTimeUnitFormat;
80 	delete fCalendar;
81 	fCalendar = other.fCalendar != NULL
82 		? new GregorianCalendar(*other.fCalendar) : NULL;
83 
84 	if (fCalendar == NULL && other.fCalendar != NULL)
85 		fInitStatus = B_NO_MEMORY;
86 
87 	return *this;
88 }
89 
90 
91 void
92 BDurationFormat::SetSeparator(const BString& separator)
93 {
94 	fSeparator = separator;
95 }
96 
97 
98 status_t
99 BDurationFormat::SetLocale(const BLocale* locale)
100 {
101 	status_t result = Inherited::SetLocale(locale);
102 	if (result != B_OK)
103 		return result;
104 
105 	return fTimeUnitFormat.SetLocale(locale);
106 }
107 
108 
109 status_t
110 BDurationFormat::SetTimeZone(const BTimeZone* timeZone)
111 {
112 	if (fCalendar == NULL)
113 		return B_NO_INIT;
114 
115 	BTimeZone::Private zonePrivate;
116 	if (timeZone == NULL) {
117 		BTimeZone defaultTimeZone;
118 		status_t result
119 			= BLocaleRoster::Default()->GetDefaultTimeZone(&defaultTimeZone);
120 		if (result != B_OK)
121 			return result;
122 		zonePrivate.SetTo(&defaultTimeZone);
123 	} else
124 		zonePrivate.SetTo(timeZone);
125 
126 	TimeZone* icuTimeZone = zonePrivate.ICUTimeZone();
127 	if (icuTimeZone != NULL)
128 		fCalendar->setTimeZone(*icuTimeZone);
129 
130 	return B_OK;
131 }
132 
133 
134 status_t
135 BDurationFormat::Format(bigtime_t startValue, bigtime_t stopValue,
136 	BString* buffer, time_unit_style style) const
137 {
138 	if (buffer == NULL)
139 		return B_BAD_VALUE;
140 
141 	UErrorCode icuStatus = U_ZERO_ERROR;
142 	fCalendar->setTime((UDate)startValue / 1000, icuStatus);
143 	if (!U_SUCCESS(icuStatus))
144 		return B_ERROR;
145 
146 	UDate stop = (UDate)stopValue / 1000;
147 	bool needSeparator = false;
148 	for (int unit = 0; unit <= B_TIME_UNIT_LAST; ++unit) {
149 		int delta
150 			= fCalendar->fieldDifference(stop, skUnitMap[unit], icuStatus);
151 		if (!U_SUCCESS(icuStatus))
152 			return B_ERROR;
153 
154 		if (delta != 0) {
155 			if (needSeparator)
156 				buffer->Append(fSeparator);
157 			else
158 				needSeparator = true;
159 			status_t status = fTimeUnitFormat.Format(delta,
160 				(time_unit_element)unit, buffer, style);
161 			if (status != B_OK)
162 				return status;
163 		}
164 	}
165 
166 	return B_OK;
167 }
168