Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/intl/locale/DateTimeFormat.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2
 *
3
 * This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "DateTimeFormat.h"
8
#include "nsCOMPtr.h"
9
#include "nsIServiceManager.h"
10
#include "mozilla/intl/LocaleService.h"
11
#include "OSPreferences.h"
12
#include "mozIOSPreferences.h"
13
#include "unicode/udatpg.h"
14
15
namespace mozilla {
16
using namespace mozilla::intl;
17
18
nsCString* DateTimeFormat::mLocale = nullptr;
19
20
/*static*/ nsresult
21
DateTimeFormat::Initialize()
22
0
{
23
0
  if (mLocale) {
24
0
    return NS_OK;
25
0
  }
26
0
27
0
  mLocale = new nsCString();
28
0
  AutoTArray<nsCString, 10> regionalPrefsLocales;
29
0
  intl::LocaleService::GetInstance()->GetRegionalPrefsLocales(regionalPrefsLocales);
30
0
  mLocale->Assign(regionalPrefsLocales[0]);
31
0
32
0
  return NS_OK;
33
0
}
34
35
// performs a locale sensitive date formatting operation on the PRTime parameter
36
/*static*/ nsresult
37
DateTimeFormat::FormatPRTime(const nsDateFormatSelector aDateFormatSelector,
38
                             const nsTimeFormatSelector aTimeFormatSelector,
39
                             const PRTime aPrTime,
40
                             nsAString& aStringOut)
41
0
{
42
0
  return FormatUDateTime(aDateFormatSelector, aTimeFormatSelector, (aPrTime / PR_USEC_PER_MSEC), nullptr, aStringOut);
43
0
}
44
45
// performs a locale sensitive date formatting operation on the PRExplodedTime parameter
46
/*static*/ nsresult
47
DateTimeFormat::FormatPRExplodedTime(const nsDateFormatSelector aDateFormatSelector,
48
                                     const nsTimeFormatSelector aTimeFormatSelector,
49
                                     const PRExplodedTime* aExplodedTime,
50
                                     nsAString& aStringOut)
51
0
{
52
0
  return FormatUDateTime(aDateFormatSelector, aTimeFormatSelector, (PR_ImplodeTime(aExplodedTime) / PR_USEC_PER_MSEC), &(aExplodedTime->tm_params), aStringOut);
53
0
}
54
55
// performs a locale sensitive date formatting operation on the UDate parameter
56
/*static*/ nsresult
57
DateTimeFormat::FormatUDateTime(const nsDateFormatSelector aDateFormatSelector,
58
                                const nsTimeFormatSelector aTimeFormatSelector,
59
                                const UDate aUDateTime,
60
                                const PRTimeParameters* aTimeParameters,
61
                                nsAString& aStringOut)
62
0
{
63
0
  const int32_t DATETIME_FORMAT_INITIAL_LEN = 127;
64
0
  int32_t dateTimeLen = 0;
65
0
  nsresult rv = NS_OK;
66
0
67
0
  // return, nothing to format
68
0
  if (aDateFormatSelector == kDateFormatNone && aTimeFormatSelector == kTimeFormatNone) {
69
0
    aStringOut.Truncate();
70
0
    return NS_OK;
71
0
  }
72
0
73
0
  // set up locale data
74
0
  rv = Initialize();
75
0
76
0
  if (NS_FAILED(rv)) {
77
0
    return rv;
78
0
  }
79
0
80
0
  // Get the date style for the formatter.
81
0
  nsAutoString skeletonDate;
82
0
  nsAutoString patternDate;
83
0
  bool haveSkeleton = true;
84
0
  switch (aDateFormatSelector) {
85
0
  case kDateFormatLong:
86
0
    rv = OSPreferences::GetInstance()->GetDateTimePattern(mozIOSPreferences::dateTimeFormatStyleLong,
87
0
                                                          mozIOSPreferences::dateTimeFormatStyleNone,
88
0
                                                          nsDependentCString(mLocale->get()),
89
0
                                                          patternDate);
90
0
    NS_ENSURE_SUCCESS(rv, rv);
91
0
    haveSkeleton = false;
92
0
    break;
93
0
  case kDateFormatShort:
94
0
    rv = OSPreferences::GetInstance()->GetDateTimePattern(mozIOSPreferences::dateTimeFormatStyleShort,
95
0
                                                          mozIOSPreferences::dateTimeFormatStyleNone,
96
0
                                                          nsDependentCString(mLocale->get()),
97
0
                                                          patternDate);
98
0
    NS_ENSURE_SUCCESS(rv, rv);
99
0
    haveSkeleton = false;
100
0
    break;
101
0
  case kDateFormatYearMonth:
102
0
    skeletonDate.AssignLiteral("yyyyMM");
103
0
    break;
104
0
  case kDateFormatYearMonthLong:
105
0
    skeletonDate.AssignLiteral("yyyyMMMM");
106
0
    break;
107
0
  case kDateFormatMonthLong:
108
0
    skeletonDate.AssignLiteral("MMMM");
109
0
    break;
110
0
  case kDateFormatWeekday:
111
0
    skeletonDate.AssignLiteral("EEE");
112
0
    break;
113
0
  case kDateFormatNone:
114
0
    haveSkeleton = false;
115
0
    break;
116
0
  default:
117
0
    NS_ERROR("Unknown nsDateFormatSelector");
118
0
    return NS_ERROR_ILLEGAL_VALUE;
119
0
  }
120
0
121
0
  UErrorCode status = U_ZERO_ERROR;
122
0
  if (haveSkeleton) {
123
0
    // Get pattern for skeleton.
124
0
    UDateTimePatternGenerator* patternGenerator = udatpg_open(mLocale->get(), &status);
125
0
    if (U_SUCCESS(status)) {
126
0
      int32_t patternLength;
127
0
      patternDate.SetLength(DATETIME_FORMAT_INITIAL_LEN);
128
0
      patternLength = udatpg_getBestPattern(patternGenerator,
129
0
                                            reinterpret_cast<const UChar*>(skeletonDate.BeginReading()),
130
0
                                            skeletonDate.Length(),
131
0
                                            reinterpret_cast<UChar*>(patternDate.BeginWriting()),
132
0
                                            DATETIME_FORMAT_INITIAL_LEN,
133
0
                                            &status);
134
0
      patternDate.SetLength(patternLength);
135
0
136
0
      if (status == U_BUFFER_OVERFLOW_ERROR) {
137
0
        status = U_ZERO_ERROR;
138
0
        udatpg_getBestPattern(patternGenerator,
139
0
                              reinterpret_cast<const UChar*>(skeletonDate.BeginReading()),
140
0
                              skeletonDate.Length(),
141
0
                              reinterpret_cast<UChar*>(patternDate.BeginWriting()),
142
0
                              patternLength,
143
0
                              &status);
144
0
      }
145
0
    }
146
0
    udatpg_close(patternGenerator);
147
0
  }
148
0
149
0
  // Get the time style for the formatter.
150
0
  nsAutoString patternTime;
151
0
  switch (aTimeFormatSelector) {
152
0
  case kTimeFormatSeconds:
153
0
    rv = OSPreferences::GetInstance()->GetDateTimePattern(mozIOSPreferences::dateTimeFormatStyleNone,
154
0
                                                          mozIOSPreferences::dateTimeFormatStyleLong,
155
0
                                                          nsDependentCString(mLocale->get()),
156
0
                                                          patternTime);
157
0
    NS_ENSURE_SUCCESS(rv, rv);
158
0
    break;
159
0
  case kTimeFormatNoSeconds:
160
0
    rv = OSPreferences::GetInstance()->GetDateTimePattern(mozIOSPreferences::dateTimeFormatStyleNone,
161
0
                                                          mozIOSPreferences::dateTimeFormatStyleShort,
162
0
                                                          nsDependentCString(mLocale->get()),
163
0
                                                          patternTime);
164
0
    NS_ENSURE_SUCCESS(rv, rv);
165
0
    break;
166
0
  case kTimeFormatNone:
167
0
    break;
168
0
  default:
169
0
    NS_ERROR("Unknown nsTimeFormatSelector");
170
0
    return NS_ERROR_ILLEGAL_VALUE;
171
0
  }
172
0
173
0
  nsAutoString pattern;
174
0
  if (patternTime.Length() == 0) {
175
0
    pattern.Assign(patternDate);
176
0
  } else if (patternDate.Length() == 0) {
177
0
    pattern.Assign(patternTime);
178
0
  } else {
179
0
    OSPreferences::GetDateTimeConnectorPattern(nsDependentCString(mLocale->get()), pattern);
180
0
    int32_t index = pattern.Find("{1}");
181
0
    if (index != kNotFound)
182
0
      pattern.Replace(index, 3, patternDate);
183
0
    index = pattern.Find("{0}");
184
0
    if (index != kNotFound)
185
0
      pattern.Replace(index, 3, patternTime);
186
0
  }
187
0
188
0
  // Generate date/time string.
189
0
  nsAutoString timeZoneID(u"GMT");
190
0
  if (aTimeParameters) {
191
0
    int32_t totalOffsetMinutes = (aTimeParameters->tp_gmt_offset + aTimeParameters->tp_dst_offset) / 60;
192
0
    if (totalOffsetMinutes != 0) {
193
0
      char sign = totalOffsetMinutes < 0 ? '-' : '+';
194
0
      int32_t hours = abs(totalOffsetMinutes) / 60;
195
0
      int32_t minutes = abs(totalOffsetMinutes) % 60;
196
0
      timeZoneID.AppendPrintf("%c%02d:%02d", sign, hours, minutes);
197
0
    }
198
0
  }
199
0
200
0
  UDateFormat* dateTimeFormat;
201
0
  if (aTimeParameters) {
202
0
    dateTimeFormat = udat_open(UDAT_PATTERN, UDAT_PATTERN, mLocale->get(),
203
0
                               reinterpret_cast<const UChar*>(timeZoneID.BeginReading()),
204
0
                               timeZoneID.Length(),
205
0
                               reinterpret_cast<const UChar*>(pattern.BeginReading()),
206
0
                               pattern.Length(),
207
0
                               &status);
208
0
  } else {
209
0
    dateTimeFormat = udat_open(UDAT_PATTERN, UDAT_PATTERN, mLocale->get(),
210
0
                               nullptr, -1,
211
0
                               reinterpret_cast<const UChar*>(pattern.BeginReading()),
212
0
                               pattern.Length(),
213
0
                               &status);
214
0
  }
215
0
216
0
  if (U_SUCCESS(status) && dateTimeFormat) {
217
0
    aStringOut.SetLength(DATETIME_FORMAT_INITIAL_LEN);
218
0
    dateTimeLen = udat_format(dateTimeFormat, aUDateTime,
219
0
                              reinterpret_cast<UChar*>(aStringOut.BeginWriting()),
220
0
                              DATETIME_FORMAT_INITIAL_LEN,
221
0
                              nullptr,
222
0
                              &status);
223
0
    aStringOut.SetLength(dateTimeLen);
224
0
225
0
    if (status == U_BUFFER_OVERFLOW_ERROR) {
226
0
      status = U_ZERO_ERROR;
227
0
      udat_format(dateTimeFormat, aUDateTime,
228
0
                  reinterpret_cast<UChar*>(aStringOut.BeginWriting()),
229
0
                  dateTimeLen,
230
0
                  nullptr,
231
0
                  &status);
232
0
    }
233
0
  }
234
0
235
0
  if (U_FAILURE(status)) {
236
0
    rv = NS_ERROR_FAILURE;
237
0
  }
238
0
239
0
  if (dateTimeFormat) {
240
0
    udat_close(dateTimeFormat);
241
0
  }
242
0
243
0
  return rv;
244
0
}
245
246
/*static*/ void
247
DateTimeFormat::Shutdown()
248
0
{
249
0
  if (mLocale) {
250
0
    delete mLocale;
251
0
  }
252
0
}
253
254
}