michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsDateTimeFormatWin.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsIComponentManager.h" michael@0: #include "nsILocaleService.h" michael@0: #include "nsWin32Locale.h" michael@0: #include "nsUnicharUtils.h" michael@0: #include "nsCRT.h" michael@0: #include "nsCOMPtr.h" michael@0: michael@0: michael@0: #define NSDATETIMEFORMAT_BUFFER_LEN 80 michael@0: michael@0: NS_IMPL_ISUPPORTS(nsDateTimeFormatWin, nsIDateTimeFormat) michael@0: michael@0: michael@0: // init this interface to a specified locale michael@0: nsresult nsDateTimeFormatWin::Initialize(nsILocale* locale) michael@0: { michael@0: nsAutoString localeStr; michael@0: nsresult res = NS_OK; michael@0: michael@0: // use cached info if match with stored locale michael@0: if (!locale) { michael@0: if (!mLocale.IsEmpty() && michael@0: mLocale.Equals(mAppLocale, nsCaseInsensitiveStringComparator())) { michael@0: return NS_OK; michael@0: } michael@0: } michael@0: else { michael@0: res = locale->GetCategory(NS_LITERAL_STRING("NSILOCALE_TIME"), localeStr); michael@0: if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) { michael@0: if (!mLocale.IsEmpty() && michael@0: mLocale.Equals(localeStr, nsCaseInsensitiveStringComparator())) { michael@0: return NS_OK; michael@0: } michael@0: } michael@0: } michael@0: michael@0: // default LCID (en-US) michael@0: mLCID = 1033; michael@0: michael@0: // get locale string, use app default if no locale specified michael@0: if (!locale) { michael@0: nsCOMPtr localeService = michael@0: do_GetService(NS_LOCALESERVICE_CONTRACTID); michael@0: if (localeService) { michael@0: nsCOMPtr appLocale; michael@0: res = localeService->GetApplicationLocale(getter_AddRefs(appLocale)); michael@0: if (NS_SUCCEEDED(res)) { michael@0: res = appLocale->GetCategory(NS_LITERAL_STRING("NSILOCALE_TIME"), michael@0: localeStr); michael@0: if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) { michael@0: mAppLocale.Assign(localeStr); // cache app locale name michael@0: } michael@0: } michael@0: } michael@0: } michael@0: else { michael@0: res = locale->GetCategory(NS_LITERAL_STRING("NSILOCALE_TIME"), localeStr); michael@0: } michael@0: michael@0: // Get LCID and charset name from locale, if available michael@0: if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) { michael@0: mLocale.Assign(localeStr); // cache locale name michael@0: res = nsWin32Locale::GetPlatformLocale(mLocale, (LCID *) &mLCID); michael@0: } michael@0: michael@0: return res; michael@0: } michael@0: michael@0: // performs a locale sensitive date formatting operation on the time_t parameter michael@0: nsresult nsDateTimeFormatWin::FormatTime(nsILocale* locale, michael@0: const nsDateFormatSelector dateFormatSelector, michael@0: const nsTimeFormatSelector timeFormatSelector, michael@0: const time_t timetTime, michael@0: nsAString& stringOut) michael@0: { michael@0: return FormatTMTime(locale, dateFormatSelector, timeFormatSelector, localtime( &timetTime ), stringOut); michael@0: } michael@0: michael@0: // performs a locale sensitive date formatting operation on the struct tm parameter michael@0: nsresult nsDateTimeFormatWin::FormatTMTime(nsILocale* locale, michael@0: const nsDateFormatSelector dateFormatSelector, michael@0: const nsTimeFormatSelector timeFormatSelector, michael@0: const struct tm* tmTime, michael@0: nsAString& stringOut) michael@0: { michael@0: SYSTEMTIME system_time; michael@0: DWORD dwFlags_Date = 0, dwFlags_Time = 0; michael@0: int dateLen, timeLen; michael@0: char16_t dateBuffer[NSDATETIMEFORMAT_BUFFER_LEN], timeBuffer[NSDATETIMEFORMAT_BUFFER_LEN]; michael@0: michael@0: // set up locale data michael@0: (void) Initialize(locale); michael@0: michael@0: // Map tm to SYSTEMTIME michael@0: system_time.wYear = 1900 + tmTime->tm_year; michael@0: system_time.wMonth = tmTime->tm_mon + 1; michael@0: system_time.wDayOfWeek = tmTime->tm_wday; michael@0: system_time.wDay = tmTime->tm_mday; michael@0: system_time.wHour = tmTime->tm_hour; michael@0: system_time.wMinute = tmTime->tm_min; michael@0: system_time.wSecond = tmTime->tm_sec; michael@0: system_time.wMilliseconds = 0; michael@0: michael@0: // Map to WinAPI date format michael@0: switch (dateFormatSelector) { michael@0: case kDateFormatLong: michael@0: dwFlags_Date = DATE_LONGDATE; michael@0: break; michael@0: case kDateFormatShort: michael@0: dwFlags_Date = DATE_SHORTDATE; michael@0: break; michael@0: case kDateFormatWeekday: michael@0: dwFlags_Date = 0; michael@0: break; michael@0: case kDateFormatYearMonth: michael@0: dwFlags_Date = 0; // TODO:only availabe NT5 michael@0: break; michael@0: } michael@0: michael@0: // Map to WinAPI time format michael@0: switch (timeFormatSelector) { michael@0: case kTimeFormatSeconds: michael@0: dwFlags_Time = 0; michael@0: break; michael@0: case kTimeFormatNoSeconds: michael@0: dwFlags_Time = TIME_NOSECONDS; michael@0: break; michael@0: case kTimeFormatSecondsForce24Hour: michael@0: dwFlags_Time = TIME_FORCE24HOURFORMAT; michael@0: break; michael@0: case kTimeFormatNoSecondsForce24Hour: michael@0: dwFlags_Time = TIME_NOSECONDS + TIME_FORCE24HOURFORMAT; michael@0: break; michael@0: } michael@0: michael@0: // Call GetDateFormatW michael@0: if (dateFormatSelector == kDateFormatNone) { michael@0: dateLen = 0; michael@0: } michael@0: else { michael@0: if (dateFormatSelector == kDateFormatYearMonth) { michael@0: dateLen = nsGetDateFormatW(0, &system_time, "yyyy/MM", michael@0: dateBuffer, NSDATETIMEFORMAT_BUFFER_LEN); michael@0: } michael@0: else if (dateFormatSelector == kDateFormatWeekday) { michael@0: dateLen = nsGetDateFormatW(0, &system_time, "ddd", michael@0: dateBuffer, NSDATETIMEFORMAT_BUFFER_LEN); michael@0: } michael@0: else { michael@0: dateLen = nsGetDateFormatW(dwFlags_Date, &system_time, nullptr, michael@0: dateBuffer, NSDATETIMEFORMAT_BUFFER_LEN); michael@0: } michael@0: if (dateLen != 0) { michael@0: dateLen--; // Since the count includes the terminating null. michael@0: } michael@0: } michael@0: michael@0: // Call GetTimeFormatW michael@0: if (timeFormatSelector == kTimeFormatNone) { michael@0: timeLen = 0; michael@0: } michael@0: else { michael@0: timeLen = nsGetTimeFormatW(dwFlags_Time, &system_time, nullptr, michael@0: timeBuffer, NSDATETIMEFORMAT_BUFFER_LEN); michael@0: if (timeLen != 0) { michael@0: timeLen--; // Since the count includes the terminating null. michael@0: } michael@0: } michael@0: michael@0: NS_ASSERTION(NSDATETIMEFORMAT_BUFFER_LEN >= (uint32_t) (dateLen + 1), "internal date buffer is not large enough"); michael@0: NS_ASSERTION(NSDATETIMEFORMAT_BUFFER_LEN >= (uint32_t) (timeLen + 1), "internal time buffer is not large enough"); michael@0: michael@0: // Copy the result michael@0: stringOut.Truncate(); michael@0: if (dateLen != 0 && timeLen != 0) { michael@0: stringOut.Assign(dateBuffer, dateLen); michael@0: stringOut.Append((char16_t *)(L" "), 1); michael@0: stringOut.Append(timeBuffer, timeLen); michael@0: } michael@0: else if (dateLen != 0 && timeLen == 0) { michael@0: stringOut.Assign(dateBuffer, dateLen); michael@0: } michael@0: else if (dateLen == 0 && timeLen != 0) { michael@0: stringOut.Assign(timeBuffer, timeLen); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // performs a locale sensitive date formatting operation on the PRTime parameter michael@0: nsresult nsDateTimeFormatWin::FormatPRTime(nsILocale* locale, michael@0: const nsDateFormatSelector dateFormatSelector, michael@0: const nsTimeFormatSelector timeFormatSelector, michael@0: const PRTime prTime, michael@0: nsAString& stringOut) michael@0: { michael@0: PRExplodedTime explodedTime; michael@0: PR_ExplodeTime(prTime, PR_LocalTimeParameters, &explodedTime); michael@0: michael@0: return FormatPRExplodedTime(locale, dateFormatSelector, timeFormatSelector, &explodedTime, stringOut); michael@0: } michael@0: michael@0: // performs a locale sensitive date formatting operation on the PRExplodedTime parameter michael@0: nsresult nsDateTimeFormatWin::FormatPRExplodedTime(nsILocale* locale, michael@0: const nsDateFormatSelector dateFormatSelector, michael@0: const nsTimeFormatSelector timeFormatSelector, michael@0: const PRExplodedTime* explodedTime, michael@0: nsAString& stringOut) michael@0: { michael@0: struct tm tmTime; michael@0: memset( &tmTime, 0, sizeof(tmTime) ); michael@0: michael@0: tmTime.tm_yday = explodedTime->tm_yday; michael@0: tmTime.tm_wday = explodedTime->tm_wday; michael@0: tmTime.tm_year = explodedTime->tm_year; michael@0: tmTime.tm_year -= 1900; michael@0: tmTime.tm_mon = explodedTime->tm_month; michael@0: tmTime.tm_mday = explodedTime->tm_mday; michael@0: tmTime.tm_hour = explodedTime->tm_hour; michael@0: tmTime.tm_min = explodedTime->tm_min; michael@0: tmTime.tm_sec = explodedTime->tm_sec; michael@0: michael@0: return FormatTMTime(locale, dateFormatSelector, timeFormatSelector, &tmTime, stringOut); michael@0: } michael@0: michael@0: int nsDateTimeFormatWin::nsGetTimeFormatW(DWORD dwFlags, const SYSTEMTIME *lpTime, michael@0: const char* format, char16_t *timeStr, int cchTime) michael@0: { michael@0: int len = 0; michael@0: len = GetTimeFormatW(mLCID, dwFlags, lpTime, michael@0: format ? michael@0: NS_ConvertASCIItoUTF16(format).get() : michael@0: nullptr, michael@0: (LPWSTR) timeStr, cchTime); michael@0: return len; michael@0: } michael@0: michael@0: int nsDateTimeFormatWin::nsGetDateFormatW(DWORD dwFlags, const SYSTEMTIME *lpDate, michael@0: const char* format, char16_t *dateStr, int cchDate) michael@0: { michael@0: int len = 0; michael@0: len = GetDateFormatW(mLCID, dwFlags, lpDate, michael@0: format ? NS_ConvertASCIItoUTF16(format).get() : nullptr, michael@0: (LPWSTR) dateStr, cchDate); michael@0: return len; michael@0: }