1#include <DataTypes/DataTypeDateTime.h>
2
3#include <Columns/ColumnDecimal.h>
4#include <Columns/ColumnVector.h>
5#include <Columns/ColumnsNumber.h>
6#include <Common/assert_cast.h>
7#include <Common/typeid_cast.h>
8#include <common/DateLUT.h>
9#include <DataTypes/DataTypeFactory.h>
10#include <Formats/FormatSettings.h>
11#include <Formats/ProtobufReader.h>
12#include <Formats/ProtobufWriter.h>
13#include <IO/Operators.h>
14#include <IO/ReadHelpers.h>
15#include <IO/WriteBufferFromString.h>
16#include <IO/WriteHelpers.h>
17#include <IO/parseDateTimeBestEffort.h>
18#include <Parsers/ASTLiteral.h>
19
20namespace
21{
22using namespace DB;
23static inline void readText(time_t & x, ReadBuffer & istr, const FormatSettings & settings, const DateLUTImpl & time_zone, const DateLUTImpl & utc_time_zone)
24{
25 switch (settings.date_time_input_format)
26 {
27 case FormatSettings::DateTimeInputFormat::Basic:
28 readDateTimeText(x, istr, time_zone);
29 return;
30 case FormatSettings::DateTimeInputFormat::BestEffort:
31 parseDateTimeBestEffort(x, istr, time_zone, utc_time_zone);
32 return;
33 }
34}
35}
36
37namespace DB
38{
39
40TimezoneMixin::TimezoneMixin(const String & time_zone_name)
41 : has_explicit_time_zone(!time_zone_name.empty()),
42 time_zone(DateLUT::instance(time_zone_name)),
43 utc_time_zone(DateLUT::instance("UTC"))
44{}
45
46DataTypeDateTime::DataTypeDateTime(const String & time_zone_name, const String & type_name_)
47 : TimezoneMixin(time_zone_name), type_name(type_name_)
48{
49}
50
51DataTypeDateTime::DataTypeDateTime(const TimezoneMixin & time_zone_)
52 : TimezoneMixin(time_zone_)
53{}
54
55String DataTypeDateTime::doGetName() const
56{
57 if (!has_explicit_time_zone)
58 return type_name;
59
60 WriteBufferFromOwnString out;
61 out << type_name << "(" << quote << time_zone.getTimeZone() << ")";
62 return out.str();
63}
64
65void DataTypeDateTime::serializeText(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings &) const
66{
67 writeDateTimeText(assert_cast<const ColumnType &>(column).getData()[row_num], ostr, time_zone);
68}
69
70void DataTypeDateTime::serializeTextEscaped(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) const
71{
72 serializeText(column, row_num, ostr, settings);
73}
74
75void DataTypeDateTime::deserializeWholeText(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const
76{
77 deserializeTextEscaped(column, istr, settings);
78}
79
80void DataTypeDateTime::deserializeTextEscaped(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const
81{
82 time_t x;
83 ::readText(x, istr, settings, time_zone, utc_time_zone);
84 assert_cast<ColumnType &>(column).getData().push_back(x);
85}
86
87void DataTypeDateTime::serializeTextQuoted(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) const
88{
89 writeChar('\'', ostr);
90 serializeText(column, row_num, ostr, settings);
91 writeChar('\'', ostr);
92}
93
94void DataTypeDateTime::deserializeTextQuoted(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const
95{
96 time_t x;
97 if (checkChar('\'', istr)) /// Cases: '2017-08-31 18:36:48' or '1504193808'
98 {
99 ::readText(x, istr, settings, time_zone, utc_time_zone);
100 assertChar('\'', istr);
101 }
102 else /// Just 1504193808 or 01504193808
103 {
104 readIntText(x, istr);
105 }
106 assert_cast<ColumnType &>(column).getData().push_back(x); /// It's important to do this at the end - for exception safety.
107}
108
109void DataTypeDateTime::serializeTextJSON(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) const
110{
111 writeChar('"', ostr);
112 serializeText(column, row_num, ostr, settings);
113 writeChar('"', ostr);
114}
115
116void DataTypeDateTime::deserializeTextJSON(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const
117{
118 time_t x;
119 if (checkChar('"', istr))
120 {
121 ::readText(x, istr, settings, time_zone, utc_time_zone);
122 assertChar('"', istr);
123 }
124 else
125 {
126 readIntText(x, istr);
127 }
128 assert_cast<ColumnType &>(column).getData().push_back(x);
129}
130
131void DataTypeDateTime::serializeTextCSV(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) const
132{
133 writeChar('"', ostr);
134 serializeText(column, row_num, ostr, settings);
135 writeChar('"', ostr);
136}
137
138void DataTypeDateTime::deserializeTextCSV(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const
139{
140 time_t x;
141
142 if (istr.eof())
143 throwReadAfterEOF();
144
145 char maybe_quote = *istr.position();
146
147 if (maybe_quote == '\'' || maybe_quote == '\"')
148 ++istr.position();
149
150 ::readText(x, istr, settings, time_zone, utc_time_zone);
151
152 if (maybe_quote == '\'' || maybe_quote == '\"')
153 assertChar(maybe_quote, istr);
154
155 assert_cast<ColumnType &>(column).getData().push_back(x);
156}
157
158void DataTypeDateTime::serializeProtobuf(const IColumn & column, size_t row_num, ProtobufWriter & protobuf, size_t & value_index) const
159{
160 if (value_index)
161 return;
162
163 // On some platforms `time_t` is `long` but not `unsigned int` (UInt32 that we store in column), hence static_cast.
164 value_index = static_cast<bool>(protobuf.writeDateTime(static_cast<time_t>(assert_cast<const ColumnType &>(column).getData()[row_num])));
165}
166
167void DataTypeDateTime::deserializeProtobuf(IColumn & column, ProtobufReader & protobuf, bool allow_add_row, bool & row_added) const
168{
169 row_added = false;
170 time_t t;
171 if (!protobuf.readDateTime(t))
172 return;
173
174 auto & container = assert_cast<ColumnType &>(column).getData();
175 if (allow_add_row)
176 {
177 container.emplace_back(t);
178 row_added = true;
179 }
180 else
181 container.back() = t;
182}
183
184bool DataTypeDateTime::equals(const IDataType & rhs) const
185{
186 /// DateTime with different timezones are equal, because:
187 /// "all types with different time zones are equivalent and may be used interchangingly."
188 return typeid(rhs) == typeid(*this);
189}
190
191namespace ErrorCodes
192{
193 extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
194 extern const int ILLEGAL_TYPE_OF_ARGUMENT;
195}
196
197static DataTypePtr create(const String & type_name, const ASTPtr & arguments)
198{
199 if (!arguments)
200 return std::make_shared<DataTypeDateTime>("", type_name);
201
202 if (arguments->children.size() != 1)
203 throw Exception("DateTime data type can optionally have only one argument - time zone name", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
204
205 const auto * arg = arguments->children[0]->as<ASTLiteral>();
206 if (!arg || arg->value.getType() != Field::Types::String)
207 throw Exception("Parameter for DateTime data type must be string literal", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
208
209 return std::make_shared<DataTypeDateTime>(arg->value.get<String>(), type_name);
210}
211
212void registerDataTypeDateTime(DataTypeFactory & factory)
213{
214 factory.registerDataType("DateTime", create, DataTypeFactory::CaseInsensitive);
215 factory.registerAlias("TIMESTAMP", "DateTime", DataTypeFactory::CaseInsensitive);
216}
217
218}
219