Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : *
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "DateTimeFormat.h"
8 : #include "nsCOMPtr.h"
9 : #include "nsIServiceManager.h"
10 : #include "mozilla/intl/LocaleService.h"
11 : #include "OSPreferences.h"
12 : #include "mozIOSPreferences.h"
13 : #include "unicode/udatpg.h"
14 :
15 : namespace mozilla {
16 : using namespace mozilla::intl;
17 :
18 : nsCString* DateTimeFormat::mLocale = nullptr;
19 :
20 : /*static*/ nsresult
21 0 : DateTimeFormat::Initialize()
22 : {
23 0 : if (mLocale) {
24 0 : return NS_OK;
25 : }
26 :
27 0 : mLocale = new nsCString();
28 0 : nsAutoCString locale;
29 0 : intl::LocaleService::GetInstance()->GetAppLocaleAsBCP47(locale);
30 0 : mLocale->Assign(locale);
31 :
32 0 : return NS_OK;
33 : }
34 :
35 : // performs a locale sensitive date formatting operation on the time_t parameter
36 : /*static*/ nsresult
37 0 : DateTimeFormat::FormatTime(const nsDateFormatSelector aDateFormatSelector,
38 : const nsTimeFormatSelector aTimeFormatSelector,
39 : const time_t aTimetTime,
40 : nsAString& aStringOut)
41 : {
42 0 : return FormatPRTime(aDateFormatSelector, aTimeFormatSelector, (aTimetTime * PR_USEC_PER_SEC), aStringOut);
43 : }
44 :
45 : // performs a locale sensitive date formatting operation on the PRTime parameter
46 : /*static*/ nsresult
47 0 : DateTimeFormat::FormatPRTime(const nsDateFormatSelector aDateFormatSelector,
48 : const nsTimeFormatSelector aTimeFormatSelector,
49 : const PRTime aPrTime,
50 : nsAString& aStringOut)
51 : {
52 0 : return FormatUDateTime(aDateFormatSelector, aTimeFormatSelector, (aPrTime / PR_USEC_PER_MSEC), nullptr, aStringOut);
53 : }
54 :
55 : // performs a locale sensitive date formatting operation on the PRExplodedTime parameter
56 : /*static*/ nsresult
57 0 : DateTimeFormat::FormatPRExplodedTime(const nsDateFormatSelector aDateFormatSelector,
58 : const nsTimeFormatSelector aTimeFormatSelector,
59 : const PRExplodedTime* aExplodedTime,
60 : nsAString& aStringOut)
61 : {
62 0 : return FormatUDateTime(aDateFormatSelector, aTimeFormatSelector, (PR_ImplodeTime(aExplodedTime) / PR_USEC_PER_MSEC), &(aExplodedTime->tm_params), aStringOut);
63 : }
64 :
65 : // performs a locale sensitive date formatting operation on the UDate parameter
66 : /*static*/ nsresult
67 0 : DateTimeFormat::FormatUDateTime(const nsDateFormatSelector aDateFormatSelector,
68 : const nsTimeFormatSelector aTimeFormatSelector,
69 : const UDate aUDateTime,
70 : const PRTimeParameters* aTimeParameters,
71 : nsAString& aStringOut)
72 : {
73 0 : const int32_t DATETIME_FORMAT_INITIAL_LEN = 127;
74 0 : int32_t dateTimeLen = 0;
75 0 : nsresult rv = NS_OK;
76 :
77 : // return, nothing to format
78 0 : if (aDateFormatSelector == kDateFormatNone && aTimeFormatSelector == kTimeFormatNone) {
79 0 : aStringOut.Truncate();
80 0 : return NS_OK;
81 : }
82 :
83 : // set up locale data
84 0 : rv = Initialize();
85 :
86 0 : if (NS_FAILED(rv)) {
87 0 : return rv;
88 : }
89 :
90 : // Get the date style for the formatter.
91 0 : nsAutoString skeletonDate;
92 0 : nsAutoString patternDate;
93 0 : bool haveSkeleton = true;
94 0 : switch (aDateFormatSelector) {
95 : case kDateFormatLong:
96 0 : rv = OSPreferences::GetInstance()->GetDateTimePattern(mozIOSPreferences::dateTimeFormatStyleLong,
97 : mozIOSPreferences::dateTimeFormatStyleNone,
98 0 : nsDependentCString(mLocale->get()),
99 0 : patternDate);
100 0 : NS_ENSURE_SUCCESS(rv, rv);
101 0 : haveSkeleton = false;
102 0 : break;
103 : case kDateFormatShort:
104 0 : rv = OSPreferences::GetInstance()->GetDateTimePattern(mozIOSPreferences::dateTimeFormatStyleShort,
105 : mozIOSPreferences::dateTimeFormatStyleNone,
106 0 : nsDependentCString(mLocale->get()),
107 0 : patternDate);
108 0 : NS_ENSURE_SUCCESS(rv, rv);
109 0 : haveSkeleton = false;
110 0 : break;
111 : case kDateFormatYearMonth:
112 0 : skeletonDate.AssignLiteral("yyyyMM");
113 0 : break;
114 : case kDateFormatYearMonthLong:
115 0 : skeletonDate.AssignLiteral("yyyyMMMM");
116 0 : break;
117 : case kDateFormatMonthLong:
118 0 : skeletonDate.AssignLiteral("MMMM");
119 0 : break;
120 : case kDateFormatWeekday:
121 0 : skeletonDate.AssignLiteral("EEE");
122 0 : break;
123 : case kDateFormatNone:
124 0 : haveSkeleton = false;
125 0 : break;
126 : default:
127 0 : NS_ERROR("Unknown nsDateFormatSelector");
128 0 : return NS_ERROR_ILLEGAL_VALUE;
129 : }
130 :
131 0 : UErrorCode status = U_ZERO_ERROR;
132 0 : if (haveSkeleton) {
133 : // Get pattern for skeleton.
134 0 : UDateTimePatternGenerator* patternGenerator = udatpg_open(mLocale->get(), &status);
135 0 : if (U_SUCCESS(status)) {
136 : int32_t patternLength;
137 0 : patternDate.SetLength(DATETIME_FORMAT_INITIAL_LEN);
138 0 : patternLength = udatpg_getBestPattern(patternGenerator,
139 : reinterpret_cast<const UChar*>(skeletonDate.BeginReading()),
140 0 : skeletonDate.Length(),
141 : reinterpret_cast<UChar*>(patternDate.BeginWriting()),
142 : DATETIME_FORMAT_INITIAL_LEN,
143 0 : &status);
144 0 : patternDate.SetLength(patternLength);
145 :
146 0 : if (status == U_BUFFER_OVERFLOW_ERROR) {
147 0 : status = U_ZERO_ERROR;
148 0 : udatpg_getBestPattern(patternGenerator,
149 : reinterpret_cast<const UChar*>(skeletonDate.BeginReading()),
150 0 : skeletonDate.Length(),
151 : reinterpret_cast<UChar*>(patternDate.BeginWriting()),
152 : patternLength,
153 0 : &status);
154 : }
155 : }
156 0 : udatpg_close(patternGenerator);
157 : }
158 :
159 : // Get the time style for the formatter.
160 0 : nsAutoString patternTime;
161 0 : switch (aTimeFormatSelector) {
162 : case kTimeFormatSeconds:
163 0 : rv = OSPreferences::GetInstance()->GetDateTimePattern(mozIOSPreferences::dateTimeFormatStyleNone,
164 : mozIOSPreferences::dateTimeFormatStyleLong,
165 0 : nsDependentCString(mLocale->get()),
166 0 : patternTime);
167 0 : NS_ENSURE_SUCCESS(rv, rv);
168 0 : break;
169 : case kTimeFormatNoSeconds:
170 0 : rv = OSPreferences::GetInstance()->GetDateTimePattern(mozIOSPreferences::dateTimeFormatStyleNone,
171 : mozIOSPreferences::dateTimeFormatStyleShort,
172 0 : nsDependentCString(mLocale->get()),
173 0 : patternTime);
174 0 : NS_ENSURE_SUCCESS(rv, rv);
175 0 : break;
176 : case kTimeFormatNone:
177 0 : break;
178 : default:
179 0 : NS_ERROR("Unknown nsTimeFormatSelector");
180 0 : return NS_ERROR_ILLEGAL_VALUE;
181 : }
182 :
183 0 : nsAutoString pattern;
184 0 : if (patternTime.Length() == 0) {
185 0 : pattern.Assign(patternDate);
186 0 : } else if (patternDate.Length() == 0) {
187 0 : pattern.Assign(patternTime);
188 : } else {
189 0 : OSPreferences::GetDateTimeConnectorPattern(nsDependentCString(mLocale->get()), pattern);
190 0 : int32_t index = pattern.Find("{1}");
191 0 : if (index != kNotFound)
192 0 : pattern.Replace(index, 3, patternDate);
193 0 : index = pattern.Find("{0}");
194 0 : if (index != kNotFound)
195 0 : pattern.Replace(index, 3, patternTime);
196 : }
197 :
198 : // Generate date/time string.
199 0 : nsAutoString timeZoneID(u"GMT");
200 0 : if (aTimeParameters) {
201 0 : int32_t totalOffsetMinutes = (aTimeParameters->tp_gmt_offset + aTimeParameters->tp_dst_offset) / 60;
202 0 : if (totalOffsetMinutes != 0) {
203 0 : char sign = totalOffsetMinutes < 0 ? '-' : '+';
204 0 : int32_t hours = abs(totalOffsetMinutes) / 60;
205 0 : int32_t minutes = abs(totalOffsetMinutes) % 60;
206 0 : timeZoneID.AppendPrintf("%c%02d:%02d", sign, hours, minutes);
207 : }
208 : }
209 :
210 : UDateFormat* dateTimeFormat;
211 0 : if (aTimeParameters) {
212 0 : dateTimeFormat = udat_open(UDAT_PATTERN, UDAT_PATTERN, mLocale->get(),
213 : reinterpret_cast<const UChar*>(timeZoneID.BeginReading()),
214 0 : timeZoneID.Length(),
215 : reinterpret_cast<const UChar*>(pattern.BeginReading()),
216 0 : pattern.Length(),
217 0 : &status);
218 : } else {
219 0 : dateTimeFormat = udat_open(UDAT_PATTERN, UDAT_PATTERN, mLocale->get(),
220 : nullptr, -1,
221 : reinterpret_cast<const UChar*>(pattern.BeginReading()),
222 0 : pattern.Length(),
223 0 : &status);
224 : }
225 :
226 0 : if (U_SUCCESS(status) && dateTimeFormat) {
227 0 : aStringOut.SetLength(DATETIME_FORMAT_INITIAL_LEN);
228 0 : dateTimeLen = udat_format(dateTimeFormat, aUDateTime,
229 : reinterpret_cast<UChar*>(aStringOut.BeginWriting()),
230 : DATETIME_FORMAT_INITIAL_LEN,
231 : nullptr,
232 0 : &status);
233 0 : aStringOut.SetLength(dateTimeLen);
234 :
235 0 : if (status == U_BUFFER_OVERFLOW_ERROR) {
236 0 : status = U_ZERO_ERROR;
237 0 : udat_format(dateTimeFormat, aUDateTime,
238 : reinterpret_cast<UChar*>(aStringOut.BeginWriting()),
239 : dateTimeLen,
240 : nullptr,
241 0 : &status);
242 : }
243 : }
244 :
245 0 : if (U_FAILURE(status)) {
246 0 : rv = NS_ERROR_FAILURE;
247 : }
248 :
249 0 : if (dateTimeFormat) {
250 0 : udat_close(dateTimeFormat);
251 : }
252 :
253 0 : return rv;
254 : }
255 :
256 : /*static*/ void
257 0 : DateTimeFormat::Shutdown()
258 : {
259 0 : if (mLocale) {
260 0 : delete mLocale;
261 : }
262 0 : }
263 :
264 : }
|