summaryrefslogtreecommitdiffstats
path: root/content/renderer/date_time_formatter.cc
blob: d3c16e355c88b967e21f4ec50fa86fe60aa88631 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/renderer/date_time_formatter.h"

#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebCString.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDateTimeChooserParams.h"
#include "third_party/icu/public/i18n/unicode/smpdtfmt.h"


namespace content {

void DateTimeFormatter::CreatePatternMap() {
  // Initialize all the UI elements with empty patterns,
  // then fill in the ones that are actually date/time inputs and
  // are implemented.
  for (int i = 0 ; i <= ui::TEXT_INPUT_TYPE_MAX; ++i) {
    patterns_[i] = "";
  }
  patterns_[ui::TEXT_INPUT_TYPE_DATE] = "yyyy-MM-dd";
  patterns_[ui::TEXT_INPUT_TYPE_DATE_TIME] =  "yyyy-MM-dd'T'HH:mm'Z'";
  patterns_[ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL] =  "yyyy-MM-dd'T'HH:mm";
  patterns_[ui::TEXT_INPUT_TYPE_MONTH] = "yyyy-MM";
  patterns_[ui::TEXT_INPUT_TYPE_TIME] = "HH:mm";
}

DateTimeFormatter::DateTimeFormatter(
    const WebKit::WebDateTimeChooserParams& source)
  : formatted_string_(source.currentValue.utf8()) {
  CreatePatternMap();
  ExtractType(source);
  if (!ParseValues()) {
    type_ = ui::TEXT_INPUT_TYPE_NONE;
    ClearAll();
    LOG(WARNING) << "Problems parsing input <" << formatted_string_ << ">";
  }
}

DateTimeFormatter::DateTimeFormatter(
    ui::TextInputType type,
    int year, int month, int day, int hour, int minute, int second)
  : type_(type),
    year_(year),
    month_(month),
    day_(day),
    hour_(hour),
    minute_(minute),
    second_(second) {
  CreatePatternMap();
  pattern_ = type_ > 0 && type_ <= ui::TEXT_INPUT_TYPE_MAX ?
      &patterns_[type_] : &patterns_[ui::TEXT_INPUT_TYPE_NONE];

  formatted_string_ = FormatString();
}

DateTimeFormatter::~DateTimeFormatter() {
}

int DateTimeFormatter::GetYear() const {
  return year_;
}

int DateTimeFormatter::GetMonth() const {
  return month_;
}

int DateTimeFormatter::GetDay() const {
  return day_;
}

int DateTimeFormatter::GetHour() const {
  return hour_;
}

int DateTimeFormatter::GetMinute() const {
  return minute_;
}

int DateTimeFormatter::GetSecond() const {
  return second_;
}

ui::TextInputType DateTimeFormatter::GetType() const {
  return type_;
}

const std::string& DateTimeFormatter::GetFormattedValue() const {
  return formatted_string_;
}

const std::string DateTimeFormatter::FormatString() const {
  UErrorCode success = U_ZERO_ERROR;
  if (year_ == 0 && month_ == 0 && day_ == 0 &&
      hour_ == 0 && minute_ == 0 && second_ == 0) {
    return "";
  }

  std::string result;
  const icu::GregorianCalendar calendar(
      year_, month_, day_, hour_, minute_, second_, success);
  if (success <= U_ZERO_ERROR) {
    UDate time = calendar.getTime(success);
    icu::SimpleDateFormat formatter(*pattern_, success);
    icu::UnicodeString formatted_time;
    formatter.format(time, formatted_time, success);
    UTF16ToUTF8(formatted_time.getBuffer(),
                static_cast<size_t>(formatted_time.length()),
                &result);
    if (success <= U_ZERO_ERROR)
      return result;
  }
  LOG(WARNING) << "Calendar not created: error " <<  success;
  return "";
}

void DateTimeFormatter::ExtractType(
    const WebKit::WebDateTimeChooserParams& source) {
  switch (source.type) {
    case WebKit::WebDateTimeInputTypeDate:
      type_ = ui::TEXT_INPUT_TYPE_DATE;
      break;
    case WebKit::WebDateTimeInputTypeDateTime:
      type_ = ui::TEXT_INPUT_TYPE_DATE_TIME;
      break;
    case WebKit::WebDateTimeInputTypeDateTimeLocal:
      type_ = ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL;
      break;
    case WebKit::WebDateTimeInputTypeMonth:
      type_ = ui::TEXT_INPUT_TYPE_MONTH;
      break;
    case WebKit::WebDateTimeInputTypeTime:
      type_ = ui::TEXT_INPUT_TYPE_TIME;
      break;
    case WebKit::WebDateTimeInputTypeWeek: // Not implemented
    case WebKit::WebDateTimeInputTypeNone:
    default:
      type_ = ui::TEXT_INPUT_TYPE_NONE;
  }
}

// Not all fields are defined in all configurations and ICU might store
// garbage if success <= U_ZERO_ERROR so the output is sanitized here.
int DateTimeFormatter::ExtractValue(
    const icu::Calendar* calendar, UCalendarDateFields value) const {
  UErrorCode success = U_ZERO_ERROR;
  int result = calendar->get(value, success);
  return (success <= U_ZERO_ERROR) ? result : 0;
}

bool DateTimeFormatter::ParseValues() {
  if (type_ == ui::TEXT_INPUT_TYPE_NONE) {
    ClearAll();
    return false;
  }

  if (formatted_string_.empty()) {
    ClearAll();
    return true;
  }

  UErrorCode success = U_ZERO_ERROR;
  icu::UnicodeString icu_value = icu::UnicodeString::fromUTF8(
      icu::StringPiece(formatted_string_.data(), formatted_string_.size()));
  if (type_ > 0 && type_ <= ui::TEXT_INPUT_TYPE_MAX) {
    const icu::UnicodeString pattern = patterns_[type_];
    icu::SimpleDateFormat formatter(pattern, success);
    formatter.parse(icu_value, success);
    if (success <= U_ZERO_ERROR) {
      const icu::Calendar* cal = formatter.getCalendar();
      year_ = ExtractValue(cal, UCAL_YEAR);
      month_ = ExtractValue(cal, UCAL_MONTH);
      day_ = ExtractValue(cal, UCAL_DATE);
      hour_ = ExtractValue(cal, UCAL_HOUR_OF_DAY);  // 24h format
      minute_ = ExtractValue(cal, UCAL_MINUTE);
      second_ = ExtractValue(cal, UCAL_SECOND);
    }
  }

  return (success <= U_ZERO_ERROR);
}

void DateTimeFormatter::ClearAll() {
  year_ = 0;
  month_ = 0;
  day_ = 0;
  hour_ = 0;
  minute_ = 0;
  second_ = 0;
}

}  // namespace content