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