1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/. */
5 
6 #include "mozilla/Sprintf.h"
7 #include "nsILocaleService.h"
8 #include "nsDateTimeFormatCID.h"
9 #include "nsIDateTimeFormat.h"
10 #include "nsIScriptableDateFormat.h"
11 #include "nsCOMPtr.h"
12 #include "nsServiceManagerUtils.h"
13 
14 static NS_DEFINE_CID(kLocaleServiceCID, NS_LOCALESERVICE_CID);
15 static NS_DEFINE_CID(kDateTimeFormatCID, NS_DATETIMEFORMAT_CID);
16 
17 class nsScriptableDateFormat : public nsIScriptableDateFormat {
18  public:
19   NS_DECL_ISUPPORTS
20 
21   NS_IMETHOD FormatDateTime(const char16_t *locale,
22                             nsDateFormatSelector dateFormatSelector,
23                             nsTimeFormatSelector timeFormatSelector,
24                             int32_t year,
25                             int32_t month,
26                             int32_t day,
27                             int32_t hour,
28                             int32_t minute,
29                             int32_t second,
30                             char16_t **dateTimeString) override;
31 
FormatDate(const char16_t * locale,nsDateFormatSelector dateFormatSelector,int32_t year,int32_t month,int32_t day,char16_t ** dateString)32   NS_IMETHOD FormatDate(const char16_t *locale,
33                         nsDateFormatSelector dateFormatSelector,
34                         int32_t year,
35                         int32_t month,
36                         int32_t day,
37                         char16_t **dateString) override
38                         {return FormatDateTime(locale, dateFormatSelector, kTimeFormatNone,
39                                                year, month, day, 0, 0, 0, dateString);}
40 
FormatTime(const char16_t * locale,nsTimeFormatSelector timeFormatSelector,int32_t hour,int32_t minute,int32_t second,char16_t ** timeString)41   NS_IMETHOD FormatTime(const char16_t *locale,
42                         nsTimeFormatSelector timeFormatSelector,
43                         int32_t hour,
44                         int32_t minute,
45                         int32_t second,
46                         char16_t **timeString) override
47                         {return FormatDateTime(locale, kDateFormatNone, timeFormatSelector,
48                                                1999, 1, 1, hour, minute, second, timeString);}
49 
nsScriptableDateFormat()50   nsScriptableDateFormat() {}
51 
52 private:
53   nsString mStringOut;
54 
~nsScriptableDateFormat()55   virtual ~nsScriptableDateFormat() {}
56 };
57 
NS_IMPL_ISUPPORTS(nsScriptableDateFormat,nsIScriptableDateFormat)58 NS_IMPL_ISUPPORTS(nsScriptableDateFormat, nsIScriptableDateFormat)
59 
60 NS_IMETHODIMP nsScriptableDateFormat::FormatDateTime(
61                             const char16_t *aLocale,
62                             nsDateFormatSelector dateFormatSelector,
63                             nsTimeFormatSelector timeFormatSelector,
64                             int32_t year,
65                             int32_t month,
66                             int32_t day,
67                             int32_t hour,
68                             int32_t minute,
69                             int32_t second,
70                             char16_t **dateTimeString)
71 {
72   // We can't have a valid date with the year, month or day
73   // being lower than 1.
74   if (year < 1 || month < 1 || day < 1)
75     return NS_ERROR_INVALID_ARG;
76 
77   nsresult rv;
78   nsAutoString localeName(aLocale);
79   *dateTimeString = nullptr;
80 
81   nsCOMPtr<nsILocale> locale;
82   // re-initialise locale pointer only if the locale was given explicitly
83   if (!localeName.IsEmpty()) {
84     // get locale service
85     nsCOMPtr<nsILocaleService> localeService(do_GetService(kLocaleServiceCID, &rv));
86     NS_ENSURE_SUCCESS(rv, rv);
87     // get locale
88     rv = localeService->NewLocale(localeName, getter_AddRefs(locale));
89     NS_ENSURE_SUCCESS(rv, rv);
90   }
91 
92   nsCOMPtr<nsIDateTimeFormat> dateTimeFormat(do_CreateInstance(kDateTimeFormatCID, &rv));
93   NS_ENSURE_SUCCESS(rv, rv);
94 
95   tm tmTime;
96   time_t timetTime;
97 
98   memset(&tmTime, 0, sizeof(tmTime));
99   tmTime.tm_year = year - 1900;
100   tmTime.tm_mon = month - 1;
101   tmTime.tm_mday = day;
102   tmTime.tm_hour = hour;
103   tmTime.tm_min = minute;
104   tmTime.tm_sec = second;
105   tmTime.tm_yday = tmTime.tm_wday = 0;
106   tmTime.tm_isdst = -1;
107   timetTime = mktime(&tmTime);
108 
109   if ((time_t)-1 != timetTime) {
110     rv = dateTimeFormat->FormatTime(locale, dateFormatSelector, timeFormatSelector,
111                                      timetTime, mStringOut);
112   }
113   else {
114     // if mktime fails (e.g. year <= 1970), then try NSPR.
115     PRTime prtime;
116     char string[32];
117     SprintfLiteral(string, "%.2d/%.2d/%d %.2d:%.2d:%.2d", month, day, year, hour, minute, second);
118     if (PR_SUCCESS != PR_ParseTimeString(string, false, &prtime))
119       return NS_ERROR_INVALID_ARG;
120 
121     rv = dateTimeFormat->FormatPRTime(locale, dateFormatSelector, timeFormatSelector,
122                                       prtime, mStringOut);
123   }
124   if (NS_SUCCEEDED(rv))
125     *dateTimeString = ToNewUnicode(mStringOut);
126 
127   return rv;
128 }
129 
130 nsresult
NS_NewScriptableDateFormat(nsISupports * aOuter,REFNSIID aIID,void ** aResult)131 NS_NewScriptableDateFormat(nsISupports* aOuter, REFNSIID aIID, void** aResult)
132 {
133   if (aOuter)
134     return NS_ERROR_NO_AGGREGATION;
135 
136   nsScriptableDateFormat* result = new nsScriptableDateFormat();
137   if (! result)
138     return NS_ERROR_OUT_OF_MEMORY;
139 
140   NS_ADDREF(result);
141   nsresult rv = result->QueryInterface(aIID, aResult);
142   NS_RELEASE(result);
143 
144   return rv;
145 }
146