Bumping manifests a=b2g-bump
[gecko.git] / intl / locale / mac / nsDateTimeFormatMac.cpp
blobe4ab1fc822f092a5609bb56d81134041dd2f38bb
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include <CoreFoundation/CoreFoundation.h>
7 #include "nsIServiceManager.h"
8 #include "nsDateTimeFormatMac.h"
9 #include <CoreFoundation/CFDateFormatter.h>
10 #include "nsIComponentManager.h"
11 #include "nsILocaleService.h"
12 #include "nsCRT.h"
13 #include "plstr.h"
14 #include "nsUnicharUtils.h"
15 #include "nsTArray.h"
18 NS_IMPL_ISUPPORTS(nsDateTimeFormatMac, nsIDateTimeFormat)
20 nsresult nsDateTimeFormatMac::Initialize(nsILocale* locale)
22 nsAutoString localeStr;
23 nsAutoString category(NS_LITERAL_STRING("NSILOCALE_TIME"));
24 nsresult res;
26 // use cached info if match with stored locale
27 if (nullptr == locale) {
28 if (!mLocale.IsEmpty() &&
29 mLocale.Equals(mAppLocale, nsCaseInsensitiveStringComparator())) {
30 return NS_OK;
33 else {
34 res = locale->GetCategory(category, localeStr);
35 if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) {
36 if (!mLocale.IsEmpty() &&
37 mLocale.Equals(localeStr,
38 nsCaseInsensitiveStringComparator())) {
39 return NS_OK;
44 // get application locale
45 nsCOMPtr<nsILocaleService> localeService =
46 do_GetService(NS_LOCALESERVICE_CONTRACTID, &res);
47 if (NS_SUCCEEDED(res)) {
48 nsCOMPtr<nsILocale> appLocale;
49 res = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
50 if (NS_SUCCEEDED(res)) {
51 res = appLocale->GetCategory(category, localeStr);
52 if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) {
53 mAppLocale = localeStr; // cache app locale name
58 // use app default if no locale specified
59 if (nullptr == locale) {
60 mUseDefaultLocale = true;
62 else {
63 mUseDefaultLocale = false;
64 res = locale->GetCategory(category, localeStr);
67 if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) {
68 mLocale.Assign(localeStr); // cache locale name
71 return res;
74 // performs a locale sensitive date formatting operation on the time_t parameter
75 nsresult nsDateTimeFormatMac::FormatTime(nsILocale* locale,
76 const nsDateFormatSelector dateFormatSelector,
77 const nsTimeFormatSelector timeFormatSelector,
78 const time_t timetTime,
79 nsAString& stringOut)
81 struct tm tmTime;
82 return FormatTMTime(locale, dateFormatSelector, timeFormatSelector, localtime_r(&timetTime, &tmTime), stringOut);
85 // performs a locale sensitive date formatting operation on the struct tm parameter
86 nsresult nsDateTimeFormatMac::FormatTMTime(nsILocale* locale,
87 const nsDateFormatSelector dateFormatSelector,
88 const nsTimeFormatSelector timeFormatSelector,
89 const struct tm* tmTime,
90 nsAString& stringOut)
92 nsresult res = NS_OK;
94 // set up locale data
95 (void) Initialize(locale);
97 // return, nothing to format
98 if (dateFormatSelector == kDateFormatNone && timeFormatSelector == kTimeFormatNone) {
99 stringOut.Truncate();
100 return NS_OK;
103 NS_ASSERTION(tmTime->tm_mon >= 0, "tm is not set correctly");
104 NS_ASSERTION(tmTime->tm_mday >= 1, "tm is not set correctly");
105 NS_ASSERTION(tmTime->tm_hour >= 0, "tm is not set correctly");
106 NS_ASSERTION(tmTime->tm_min >= 0, "tm is not set correctly");
107 NS_ASSERTION(tmTime->tm_sec >= 0, "tm is not set correctly");
108 NS_ASSERTION(tmTime->tm_wday >= 0, "tm is not set correctly");
110 // Got the locale for the formatter:
111 CFLocaleRef formatterLocale;
112 if (!locale) {
113 formatterLocale = CFLocaleCopyCurrent();
114 } else {
115 CFStringRef localeStr = CFStringCreateWithCharacters(nullptr,
116 reinterpret_cast<const UniChar*>(mLocale.get()),
117 mLocale.Length());
118 formatterLocale = CFLocaleCreate(nullptr, localeStr);
119 CFRelease(localeStr);
122 // Get the date style for the formatter:
123 CFDateFormatterStyle dateStyle;
124 switch (dateFormatSelector) {
125 case kDateFormatLong:
126 dateStyle = kCFDateFormatterLongStyle;
127 break;
128 case kDateFormatShort:
129 dateStyle = kCFDateFormatterShortStyle;
130 break;
131 case kDateFormatYearMonth:
132 case kDateFormatWeekday:
133 dateStyle = kCFDateFormatterNoStyle; // formats handled below
134 break;
135 case kDateFormatNone:
136 dateStyle = kCFDateFormatterNoStyle;
137 break;
138 default:
139 NS_ERROR("Unknown nsDateFormatSelector");
140 res = NS_ERROR_FAILURE;
141 dateStyle = kCFDateFormatterNoStyle;
144 // Get the time style for the formatter:
145 CFDateFormatterStyle timeStyle;
146 switch (timeFormatSelector) {
147 case kTimeFormatSeconds:
148 case kTimeFormatSecondsForce24Hour: // 24 hour part fixed below
149 timeStyle = kCFDateFormatterMediumStyle;
150 break;
151 case kTimeFormatNoSeconds:
152 case kTimeFormatNoSecondsForce24Hour: // 24 hour part fixed below
153 timeStyle = kCFDateFormatterShortStyle;
154 break;
155 case kTimeFormatNone:
156 timeStyle = kCFDateFormatterNoStyle;
157 break;
158 default:
159 NS_ERROR("Unknown nsTimeFormatSelector");
160 res = NS_ERROR_FAILURE;
161 timeStyle = kCFDateFormatterNoStyle;
164 // Create the formatter and fix up its formatting as necessary:
165 CFDateFormatterRef formatter =
166 CFDateFormatterCreate(nullptr, formatterLocale, dateStyle, timeStyle);
168 CFRelease(formatterLocale);
170 if (dateFormatSelector == kDateFormatYearMonth ||
171 dateFormatSelector == kDateFormatWeekday) {
172 CFStringRef dateFormat =
173 dateFormatSelector == kDateFormatYearMonth ? CFSTR("yyyy/MM ") : CFSTR("EEE ");
175 CFStringRef oldFormat = CFDateFormatterGetFormat(formatter);
176 CFMutableStringRef newFormat = CFStringCreateMutableCopy(nullptr, 0, oldFormat);
177 CFStringInsert(newFormat, 0, dateFormat);
178 CFDateFormatterSetFormat(formatter, newFormat);
179 CFRelease(newFormat); // note we don't own oldFormat
182 if (timeFormatSelector == kTimeFormatSecondsForce24Hour ||
183 timeFormatSelector == kTimeFormatNoSecondsForce24Hour) {
184 // Replace "h" with "H", and remove "a":
185 CFStringRef oldFormat = CFDateFormatterGetFormat(formatter);
186 CFMutableStringRef newFormat = CFStringCreateMutableCopy(nullptr, 0, oldFormat);
187 CFIndex replaceCount = CFStringFindAndReplace(newFormat,
188 CFSTR("h"), CFSTR("H"),
189 CFRangeMake(0, CFStringGetLength(newFormat)),
191 NS_ASSERTION(replaceCount <= 2, "Unexpected number of \"h\" occurrences");
192 replaceCount = CFStringFindAndReplace(newFormat,
193 CFSTR("a"), CFSTR(""),
194 CFRangeMake(0, CFStringGetLength(newFormat)),
196 NS_ASSERTION(replaceCount <= 1, "Unexpected number of \"a\" occurrences");
197 CFDateFormatterSetFormat(formatter, newFormat);
198 CFRelease(newFormat); // note we don't own oldFormat
201 // Now get the formatted date:
202 CFGregorianDate date;
203 date.second = tmTime->tm_sec;
204 date.minute = tmTime->tm_min;
205 date.hour = tmTime->tm_hour;
206 date.day = tmTime->tm_mday; // Mac is 1-based, tm is 1-based
207 date.month = tmTime->tm_mon + 1; // Mac is 1-based, tm is 0-based
208 date.year = tmTime->tm_year + 1900;
210 CFTimeZoneRef timeZone = CFTimeZoneCopySystem(); // tmTime is in local time
211 CFAbsoluteTime absTime = CFGregorianDateGetAbsoluteTime(date, timeZone);
212 CFRelease(timeZone);
214 CFStringRef formattedDate = CFDateFormatterCreateStringWithAbsoluteTime(nullptr,
215 formatter,
216 absTime);
218 CFIndex stringLen = CFStringGetLength(formattedDate);
220 nsAutoTArray<UniChar, 256> stringBuffer;
221 stringBuffer.SetLength(stringLen + 1);
222 CFStringGetCharacters(formattedDate, CFRangeMake(0, stringLen), stringBuffer.Elements());
223 stringOut.Assign(reinterpret_cast<char16_t*>(stringBuffer.Elements()), stringLen);
225 CFRelease(formattedDate);
226 CFRelease(formatter);
228 return res;
231 // performs a locale sensitive date formatting operation on the PRTime parameter
232 nsresult nsDateTimeFormatMac::FormatPRTime(nsILocale* locale,
233 const nsDateFormatSelector dateFormatSelector,
234 const nsTimeFormatSelector timeFormatSelector,
235 const PRTime prTime,
236 nsAString& stringOut)
238 PRExplodedTime explodedTime;
239 PR_ExplodeTime(prTime, PR_LocalTimeParameters, &explodedTime);
241 return FormatPRExplodedTime(locale, dateFormatSelector, timeFormatSelector, &explodedTime, stringOut);
244 // performs a locale sensitive date formatting operation on the PRExplodedTime parameter
245 nsresult nsDateTimeFormatMac::FormatPRExplodedTime(nsILocale* locale,
246 const nsDateFormatSelector dateFormatSelector,
247 const nsTimeFormatSelector timeFormatSelector,
248 const PRExplodedTime* explodedTime,
249 nsAString& stringOut)
251 struct tm tmTime;
252 memset( &tmTime, 0, sizeof(tmTime) );
254 tmTime.tm_yday = explodedTime->tm_yday;
255 tmTime.tm_wday = explodedTime->tm_wday;
256 tmTime.tm_year = explodedTime->tm_year;
257 tmTime.tm_year -= 1900;
258 tmTime.tm_mon = explodedTime->tm_month;
259 tmTime.tm_mday = explodedTime->tm_mday;
260 tmTime.tm_hour = explodedTime->tm_hour;
261 tmTime.tm_min = explodedTime->tm_min;
262 tmTime.tm_sec = explodedTime->tm_sec;
264 return FormatTMTime(locale, dateFormatSelector, timeFormatSelector, &tmTime, stringOut);