|
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/. */ |
|
5 |
|
6 #include "nsDateTimeFormatWin.h" |
|
7 #include "nsIServiceManager.h" |
|
8 #include "nsIComponentManager.h" |
|
9 #include "nsILocaleService.h" |
|
10 #include "nsWin32Locale.h" |
|
11 #include "nsUnicharUtils.h" |
|
12 #include "nsCRT.h" |
|
13 #include "nsCOMPtr.h" |
|
14 |
|
15 |
|
16 #define NSDATETIMEFORMAT_BUFFER_LEN 80 |
|
17 |
|
18 NS_IMPL_ISUPPORTS(nsDateTimeFormatWin, nsIDateTimeFormat) |
|
19 |
|
20 |
|
21 // init this interface to a specified locale |
|
22 nsresult nsDateTimeFormatWin::Initialize(nsILocale* locale) |
|
23 { |
|
24 nsAutoString localeStr; |
|
25 nsresult res = NS_OK; |
|
26 |
|
27 // use cached info if match with stored locale |
|
28 if (!locale) { |
|
29 if (!mLocale.IsEmpty() && |
|
30 mLocale.Equals(mAppLocale, nsCaseInsensitiveStringComparator())) { |
|
31 return NS_OK; |
|
32 } |
|
33 } |
|
34 else { |
|
35 res = locale->GetCategory(NS_LITERAL_STRING("NSILOCALE_TIME"), localeStr); |
|
36 if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) { |
|
37 if (!mLocale.IsEmpty() && |
|
38 mLocale.Equals(localeStr, nsCaseInsensitiveStringComparator())) { |
|
39 return NS_OK; |
|
40 } |
|
41 } |
|
42 } |
|
43 |
|
44 // default LCID (en-US) |
|
45 mLCID = 1033; |
|
46 |
|
47 // get locale string, use app default if no locale specified |
|
48 if (!locale) { |
|
49 nsCOMPtr<nsILocaleService> localeService = |
|
50 do_GetService(NS_LOCALESERVICE_CONTRACTID); |
|
51 if (localeService) { |
|
52 nsCOMPtr<nsILocale> appLocale; |
|
53 res = localeService->GetApplicationLocale(getter_AddRefs(appLocale)); |
|
54 if (NS_SUCCEEDED(res)) { |
|
55 res = appLocale->GetCategory(NS_LITERAL_STRING("NSILOCALE_TIME"), |
|
56 localeStr); |
|
57 if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) { |
|
58 mAppLocale.Assign(localeStr); // cache app locale name |
|
59 } |
|
60 } |
|
61 } |
|
62 } |
|
63 else { |
|
64 res = locale->GetCategory(NS_LITERAL_STRING("NSILOCALE_TIME"), localeStr); |
|
65 } |
|
66 |
|
67 // Get LCID and charset name from locale, if available |
|
68 if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) { |
|
69 mLocale.Assign(localeStr); // cache locale name |
|
70 res = nsWin32Locale::GetPlatformLocale(mLocale, (LCID *) &mLCID); |
|
71 } |
|
72 |
|
73 return res; |
|
74 } |
|
75 |
|
76 // performs a locale sensitive date formatting operation on the time_t parameter |
|
77 nsresult nsDateTimeFormatWin::FormatTime(nsILocale* locale, |
|
78 const nsDateFormatSelector dateFormatSelector, |
|
79 const nsTimeFormatSelector timeFormatSelector, |
|
80 const time_t timetTime, |
|
81 nsAString& stringOut) |
|
82 { |
|
83 return FormatTMTime(locale, dateFormatSelector, timeFormatSelector, localtime( &timetTime ), stringOut); |
|
84 } |
|
85 |
|
86 // performs a locale sensitive date formatting operation on the struct tm parameter |
|
87 nsresult nsDateTimeFormatWin::FormatTMTime(nsILocale* locale, |
|
88 const nsDateFormatSelector dateFormatSelector, |
|
89 const nsTimeFormatSelector timeFormatSelector, |
|
90 const struct tm* tmTime, |
|
91 nsAString& stringOut) |
|
92 { |
|
93 SYSTEMTIME system_time; |
|
94 DWORD dwFlags_Date = 0, dwFlags_Time = 0; |
|
95 int dateLen, timeLen; |
|
96 char16_t dateBuffer[NSDATETIMEFORMAT_BUFFER_LEN], timeBuffer[NSDATETIMEFORMAT_BUFFER_LEN]; |
|
97 |
|
98 // set up locale data |
|
99 (void) Initialize(locale); |
|
100 |
|
101 // Map tm to SYSTEMTIME |
|
102 system_time.wYear = 1900 + tmTime->tm_year; |
|
103 system_time.wMonth = tmTime->tm_mon + 1; |
|
104 system_time.wDayOfWeek = tmTime->tm_wday; |
|
105 system_time.wDay = tmTime->tm_mday; |
|
106 system_time.wHour = tmTime->tm_hour; |
|
107 system_time.wMinute = tmTime->tm_min; |
|
108 system_time.wSecond = tmTime->tm_sec; |
|
109 system_time.wMilliseconds = 0; |
|
110 |
|
111 // Map to WinAPI date format |
|
112 switch (dateFormatSelector) { |
|
113 case kDateFormatLong: |
|
114 dwFlags_Date = DATE_LONGDATE; |
|
115 break; |
|
116 case kDateFormatShort: |
|
117 dwFlags_Date = DATE_SHORTDATE; |
|
118 break; |
|
119 case kDateFormatWeekday: |
|
120 dwFlags_Date = 0; |
|
121 break; |
|
122 case kDateFormatYearMonth: |
|
123 dwFlags_Date = 0; // TODO:only availabe NT5 |
|
124 break; |
|
125 } |
|
126 |
|
127 // Map to WinAPI time format |
|
128 switch (timeFormatSelector) { |
|
129 case kTimeFormatSeconds: |
|
130 dwFlags_Time = 0; |
|
131 break; |
|
132 case kTimeFormatNoSeconds: |
|
133 dwFlags_Time = TIME_NOSECONDS; |
|
134 break; |
|
135 case kTimeFormatSecondsForce24Hour: |
|
136 dwFlags_Time = TIME_FORCE24HOURFORMAT; |
|
137 break; |
|
138 case kTimeFormatNoSecondsForce24Hour: |
|
139 dwFlags_Time = TIME_NOSECONDS + TIME_FORCE24HOURFORMAT; |
|
140 break; |
|
141 } |
|
142 |
|
143 // Call GetDateFormatW |
|
144 if (dateFormatSelector == kDateFormatNone) { |
|
145 dateLen = 0; |
|
146 } |
|
147 else { |
|
148 if (dateFormatSelector == kDateFormatYearMonth) { |
|
149 dateLen = nsGetDateFormatW(0, &system_time, "yyyy/MM", |
|
150 dateBuffer, NSDATETIMEFORMAT_BUFFER_LEN); |
|
151 } |
|
152 else if (dateFormatSelector == kDateFormatWeekday) { |
|
153 dateLen = nsGetDateFormatW(0, &system_time, "ddd", |
|
154 dateBuffer, NSDATETIMEFORMAT_BUFFER_LEN); |
|
155 } |
|
156 else { |
|
157 dateLen = nsGetDateFormatW(dwFlags_Date, &system_time, nullptr, |
|
158 dateBuffer, NSDATETIMEFORMAT_BUFFER_LEN); |
|
159 } |
|
160 if (dateLen != 0) { |
|
161 dateLen--; // Since the count includes the terminating null. |
|
162 } |
|
163 } |
|
164 |
|
165 // Call GetTimeFormatW |
|
166 if (timeFormatSelector == kTimeFormatNone) { |
|
167 timeLen = 0; |
|
168 } |
|
169 else { |
|
170 timeLen = nsGetTimeFormatW(dwFlags_Time, &system_time, nullptr, |
|
171 timeBuffer, NSDATETIMEFORMAT_BUFFER_LEN); |
|
172 if (timeLen != 0) { |
|
173 timeLen--; // Since the count includes the terminating null. |
|
174 } |
|
175 } |
|
176 |
|
177 NS_ASSERTION(NSDATETIMEFORMAT_BUFFER_LEN >= (uint32_t) (dateLen + 1), "internal date buffer is not large enough"); |
|
178 NS_ASSERTION(NSDATETIMEFORMAT_BUFFER_LEN >= (uint32_t) (timeLen + 1), "internal time buffer is not large enough"); |
|
179 |
|
180 // Copy the result |
|
181 stringOut.Truncate(); |
|
182 if (dateLen != 0 && timeLen != 0) { |
|
183 stringOut.Assign(dateBuffer, dateLen); |
|
184 stringOut.Append((char16_t *)(L" "), 1); |
|
185 stringOut.Append(timeBuffer, timeLen); |
|
186 } |
|
187 else if (dateLen != 0 && timeLen == 0) { |
|
188 stringOut.Assign(dateBuffer, dateLen); |
|
189 } |
|
190 else if (dateLen == 0 && timeLen != 0) { |
|
191 stringOut.Assign(timeBuffer, timeLen); |
|
192 } |
|
193 |
|
194 return NS_OK; |
|
195 } |
|
196 |
|
197 // performs a locale sensitive date formatting operation on the PRTime parameter |
|
198 nsresult nsDateTimeFormatWin::FormatPRTime(nsILocale* locale, |
|
199 const nsDateFormatSelector dateFormatSelector, |
|
200 const nsTimeFormatSelector timeFormatSelector, |
|
201 const PRTime prTime, |
|
202 nsAString& stringOut) |
|
203 { |
|
204 PRExplodedTime explodedTime; |
|
205 PR_ExplodeTime(prTime, PR_LocalTimeParameters, &explodedTime); |
|
206 |
|
207 return FormatPRExplodedTime(locale, dateFormatSelector, timeFormatSelector, &explodedTime, stringOut); |
|
208 } |
|
209 |
|
210 // performs a locale sensitive date formatting operation on the PRExplodedTime parameter |
|
211 nsresult nsDateTimeFormatWin::FormatPRExplodedTime(nsILocale* locale, |
|
212 const nsDateFormatSelector dateFormatSelector, |
|
213 const nsTimeFormatSelector timeFormatSelector, |
|
214 const PRExplodedTime* explodedTime, |
|
215 nsAString& stringOut) |
|
216 { |
|
217 struct tm tmTime; |
|
218 memset( &tmTime, 0, sizeof(tmTime) ); |
|
219 |
|
220 tmTime.tm_yday = explodedTime->tm_yday; |
|
221 tmTime.tm_wday = explodedTime->tm_wday; |
|
222 tmTime.tm_year = explodedTime->tm_year; |
|
223 tmTime.tm_year -= 1900; |
|
224 tmTime.tm_mon = explodedTime->tm_month; |
|
225 tmTime.tm_mday = explodedTime->tm_mday; |
|
226 tmTime.tm_hour = explodedTime->tm_hour; |
|
227 tmTime.tm_min = explodedTime->tm_min; |
|
228 tmTime.tm_sec = explodedTime->tm_sec; |
|
229 |
|
230 return FormatTMTime(locale, dateFormatSelector, timeFormatSelector, &tmTime, stringOut); |
|
231 } |
|
232 |
|
233 int nsDateTimeFormatWin::nsGetTimeFormatW(DWORD dwFlags, const SYSTEMTIME *lpTime, |
|
234 const char* format, char16_t *timeStr, int cchTime) |
|
235 { |
|
236 int len = 0; |
|
237 len = GetTimeFormatW(mLCID, dwFlags, lpTime, |
|
238 format ? |
|
239 NS_ConvertASCIItoUTF16(format).get() : |
|
240 nullptr, |
|
241 (LPWSTR) timeStr, cchTime); |
|
242 return len; |
|
243 } |
|
244 |
|
245 int nsDateTimeFormatWin::nsGetDateFormatW(DWORD dwFlags, const SYSTEMTIME *lpDate, |
|
246 const char* format, char16_t *dateStr, int cchDate) |
|
247 { |
|
248 int len = 0; |
|
249 len = GetDateFormatW(mLCID, dwFlags, lpDate, |
|
250 format ? NS_ConvertASCIItoUTF16(format).get() : nullptr, |
|
251 (LPWSTR) dateStr, cchDate); |
|
252 return len; |
|
253 } |