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