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