intl/locale/src/mac/nsDateTimeFormatMac.cpp

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

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

mercurial