intl/locale/src/mac/nsDateTimeFormatMac.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

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

mercurial