Back to index

lightning-sunbird  0.9+nobinonly
nsDateTimeFormatWin.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsDateTimeFormatWin.h"
00040 #include "nsIServiceManager.h"
00041 #include "nsIComponentManager.h"
00042 #include "nsLocaleCID.h"
00043 #include "nsILocaleService.h"
00044 #include "nsIWin32Locale.h"
00045 #include "nsUnicharUtils.h"
00046 #include "nsCRT.h"
00047 #include "nsCOMPtr.h"
00048 #include "prmem.h"
00049 
00050 
00051 #define NSDATETIMEFORMAT_BUFFER_LEN  80
00052 
00053 NS_IMPL_THREADSAFE_ISUPPORTS1(nsDateTimeFormatWin, nsIDateTimeFormat)
00054 
00055 
00056 // init this interface to a specified locale
00057 nsresult nsDateTimeFormatWin::Initialize(nsILocale* locale)
00058 {
00059   nsAutoString localeStr;
00060   nsresult res = NS_OK;
00061 
00062   // use cached info if match with stored locale
00063   if (NULL == locale) {
00064     if (!mLocale.IsEmpty() && 
00065         mLocale.Equals(mAppLocale, nsCaseInsensitiveStringComparator())) {
00066       return NS_OK;
00067     }
00068   }
00069   else {
00070     res = locale->GetCategory(NS_LITERAL_STRING("NSILOCALE_TIME"), localeStr);
00071     if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) {
00072       if (!mLocale.IsEmpty() && 
00073           mLocale.Equals(localeStr, nsCaseInsensitiveStringComparator())) {
00074         return NS_OK;
00075       }
00076     }
00077   }
00078 
00079   // get os version
00080   OSVERSIONINFO os;
00081   os.dwOSVersionInfoSize = sizeof(os);
00082   ::GetVersionEx(&os);
00083   if (VER_PLATFORM_WIN32_NT == os.dwPlatformId && os.dwMajorVersion >= 4) {
00084     mW_API = PR_TRUE;   // has W API
00085   }
00086   else {
00087     mW_API = PR_FALSE;
00088   }
00089 
00090   // default LCID (en-US)
00091   mLCID = 1033;
00092 
00093   // get locale string, use app default if no locale specified
00094   if (NULL == locale) {
00095     nsCOMPtr<nsILocaleService> localeService = 
00096              do_GetService(NS_LOCALESERVICE_CONTRACTID);
00097     if (localeService) {
00098       nsCOMPtr<nsILocale> appLocale;
00099       res = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
00100       if (NS_SUCCEEDED(res)) {
00101         res = appLocale->GetCategory(NS_LITERAL_STRING("NSILOCALE_TIME"), 
00102                                   localeStr);
00103         if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) {
00104           mAppLocale.Assign(localeStr); // cache app locale name
00105         }
00106       }
00107     }
00108   }
00109   else {
00110     res = locale->GetCategory(NS_LITERAL_STRING("NSILOCALE_TIME"), localeStr);
00111   }
00112 
00113   // Get LCID and charset name from locale, if available
00114   if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) {
00115     mLocale.Assign(localeStr); // cache locale name
00116 
00117     nsCOMPtr <nsIWin32Locale> win32Locale = do_GetService(NS_WIN32LOCALE_CONTRACTID);
00118     if (win32Locale) {
00119       res = win32Locale->GetPlatformLocale(mLocale, (LCID *) &mLCID);
00120     }
00121   }
00122 
00123   return res;
00124 }
00125 
00126 // performs a locale sensitive date formatting operation on the time_t parameter
00127 nsresult nsDateTimeFormatWin::FormatTime(nsILocale* locale, 
00128                                          const nsDateFormatSelector  dateFormatSelector, 
00129                                          const nsTimeFormatSelector timeFormatSelector, 
00130                                          const time_t  timetTime, 
00131                                          nsString& stringOut)
00132 {
00133   return FormatTMTime(locale, dateFormatSelector, timeFormatSelector, localtime( &timetTime ), stringOut);
00134 }
00135 
00136 // performs a locale sensitive date formatting operation on the struct tm parameter
00137 nsresult nsDateTimeFormatWin::FormatTMTime(nsILocale* locale, 
00138                                            const nsDateFormatSelector  dateFormatSelector, 
00139                                            const nsTimeFormatSelector timeFormatSelector, 
00140                                            const struct tm*  tmTime, 
00141                                            nsString& stringOut)
00142 {
00143   SYSTEMTIME system_time;
00144   DWORD dwFlags_Date = 0, dwFlags_Time = 0;
00145   int dateLen, timeLen;
00146   PRUnichar dateBuffer[NSDATETIMEFORMAT_BUFFER_LEN], timeBuffer[NSDATETIMEFORMAT_BUFFER_LEN];
00147 
00148   // set up locale data
00149   (void) Initialize(locale);
00150 
00151   // Map tm to SYSTEMTIME
00152   system_time.wYear = 1900 + tmTime->tm_year;
00153   system_time.wMonth = tmTime->tm_mon + 1;
00154   system_time.wDayOfWeek = tmTime->tm_wday;
00155   system_time.wDay = tmTime->tm_mday;
00156   system_time.wHour = tmTime->tm_hour;
00157   system_time.wMinute = tmTime->tm_min;
00158   system_time.wSecond = tmTime->tm_sec;
00159   system_time.wMilliseconds = 0;
00160 
00161   // Map to WinAPI date format
00162   switch (dateFormatSelector) {
00163   case kDateFormatLong:
00164     dwFlags_Date = DATE_LONGDATE;
00165     break;
00166   case kDateFormatShort:
00167     dwFlags_Date = DATE_SHORTDATE;
00168     break;
00169   case kDateFormatWeekday:
00170     dwFlags_Date = 0;
00171     break;
00172   case kDateFormatYearMonth:
00173     dwFlags_Date = 0;     // TODO:only availabe NT5
00174     break;
00175   }
00176 
00177   // Map to WinAPI time format
00178   switch (timeFormatSelector) {
00179   case kTimeFormatSeconds:
00180     dwFlags_Time = 0;
00181     break;
00182   case kTimeFormatNoSeconds:
00183     dwFlags_Time = TIME_NOSECONDS;
00184     break;
00185   case kTimeFormatSecondsForce24Hour:
00186     dwFlags_Time = TIME_FORCE24HOURFORMAT;
00187     break;
00188   case kTimeFormatNoSecondsForce24Hour:
00189     dwFlags_Time = TIME_NOSECONDS + TIME_FORCE24HOURFORMAT;
00190     break;
00191   }
00192 
00193   // Call GetDateFormatW
00194   if (dateFormatSelector == kDateFormatNone) {
00195     dateLen = 0;
00196   }
00197   else {
00198     if (dateFormatSelector == kDateFormatYearMonth) {
00199       dateLen = nsGetDateFormatW(0, &system_time, "yyyy/MM", 
00200                                  dateBuffer, NSDATETIMEFORMAT_BUFFER_LEN);
00201     }
00202     else if (dateFormatSelector == kDateFormatWeekday) {
00203       dateLen = nsGetDateFormatW(0, &system_time, "ddd", 
00204                                  dateBuffer, NSDATETIMEFORMAT_BUFFER_LEN);
00205     }
00206     else {
00207       dateLen = nsGetDateFormatW(dwFlags_Date, &system_time, NULL, 
00208                                  dateBuffer, NSDATETIMEFORMAT_BUFFER_LEN);
00209     }
00210     if (dateLen != 0) {
00211       dateLen--;  // Since the count includes the terminating null.
00212     }
00213   }
00214 
00215   // Call GetTimeFormatW
00216   if (timeFormatSelector == kTimeFormatNone) {
00217     timeLen = 0;
00218   }
00219   else {
00220     timeLen = nsGetTimeFormatW(dwFlags_Time, &system_time, NULL, 
00221                                timeBuffer, NSDATETIMEFORMAT_BUFFER_LEN);
00222     if (timeLen != 0) {
00223       timeLen--;  // Since the count includes the terminating null.
00224     }
00225   }
00226 
00227   NS_ASSERTION(NSDATETIMEFORMAT_BUFFER_LEN >= (PRUint32) (dateLen + 1), "internal date buffer is not large enough");
00228   NS_ASSERTION(NSDATETIMEFORMAT_BUFFER_LEN >= (PRUint32) (timeLen + 1), "internal time buffer is not large enough");
00229 
00230   // Copy the result
00231   stringOut.SetLength(0);
00232   if (dateLen != 0 && timeLen != 0) {
00233     stringOut.Assign(dateBuffer, dateLen);
00234     stringOut.Append((PRUnichar *)(L" "), 1);
00235     stringOut.Append(timeBuffer, timeLen);
00236   }
00237   else if (dateLen != 0 && timeLen == 0) {
00238     stringOut.Assign(dateBuffer, dateLen);
00239   }
00240   else if (dateLen == 0 && timeLen != 0) {
00241     stringOut.Assign(timeBuffer, timeLen);
00242   }
00243 
00244   return NS_OK;
00245 }
00246 
00247 // performs a locale sensitive date formatting operation on the PRTime parameter
00248 nsresult nsDateTimeFormatWin::FormatPRTime(nsILocale* locale, 
00249                                            const nsDateFormatSelector  dateFormatSelector, 
00250                                            const nsTimeFormatSelector timeFormatSelector, 
00251                                            const PRTime  prTime, 
00252                                            nsString& stringOut)
00253 {
00254   PRExplodedTime explodedTime;
00255   PR_ExplodeTime(prTime, PR_LocalTimeParameters, &explodedTime);
00256 
00257   return FormatPRExplodedTime(locale, dateFormatSelector, timeFormatSelector, &explodedTime, stringOut);
00258 }
00259 
00260 // performs a locale sensitive date formatting operation on the PRExplodedTime parameter
00261 nsresult nsDateTimeFormatWin::FormatPRExplodedTime(nsILocale* locale, 
00262                                                    const nsDateFormatSelector  dateFormatSelector, 
00263                                                    const nsTimeFormatSelector timeFormatSelector, 
00264                                                    const PRExplodedTime*  explodedTime, 
00265                                                    nsString& stringOut)
00266 {
00267   struct tm  tmTime;
00268   memset( &tmTime, 0, sizeof(tmTime) );
00269 
00270   tmTime.tm_yday = explodedTime->tm_yday;
00271   tmTime.tm_wday = explodedTime->tm_wday;
00272   tmTime.tm_year = explodedTime->tm_year;
00273   tmTime.tm_year -= 1900;
00274   tmTime.tm_mon = explodedTime->tm_month;
00275   tmTime.tm_mday = explodedTime->tm_mday;
00276   tmTime.tm_hour = explodedTime->tm_hour;
00277   tmTime.tm_min = explodedTime->tm_min;
00278   tmTime.tm_sec = explodedTime->tm_sec;
00279 
00280   return FormatTMTime(locale, dateFormatSelector, timeFormatSelector, &tmTime, stringOut);
00281 }
00282 
00283 int nsDateTimeFormatWin::nsGetTimeFormatW(DWORD dwFlags, const SYSTEMTIME *lpTime,
00284                                           const char* format, PRUnichar *timeStr, int cchTime)
00285 {
00286   int len = 0;
00287 
00288 #ifndef WINCE // Always use wide APIs on Win CE.
00289   if (mW_API) {
00290 #endif
00291     nsString formatString; if (format) formatString.AssignWithConversion(format);
00292     LPCWSTR wstr = format ? (LPCWSTR) formatString.get() : NULL;
00293     len = GetTimeFormatW(mLCID, dwFlags, lpTime, wstr, (LPWSTR) timeStr, cchTime);
00294 #ifndef WINCE // Always use wide APIs on Win CE.
00295   }
00296   else {
00297     char cstr_time[NSDATETIMEFORMAT_BUFFER_LEN];
00298 
00299     len = GetTimeFormatA(mLCID, dwFlags, lpTime, (LPCSTR) format, 
00300                          (LPSTR) cstr_time, NSDATETIMEFORMAT_BUFFER_LEN);
00301 
00302     // convert result to unicode
00303     if (len > 0)
00304       len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPCSTR) cstr_time, len, (LPWSTR) timeStr, cchTime);
00305   }
00306 #endif
00307   return len;
00308 }
00309 
00310 int nsDateTimeFormatWin::nsGetDateFormatW(DWORD dwFlags, const SYSTEMTIME *lpDate,
00311                                           const char* format, PRUnichar *dateStr, int cchDate)
00312 {
00313   int len = 0;
00314 
00315 #ifndef WINCE // Always use wide APIs on Win CE.
00316   if (mW_API) {
00317 #endif
00318     nsString formatString; if (format) formatString.AssignWithConversion(format);
00319     LPCWSTR wstr = format ? (LPCWSTR) formatString.get() : NULL;
00320     len = GetDateFormatW(mLCID, dwFlags, lpDate, wstr, (LPWSTR) dateStr, cchDate);
00321 #ifndef WINCE // Always use wide APIs on Win CE.
00322   }
00323   else {
00324     char cstr_date[NSDATETIMEFORMAT_BUFFER_LEN];
00325 
00326     len = GetDateFormatA(mLCID, dwFlags, lpDate, (LPCSTR) format, 
00327                          (LPSTR) cstr_date, NSDATETIMEFORMAT_BUFFER_LEN);
00328 
00329     // convert result to unicode
00330     if (len > 0)
00331       len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPCSTR) cstr_date, len, (LPWSTR) dateStr, cchDate);
00332   }
00333 #endif
00334   return len;
00335 }