1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/date_time_formatter.h"
7 #include "base/strings/string_util.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "third_party/WebKit/public/platform/WebCString.h"
10 #include "third_party/WebKit/public/web/WebDateTimeChooserParams.h"
11 #include "third_party/icu/public/i18n/unicode/smpdtfmt.h"
16 void DateTimeFormatter::CreatePatternMap() {
17 // Initialize all the UI elements with empty patterns,
18 // then fill in the ones that are actually date/time inputs and
20 for (int i
= 0 ; i
<= ui::TEXT_INPUT_TYPE_MAX
; ++i
) {
23 patterns_
[ui::TEXT_INPUT_TYPE_DATE
] = "yyyy-MM-dd";
24 patterns_
[ui::TEXT_INPUT_TYPE_DATE_TIME
] = "yyyy-MM-dd'T'HH:mm'Z'";
25 patterns_
[ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL
] = "yyyy-MM-dd'T'HH:mm";
26 patterns_
[ui::TEXT_INPUT_TYPE_MONTH
] = "yyyy-MM";
27 patterns_
[ui::TEXT_INPUT_TYPE_TIME
] = "HH:mm";
28 patterns_
[ui::TEXT_INPUT_TYPE_WEEK
] = "Y-'W'ww";
31 DateTimeFormatter::DateTimeFormatter(
32 const WebKit::WebDateTimeChooserParams
& source
)
33 : formatted_string_(source
.currentValue
.utf8()) {
37 type_
= ui::TEXT_INPUT_TYPE_NONE
;
39 LOG(WARNING
) << "Problems parsing input <" << formatted_string_
<< ">";
43 DateTimeFormatter::DateTimeFormatter(
44 ui::TextInputType type
,
45 int year
, int month
, int day
, int hour
, int minute
, int second
,
46 int week_year
, int week
)
54 week_year_(week_year
),
57 pattern_
= type_
> 0 && type_
<= ui::TEXT_INPUT_TYPE_MAX
?
58 &patterns_
[type_
] : &patterns_
[ui::TEXT_INPUT_TYPE_NONE
];
60 formatted_string_
= FormatString();
63 DateTimeFormatter::~DateTimeFormatter() {
66 int DateTimeFormatter::GetYear() const {
70 int DateTimeFormatter::GetMonth() const {
74 int DateTimeFormatter::GetDay() const {
78 int DateTimeFormatter::GetHour() const {
82 int DateTimeFormatter::GetMinute() const {
86 int DateTimeFormatter::GetSecond() const {
90 int DateTimeFormatter::GetWeekYear() const {
94 int DateTimeFormatter::GetWeek() const {
98 ui::TextInputType
DateTimeFormatter::GetType() const {
102 const std::string
& DateTimeFormatter::GetFormattedValue() const {
103 return formatted_string_
;
106 const std::string
DateTimeFormatter::FormatString() const {
107 UErrorCode success
= U_ZERO_ERROR
;
108 if (year_
== 0 && month_
== 0 && day_
== 0 &&
109 hour_
== 0 && minute_
== 0 && second_
== 0 &&
110 week_year_
== 0 && week_
== 0) {
111 return std::string();
115 icu::GregorianCalendar
calendar(success
);
116 if (success
<= U_ZERO_ERROR
) {
117 if (type_
== ui::TEXT_INPUT_TYPE_WEEK
) {
118 // An ISO week starts with Monday.
119 calendar
.setFirstDayOfWeek(UCAL_MONDAY
);
120 // ISO 8601 defines that the week with the year's first Thursday is the
122 calendar
.setMinimalDaysInFirstWeek(4);
123 calendar
.set(UCAL_YEAR_WOY
, week_year_
);
124 calendar
.set(UCAL_WEEK_OF_YEAR
, week_
);
126 calendar
.set(UCAL_YEAR
, year_
);
127 calendar
.set(UCAL_MONTH
, month_
);
128 calendar
.set(UCAL_DATE
, day_
);
129 calendar
.set(UCAL_HOUR_OF_DAY
, hour_
);
130 calendar
.set(UCAL_MINUTE
, minute_
);
131 calendar
.set(UCAL_SECOND
, second_
);
133 icu::SimpleDateFormat
formatter(*pattern_
, success
);
134 icu::UnicodeString formatted_time
;
135 formatter
.format(calendar
, formatted_time
, NULL
, success
);
136 UTF16ToUTF8(formatted_time
.getBuffer(),
137 static_cast<size_t>(formatted_time
.length()),
139 if (success
<= U_ZERO_ERROR
)
142 LOG(WARNING
) << "Calendar not created: error " << success
;
143 return std::string();
146 void DateTimeFormatter::ExtractType(
147 const WebKit::WebDateTimeChooserParams
& source
) {
148 switch (source
.type
) {
149 case WebKit::WebDateTimeInputTypeDate
:
150 type_
= ui::TEXT_INPUT_TYPE_DATE
;
152 case WebKit::WebDateTimeInputTypeDateTime
:
153 type_
= ui::TEXT_INPUT_TYPE_DATE_TIME
;
155 case WebKit::WebDateTimeInputTypeDateTimeLocal
:
156 type_
= ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL
;
158 case WebKit::WebDateTimeInputTypeMonth
:
159 type_
= ui::TEXT_INPUT_TYPE_MONTH
;
161 case WebKit::WebDateTimeInputTypeTime
:
162 type_
= ui::TEXT_INPUT_TYPE_TIME
;
164 case WebKit::WebDateTimeInputTypeWeek
:
165 type_
= ui::TEXT_INPUT_TYPE_WEEK
;
167 case WebKit::WebDateTimeInputTypeNone
:
169 type_
= ui::TEXT_INPUT_TYPE_NONE
;
173 // Not all fields are defined in all configurations and ICU might store
174 // garbage if success <= U_ZERO_ERROR so the output is sanitized here.
175 int DateTimeFormatter::ExtractValue(
176 const icu::Calendar
* calendar
, UCalendarDateFields value
) const {
177 UErrorCode success
= U_ZERO_ERROR
;
178 int result
= calendar
->get(value
, success
);
179 return (success
<= U_ZERO_ERROR
) ? result
: 0;
182 bool DateTimeFormatter::ParseValues() {
183 if (type_
== ui::TEXT_INPUT_TYPE_NONE
) {
188 if (formatted_string_
.empty()) {
193 UErrorCode success
= U_ZERO_ERROR
;
194 icu::UnicodeString icu_value
= icu::UnicodeString::fromUTF8(
195 icu::StringPiece(formatted_string_
.data(), formatted_string_
.size()));
196 if (type_
> 0 && type_
<= ui::TEXT_INPUT_TYPE_MAX
) {
197 const icu::UnicodeString pattern
= patterns_
[type_
];
198 icu::SimpleDateFormat
formatter(pattern
, success
);
199 formatter
.parse(icu_value
, success
);
200 if (success
<= U_ZERO_ERROR
) {
201 const icu::Calendar
* cal
= formatter
.getCalendar();
202 year_
= ExtractValue(cal
, UCAL_YEAR
);
203 month_
= ExtractValue(cal
, UCAL_MONTH
);
204 day_
= ExtractValue(cal
, UCAL_DATE
);
205 hour_
= ExtractValue(cal
, UCAL_HOUR_OF_DAY
); // 24h format
206 minute_
= ExtractValue(cal
, UCAL_MINUTE
);
207 second_
= ExtractValue(cal
, UCAL_SECOND
);
208 week_year_
= ExtractValue(cal
, UCAL_YEAR_WOY
);
209 week_
= ExtractValue(cal
, UCAL_WEEK_OF_YEAR
);
213 return (success
<= U_ZERO_ERROR
);
216 void DateTimeFormatter::ClearAll() {
227 } // namespace content