static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format) { CFDateFormatterStyle dateStyle = (format != LocaleTime ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle); CFDateFormatterStyle timeStyle = (format != LocaleDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle); bool useCustomFormat = false; String customFormatString; String arg0String = exec->argument(0).toString(exec)->value(exec); if (arg0String == "custom" && !exec->argument(1).isUndefined()) { useCustomFormat = true; customFormatString = exec->argument(1).toString(exec)->value(exec); } else if (format == LocaleDateAndTime && !exec->argument(1).isUndefined()) { dateStyle = styleFromArgString(arg0String, dateStyle); timeStyle = styleFromArgString(exec->argument(1).toString(exec)->value(exec), timeStyle); } else if (format != LocaleTime && !exec->argument(0).isUndefined()) dateStyle = styleFromArgString(arg0String, dateStyle); else if (format != LocaleDate && !exec->argument(0).isUndefined()) timeStyle = styleFromArgString(arg0String, timeStyle); CFAbsoluteTime absoluteTime = floor(timeInMilliseconds / msPerSecond) - kCFAbsoluteTimeIntervalSince1970; auto formatter = adoptCF(CFDateFormatterCreate(kCFAllocatorDefault, adoptCF(CFLocaleCopyCurrent()).get(), dateStyle, timeStyle)); if (useCustomFormat) CFDateFormatterSetFormat(formatter.get(), customFormatString.createCFString().get()); return jsNontrivialString(exec, adoptCF(CFDateFormatterCreateStringWithAbsoluteTime(kCFAllocatorDefault, formatter.get(), absoluteTime)).get()); }
static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format) { CFDateFormatterStyle dateStyle = (format != LocaleTime ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle); CFDateFormatterStyle timeStyle = (format != LocaleDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle); bool useCustomFormat = false; UString customFormatString; UString arg0String = exec->argument(0).toString(exec); if (arg0String == "custom" && !exec->argument(1).isUndefined()) { useCustomFormat = true; customFormatString = exec->argument(1).toString(exec); } else if (format == LocaleDateAndTime && !exec->argument(1).isUndefined()) { dateStyle = styleFromArgString(arg0String, dateStyle); timeStyle = styleFromArgString(exec->argument(1).toString(exec), timeStyle); } else if (format != LocaleTime && !exec->argument(0).isUndefined()) dateStyle = styleFromArgString(arg0String, dateStyle); else if (format != LocaleDate && !exec->argument(0).isUndefined()) timeStyle = styleFromArgString(arg0String, timeStyle); CFLocaleRef locale = CFLocaleCopyCurrent(); CFDateFormatterRef formatter = CFDateFormatterCreate(0, locale, dateStyle, timeStyle); CFRelease(locale); if (useCustomFormat) { CFStringRef customFormatCFString = CFStringCreateWithCharacters(0, customFormatString.characters(), customFormatString.length()); CFDateFormatterSetFormat(formatter, customFormatCFString); CFRelease(customFormatCFString); } CFStringRef string = CFDateFormatterCreateStringWithAbsoluteTime(0, formatter, floor(timeInMilliseconds / msPerSecond) - kCFAbsoluteTimeIntervalSince1970); CFRelease(formatter); // We truncate the string returned from CFDateFormatter if it's absurdly long (> 200 characters). // That's not great error handling, but it just won't happen so it doesn't matter. UChar buffer[200]; const size_t bufferLength = WTF_ARRAY_LENGTH(buffer); size_t length = CFStringGetLength(string); ASSERT(length <= bufferLength); if (length > bufferLength) length = bufferLength; CFStringGetCharacters(string, CFRangeMake(0, length), buffer); CFRelease(string); return jsNontrivialString(exec, UString(buffer, length)); }
// performs a locale sensitive date formatting operation on the struct tm parameter nsresult nsDateTimeFormatMac::FormatTMTime(nsILocale* locale, const nsDateFormatSelector dateFormatSelector, const nsTimeFormatSelector timeFormatSelector, const struct tm* tmTime, nsAString& stringOut) { nsresult res = NS_OK; // set up locale data (void) Initialize(locale); // return, nothing to format if (dateFormatSelector == kDateFormatNone && timeFormatSelector == kTimeFormatNone) { stringOut.Truncate(); return NS_OK; } NS_ASSERTION(tmTime->tm_mon >= 0, "tm is not set correctly"); NS_ASSERTION(tmTime->tm_mday >= 1, "tm is not set correctly"); NS_ASSERTION(tmTime->tm_hour >= 0, "tm is not set correctly"); NS_ASSERTION(tmTime->tm_min >= 0, "tm is not set correctly"); NS_ASSERTION(tmTime->tm_sec >= 0, "tm is not set correctly"); NS_ASSERTION(tmTime->tm_wday >= 0, "tm is not set correctly"); // Got the locale for the formatter: CFLocaleRef formatterLocale; if (!locale) { formatterLocale = CFLocaleCopyCurrent(); } else { CFStringRef localeStr = CFStringCreateWithCharacters(nullptr, reinterpret_cast<const UniChar*>(mLocale.get()), mLocale.Length()); formatterLocale = CFLocaleCreate(nullptr, localeStr); CFRelease(localeStr); } // Get the date style for the formatter: CFDateFormatterStyle dateStyle; switch (dateFormatSelector) { case kDateFormatLong: dateStyle = kCFDateFormatterLongStyle; break; case kDateFormatShort: dateStyle = kCFDateFormatterShortStyle; break; case kDateFormatYearMonth: case kDateFormatWeekday: dateStyle = kCFDateFormatterNoStyle; // formats handled below break; case kDateFormatNone: dateStyle = kCFDateFormatterNoStyle; break; default: NS_ERROR("Unknown nsDateFormatSelector"); res = NS_ERROR_FAILURE; dateStyle = kCFDateFormatterNoStyle; } // Get the time style for the formatter: CFDateFormatterStyle timeStyle; switch (timeFormatSelector) { case kTimeFormatSeconds: case kTimeFormatSecondsForce24Hour: // 24 hour part fixed below timeStyle = kCFDateFormatterMediumStyle; break; case kTimeFormatNoSeconds: case kTimeFormatNoSecondsForce24Hour: // 24 hour part fixed below timeStyle = kCFDateFormatterShortStyle; break; case kTimeFormatNone: timeStyle = kCFDateFormatterNoStyle; break; default: NS_ERROR("Unknown nsTimeFormatSelector"); res = NS_ERROR_FAILURE; timeStyle = kCFDateFormatterNoStyle; } // Create the formatter and fix up its formatting as necessary: CFDateFormatterRef formatter = CFDateFormatterCreate(nullptr, formatterLocale, dateStyle, timeStyle); CFRelease(formatterLocale); if (dateFormatSelector == kDateFormatYearMonth || dateFormatSelector == kDateFormatWeekday) { CFStringRef dateFormat = dateFormatSelector == kDateFormatYearMonth ? CFSTR("yyyy/MM ") : CFSTR("EEE "); CFStringRef oldFormat = CFDateFormatterGetFormat(formatter); CFMutableStringRef newFormat = CFStringCreateMutableCopy(nullptr, 0, oldFormat); CFStringInsert(newFormat, 0, dateFormat); CFDateFormatterSetFormat(formatter, newFormat); CFRelease(newFormat); // note we don't own oldFormat } if (timeFormatSelector == kTimeFormatSecondsForce24Hour || timeFormatSelector == kTimeFormatNoSecondsForce24Hour) { // Replace "h" with "H", and remove "a": CFStringRef oldFormat = CFDateFormatterGetFormat(formatter); CFMutableStringRef newFormat = CFStringCreateMutableCopy(nullptr, 0, oldFormat); CFIndex replaceCount = CFStringFindAndReplace(newFormat, CFSTR("h"), CFSTR("H"), CFRangeMake(0, CFStringGetLength(newFormat)), 0); NS_ASSERTION(replaceCount <= 2, "Unexpected number of \"h\" occurrences"); replaceCount = CFStringFindAndReplace(newFormat, CFSTR("a"), CFSTR(""), CFRangeMake(0, CFStringGetLength(newFormat)), 0); NS_ASSERTION(replaceCount <= 1, "Unexpected number of \"a\" occurrences"); CFDateFormatterSetFormat(formatter, newFormat); CFRelease(newFormat); // note we don't own oldFormat } // Now get the formatted date: CFGregorianDate date; date.second = tmTime->tm_sec; date.minute = tmTime->tm_min; date.hour = tmTime->tm_hour; date.day = tmTime->tm_mday; // Mac is 1-based, tm is 1-based date.month = tmTime->tm_mon + 1; // Mac is 1-based, tm is 0-based date.year = tmTime->tm_year + 1900; CFTimeZoneRef timeZone = CFTimeZoneCopySystem(); // tmTime is in local time CFAbsoluteTime absTime = CFGregorianDateGetAbsoluteTime(date, timeZone); CFRelease(timeZone); CFStringRef formattedDate = CFDateFormatterCreateStringWithAbsoluteTime(nullptr, formatter, absTime); CFIndex stringLen = CFStringGetLength(formattedDate); AutoTArray<UniChar, 256> stringBuffer; stringBuffer.SetLength(stringLen + 1); CFStringGetCharacters(formattedDate, CFRangeMake(0, stringLen), stringBuffer.Elements()); stringOut.Assign(reinterpret_cast<char16_t*>(stringBuffer.Elements()), stringLen); CFRelease(formattedDate); CFRelease(formatter); return res; }