Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
timestamp-test.cc
Go to the documentation of this file.
1 // Copyright 2012 Cloudera Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <algorithm>
16 #include <cstring>
17 #include <vector>
18 #include <boost/assign/list_of.hpp>
19 #include <gtest/gtest.h>
20 
21 #include "common/init.h"
22 #include "runtime/raw-value.h"
24 #include "util/string-parser.h"
25 
26 #include "common/names.h"
27 
28 using boost::assign::list_of;
29 using boost::date_time::Dec;
30 using boost::date_time::not_a_date_time;
31 using boost::gregorian::date;
32 using boost::posix_time::time_duration;
33 
34 namespace impala {
35 
36 // Used for defining a custom date/time format test. The structure can be used to
37 // indicate whether the format or value is expected to fail. In a happy path test,
38 // the values for year, month, day etc will be validated against the parsed result.
39 // Further validation will also be performed if the should_format flag is enabled,
40 // whereby the parsed date/time will be translated back to a string and checked
41 // against the expected value.
42 struct TimestampTC {
43  const char* fmt;
44  const char* str;
57 
58  TimestampTC(const char* fmt, const char* str, bool fmt_should_fail = true,
59  bool str_should_fail = true)
60  : fmt(fmt),
61  str(str),
64  should_format(true),
65  expected_year(0),
66  expected_month(0),
67  expected_day(0),
68  expected_hours(0),
72  fmt_has_date_toks(false),
73  fmt_has_time_toks(false) {
74  }
75 
76  TimestampTC(const char* fmt, const char* str, bool should_format,
78  int expected_month, int expected_day, int expected_hours = 0,
79  int expected_minutes = 0, int expected_seconds = 0,
80  int expected_fraction = 0)
81  : fmt(fmt),
82  str(str),
83  fmt_should_fail(false),
84  str_should_fail(false),
85  should_format(should_format),
86  expected_year(expected_year),
87  expected_month(expected_month),
88  expected_day(expected_day),
93  fmt_has_date_toks(fmt_has_date_toks),
94  fmt_has_time_toks(fmt_has_time_toks) {
95  }
96 };
97 
98 // Used to test custom date/time output test cases i.e. timestamp value -> string.
100  const long ts;
101  const char* fmt;
102  const char* str;
104 
105  TimestampFormatTC(long ts, const char* fmt, const char* str, bool should_fail = false)
106  : ts(ts),
107  fmt(fmt),
108  str(str),
110  }
111 };
112 
113 // Used to represent a parsed timestamp token. For example, it may represent a year.
115  const char* fmt;
116  int val;
117  const char* str;
118 
119  TimestampToken(const char* fmt, int val)
120  : fmt(fmt),
121  val(val),
122  str(NULL) {
123  }
124 
125  TimestampToken(const char* fmt, int val, const char* str)
126  : fmt(fmt),
127  val(val),
128  str(str) {
129  }
130 
131  friend bool operator<(const TimestampToken& lhs, const TimestampToken& rhs) {
132  return strcmp(lhs.fmt, rhs.fmt) < 0;
133  }
134 };
135 
136 inline void ValidateTimestamp(TimestampValue& tv, string& fmt, string& val,
137  string& fmt_val, int year, int month, int day, int hours, int mins, int secs,
138  int frac) {
139  boost::gregorian::date not_a_date;
140  boost::gregorian::date cust_date = tv.date();
141  boost::posix_time::time_duration cust_time = tv.time();
142  EXPECT_NE(not_a_date, cust_date) << fmt_val;
143  EXPECT_NE(not_a_date_time, cust_time) << fmt_val;
144  EXPECT_EQ(year, cust_date.year()) << fmt_val;
145  EXPECT_EQ(month, cust_date.month()) << fmt_val;
146  EXPECT_EQ(day, cust_date.day()) << fmt_val;
147  EXPECT_EQ(hours, cust_time.hours()) << fmt_val;
148  EXPECT_EQ(mins, cust_time.minutes()) << fmt_val;
149  EXPECT_EQ(secs, cust_time.seconds()) << fmt_val;
150  EXPECT_EQ(frac, cust_time.fractional_seconds()) << fmt_val;
151 }
152 
153 // This function will generate all permutations of tokens to test that the parsing and
154 // formatting is correct (position of tokens should be irrelevant). Note that separators
155 // are also combined with EACH token permutation to get the widest coverage on formats.
156 // This forces out the parsing and format logic edge cases.
157 void TestTimestampTokens(vector<TimestampToken>* toks, int year, int month,
158  int day, int hours, int mins, int secs, int frac) {
159  const char* SEPARATORS = " ~!@%^&*_+-:;|\\,./";
160  int toks_len = toks->size();
161  sort(toks->begin(), toks->end());
162  string fmt;
163  string val;
164  do {
165  // Validate we can parse date/time raw tokens (no separators)
166  {
167  for (int i = 0; i < toks_len; ++i) {
168  fmt.append((*toks)[i].fmt);
169  if ((*toks)[i].str != NULL) {
170  val.append(string((*toks)[i].str));
171  } else {
172  val.append(lexical_cast<string>((*toks)[i].val));
173  }
174  }
175  string fmt_val = "Format: " + fmt + ", Val: " + val;
176  DateTimeFormatContext dt_ctx(fmt.c_str(), fmt.length());
177  ASSERT_TRUE(TimestampParser::ParseFormatTokens(&dt_ctx)) << fmt_val;
178  TimestampValue tv(val.c_str(), val.length(), dt_ctx);
179  ValidateTimestamp(tv, fmt, val, fmt_val, year, month, day, hours, mins, secs,
180  frac);
181  int buff_len = dt_ctx.fmt_out_len + 1;
182  char buff[buff_len];
183  int actual_len = tv.Format(dt_ctx, buff_len, buff);
184  EXPECT_GT(actual_len, 0) << fmt_val;
185  EXPECT_LE(actual_len, dt_ctx.fmt_len) << fmt_val;
186  string buff_str(buff);
187  EXPECT_EQ(buff_str, val) << fmt_val << " " << buff_str;
188  fmt.clear();
189  val.clear();
190  }
191  // Validate we can parse date/time with separators
192  {
193  for (const char* separator = SEPARATORS; *separator != 0;
194  ++separator) {
195  for (int i = 0; i < toks_len; ++i) {
196  fmt.append((*toks)[i].fmt);
197  if (i + 1 < toks_len) fmt.push_back(*separator);
198  if ((*toks)[i].str != NULL) {
199  val.append(string((*toks)[i].str));
200  } else {
201  val.append(lexical_cast<string>((*toks)[i].val));
202  }
203  if (i + 1 < toks_len) val.push_back(*separator);
204  }
205  string fmt_val = "Format: " + fmt + ", Val: " + val;
206  DateTimeFormatContext dt_ctx(fmt.c_str(), fmt.length());
207  ASSERT_TRUE(TimestampParser::ParseFormatTokens(&dt_ctx)) << fmt_val;
208  TimestampValue tv(val.c_str(), val.length(), dt_ctx);
209  ValidateTimestamp(tv, fmt, val, fmt_val, year, month, day, hours, mins, secs,
210  frac);
211  int buff_len = dt_ctx.fmt_out_len + 1;
212  char buff[buff_len];
213  int actual_len = tv.Format(dt_ctx, buff_len, buff);
214  EXPECT_GT(actual_len, 0) << fmt_val;
215  EXPECT_LE(actual_len, dt_ctx.fmt_len) << fmt_val;
216  string buff_str(buff);
217  EXPECT_EQ(buff_str, val) << fmt_val << " " << buff_str;
218  fmt.clear();
219  val.clear();
220  }
221  }
222  } while (next_permutation(toks->begin(), toks->end()));
223 }
224 
225 TEST(TimestampTest, Basic) {
226  char s1[] = "2012-01-20 01:10:01";
227  char s2[] = "1990-10-20 10:10:10.123456789 ";
228  char s3[] = " 1990-10-20 10:10:10.123456789";
229 
230  TimestampValue v1(s1, strlen(s1));
231  TimestampValue v2(s2, strlen(s2));
232  TimestampValue v3(s3, strlen(s3));
233 
234  EXPECT_EQ(v1.date().year(), 2012);
235  EXPECT_EQ(v1.date().month(), 1);
236  EXPECT_EQ(v1.date().day(), 20);
237  EXPECT_EQ(v1.time().hours(), 1);
238  EXPECT_EQ(v1.time().minutes(), 10);
239  EXPECT_EQ(v1.time().seconds(), 1);
240  EXPECT_EQ(v1.time().fractional_seconds(), 0);
241  EXPECT_EQ(v2.time().fractional_seconds(), 123456789);
242 
243  EXPECT_NE(v1, v2);
244  EXPECT_EQ(v2, v3);
245  EXPECT_LT(v2, v1);
246  EXPECT_LE(v2, v1);
247  EXPECT_GT(v1, v2);
248  EXPECT_GE(v2, v3);
249 
250  EXPECT_NE(RawValue::GetHashValue(&v1, TYPE_TIMESTAMP, 0),
252  EXPECT_EQ(RawValue::GetHashValue(&v3, TYPE_TIMESTAMP, 0),
254 
255  char s4[] = "2012-01-20T01:10:01";
256  char s5[] = "1990-10-20T10:10:10.123456789";
257 
258  TimestampValue v4(s4, strlen(s4));
259  TimestampValue v5(s5, strlen(s5));
260 
261  EXPECT_EQ(v4.date().year(), 2012);
262  EXPECT_EQ(v4.date().month(), 1);
263  EXPECT_EQ(v4.date().day(), 20);
264  EXPECT_EQ(v4.time().hours(), 1);
265  EXPECT_EQ(v4.time().minutes(), 10);
266  EXPECT_EQ(v4.time().seconds(), 1);
267  EXPECT_EQ(v4.time().fractional_seconds(), 0);
268  EXPECT_EQ(v5.date().year(), 1990);
269  EXPECT_EQ(v5.date().month(), 10);
270  EXPECT_EQ(v5.date().day(), 20);
271  EXPECT_EQ(v5.time().hours(), 10);
272  EXPECT_EQ(v5.time().minutes(), 10);
273  EXPECT_EQ(v5.time().seconds(), 10);
274  EXPECT_EQ(v5.time().fractional_seconds(), 123456789);
275 
276  // Test Dates and Times as timestamps.
277  char d1[] = "2012-01-20";
278  char d2[] = "1990-10-20";
279  TimestampValue dv1(d1, strlen(d1));
280  TimestampValue dv2(d2, strlen(d2));
281 
282  EXPECT_NE(dv1, dv2);
283  EXPECT_LT(dv1, v1);
284  EXPECT_LE(dv1, v1);
285  EXPECT_GT(v1, dv1);
286  EXPECT_GE(v1, dv1);
287  EXPECT_NE(dv2, v2);
288 
289  EXPECT_EQ(dv1.date().year(), 2012);
290  EXPECT_EQ(dv1.date().month(), 1);
291  EXPECT_EQ(dv1.date().day(), 20);
292 
293  char t1[] = "10:11:12.123456789";
294  char t2[] = "00:00:00";
295  TimestampValue tv1(t1, strlen(t1));
296  TimestampValue tv2(t2, strlen(t2));
297 
298  EXPECT_NE(tv1, tv2);
299  EXPECT_NE(tv1, v2);
300 
301  EXPECT_EQ(tv1.time().hours(), 10);
302  EXPECT_EQ(tv1.time().minutes(), 11);
303  EXPECT_EQ(tv1.time().seconds(), 12);
304  EXPECT_EQ(tv1.time().fractional_seconds(), 123456789);
305  EXPECT_EQ(tv2.time().fractional_seconds(), 0);
306 
307  // Test variable fraction lengths
308  const char* FRACTION_MAX_STR = "123456789";
309  const char* TEST_VALS[] = { "2013-12-10 12:04:17.", "2013-12-10T12:04:17.",
310  "12:04:17." };
311  const int TEST_VAL_CNT = sizeof(TEST_VALS) / sizeof(char*);
312  for (int i = 0; i < TEST_VAL_CNT; ++i) {
313  const int VAL_LEN = strlen(TEST_VALS[i]);
314  int fraction_len = strlen(FRACTION_MAX_STR);
315  char frac_buff[VAL_LEN + fraction_len + 1];
316  while (fraction_len > 0) {
317  memcpy(frac_buff, TEST_VALS[i], VAL_LEN);
318  memcpy(frac_buff + VAL_LEN, FRACTION_MAX_STR, fraction_len);
319  *(frac_buff + VAL_LEN + fraction_len) = '\0';
320  TimestampValue tv_frac(frac_buff, strlen(frac_buff));
321  if (frac_buff[4] == '-') {
322  EXPECT_EQ(tv_frac.date().year(), 2013);
323  EXPECT_EQ(tv_frac.date().month(), 12);
324  EXPECT_EQ(tv_frac.date().day(), 10);
325  }
326  EXPECT_EQ(tv_frac.time().hours(), 12);
327  EXPECT_EQ(tv_frac.time().minutes(), 4);
328  EXPECT_EQ(tv_frac.time().seconds(), 17);
330  int32_t fraction =
331  StringParser::StringToInt<int32_t>(FRACTION_MAX_STR, fraction_len, &status);
332  EXPECT_TRUE(StringParser::PARSE_SUCCESS == status);
333  for (int i = fraction_len; i < 9; ++i) fraction *= 10;
334  EXPECT_EQ(tv_frac.time().fractional_seconds(), fraction);
335  --fraction_len;
336  }
337  }
338 
339  // Bad formats
340  char b1[] = "1990-10 10:10:10.123456789";
341  TimestampValue bv1(b1, strlen(b1));
342  boost::gregorian::date not_a_date;
343 
344  EXPECT_EQ(bv1.date(), not_a_date);
345  EXPECT_EQ(bv1.time(), not_a_date_time);
346 
347  char b2[] = "1991-10-10 99:10:10.123456789";
348  TimestampValue bv2(b2, strlen(b2));
349 
350  EXPECT_EQ(bv2.time(), not_a_date_time);
351  EXPECT_EQ(bv2.date(), not_a_date);
352 
353  char b3[] = "1990-10- 10:10:10.123456789";
354  TimestampValue bv3(b3, strlen(b3));
355 
356  EXPECT_EQ(bv3.date(), not_a_date);
357  EXPECT_EQ(bv3.time(), not_a_date_time);
358 
359  char b4[] = "10:1010.123456789";
360  TimestampValue bv4(b4, strlen(b4));
361 
362  EXPECT_EQ(bv4.date(), not_a_date);
363  EXPECT_EQ(bv4.time(), not_a_date_time);
364 
365  char b5[] = "10:11:12.123456 1991-10-10";
366  TimestampValue bv5(b5, strlen(b5));
367 
368  EXPECT_EQ(bv5.date(), not_a_date);
369  EXPECT_EQ(bv5.time(), not_a_date_time);
370 
371  char b6[] = "2012-01-20 01:10:00.123.466";
372  TimestampValue bv6(b6, strlen(b6));
373 
374  EXPECT_EQ(bv6.date(), not_a_date);
375  EXPECT_EQ(bv6.time(), not_a_date_time);
376 
377  char b7[] = "2012-01-20 01:10:00.123 477 ";
378  TimestampValue bv7(b7, strlen(b7));
379 
380  EXPECT_EQ(bv7.date(), not_a_date);
381  EXPECT_EQ(bv7.time(), not_a_date_time);
382 
383  // Test custom formats by generating all permutations of tokens to check parsing and
384  // formatting is behaving correctly (position of tokens should be irrelevant). Note
385  // that separators are also combined with EACH token permutation to get the widest
386  // coverage on formats.
387  const int YEAR = 2013;
388  const int MONTH = 10;
389  const int DAY = 14;
390  const int HOURS = 14;
391  const int MINS = 25;
392  const int SECS = 44;
393  const int FRAC = 123456789;
394  // Test parsing/formatting with numeric date/time tokens
395  vector<TimestampToken> dt_toks = list_of
396  (TimestampToken("dd", DAY))(TimestampToken("MM", MONTH))
397  (TimestampToken("yyyy", YEAR))(TimestampToken("HH", HOURS))
398  (TimestampToken("mm", MINS))(TimestampToken("ss", SECS))
399  (TimestampToken("SSSSSSSSS", FRAC));
400 
401  TestTimestampTokens(&dt_toks, YEAR, MONTH, DAY, HOURS, MINS, SECS, FRAC);
402  // Test literal months
403  const char* months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
404  "Sep", "Oct", "Nov", "Dec"
405  };
406  // Test parsing/formatting of literal months (short)
407  const int MONTH_CNT = (sizeof(months) / sizeof(char**));
408  for (int i = 0; i < MONTH_CNT; ++i) {
409  // Test parsing/formatting with short literal months
410  vector<TimestampToken> dt_lm_toks = list_of
411  (TimestampToken("dd", DAY))(TimestampToken("MMM", i + 1, months[i]))
412  (TimestampToken("yyyy", YEAR))(TimestampToken("HH", HOURS))
413  (TimestampToken("mm", MINS))(TimestampToken("ss", SECS))
414  (TimestampToken("SSSSSSSSS", FRAC));
415  TestTimestampTokens(&dt_lm_toks, YEAR, i + 1, DAY, HOURS, MINS, SECS, FRAC);
416  }
417  // Test parsing/formatting of complex date/time formats
418  vector<TimestampTC> test_cases = boost::assign::list_of
419  // Test tiny date/time
420  (TimestampTC("Myyd", "4139", true, true, false, 2013, 4, 9))
421  // Test case on literal short months
422  (TimestampTC("yyyy-MMM-dd", "2013-OCT-01", false, true, false, 2013, 10, 1))
423  // Test case on literal short months
424  (TimestampTC("yyyy-MMM-dd", "2013-oct-01", false, true, false, 2013, 10, 1))
425  // Test case on literal short months
426  (TimestampTC("yyyy-MMM-dd", "2013-oCt-01", false, true, false, 2013, 10, 1))
427  // Test padding on numeric and literal tokens (short)
428  (TimestampTC("MMMyyyyyydd", "Apr00201309", true, true, false, 2013, 4, 9))
429  // Test duplicate tokens
430  (TimestampTC("yyyy MM dd ddMMMyyyy (HH:mm:ss.SSSS)",
431  "2013 05 12 16Apr1952 (16:53:21.1234)", false, true, true, 1952, 4, 16, 16,
432  53, 21, 123400000))
433  // Test bad year format
434  (TimestampTC("YYYYmmdd", "20131001"))
435  // Test unknown formatting character
436  (TimestampTC("yyyyUUdd", "2013001001"))
437  // Test markers
438  (TimestampTC("TTZZ", "TTZZ"))
439  // Test numeric formatting character
440  (TimestampTC("yyyyMM1dd", "201301111"))
441  // Test out of range year
442  (TimestampTC("yyyyyMMdd", "120130101", false, true))
443  // Test out of range month
444  (TimestampTC("yyyyMMdd", "20131301", false, true))
445  // Test out of range month
446  (TimestampTC("yyyyMMdd", "20130001", false, true))
447  // Test out of range day
448  (TimestampTC("yyyyMMdd", "20130132", false, true))
449  // Test out of range day
450  (TimestampTC("yyyyMMdd", "20130100", false, true))
451  // Test out of range hour
452  (TimestampTC("HH:mm:ss", "24:01:01", false, true))
453  // Test out of range minute
454  (TimestampTC("HH:mm:ss", "23:60:01", false, true))
455  // Test out of range second
456  (TimestampTC("HH:mm:ss", "23:01:60", false, true))
457  // Test characters were numbers should be
458  (TimestampTC("HH:mm:ss", "aa:01:01", false, true))
459  // Test missing year
460  (TimestampTC("MMdd", "1201", false, true))
461  // Test missing month
462  (TimestampTC("yyyydd", "201301", false, true))
463  // Test missing month
464  (TimestampTC("yyyymm", "201301", false, true));
465  // Loop through custom parse/format test cases and execute each one. Each test case
466  // will be explicitly set with a pass/fail expectation related to either the format
467  // or literal value.
468  for (int i = 0; i < test_cases.size(); ++i) {
469  TimestampTC test_case = test_cases[i];
470  DateTimeFormatContext dt_ctx(test_case.fmt, strlen(test_case.fmt));
471  bool parse_result = TimestampParser::ParseFormatTokens(&dt_ctx);
472  if (test_case.fmt_should_fail) {
473  EXPECT_FALSE(parse_result) << "TC: " << i;
474  continue;
475  } else {
476  ASSERT_TRUE(parse_result) << "TC: " << i;
477  }
478  TimestampValue cust_tv(test_case.str, strlen(test_case.str), dt_ctx);
479  boost::gregorian::date cust_date = cust_tv.date();
480  boost::posix_time::time_duration cust_time = cust_tv.time();
481  if (test_case.str_should_fail) {
482  EXPECT_EQ(not_a_date, cust_date) << "TC: " << i;
483  EXPECT_EQ(cust_time, not_a_date_time) << "TC: " << i;
484  continue;
485  }
486  // Check that we have something valid in the timestamp value
487  EXPECT_TRUE((!cust_date.is_special())
488  || (cust_time != not_a_date_time)) << "TC: " << i;
489  // Check the date component (based on any date format tokens being present)
490  if (test_case.fmt_has_date_toks) {
491  EXPECT_NE(cust_date, not_a_date) << "TC: " << i;
492  EXPECT_EQ(test_case.expected_year, cust_date.year()) << "TC: " << i;
493  EXPECT_EQ(test_case.expected_month, cust_date.month()) << "TC: " << i;
494  EXPECT_EQ(test_case.expected_day, cust_date.day()) << "TC: " << i;
495  } else {
496  EXPECT_EQ(not_a_date, cust_date) << "TC: " << i;
497  }
498  // Check the time component (based on any time format tokens being present). Note
499  // that if the date is specified, the time will at least be 00:00:00.0
500  if (test_case.fmt_has_time_toks || test_case.fmt_has_date_toks) {
501  EXPECT_NE(cust_time, not_a_date_time) << "TC: " << i;
502  EXPECT_EQ(test_case.expected_hours, cust_time.hours()) << "TC: " << i;
503  EXPECT_EQ(test_case.expected_minutes, cust_time.minutes()) << "TC: " << i;
504  EXPECT_EQ(test_case.expected_seconds, cust_time.seconds()) << "TC: " << i;
505  EXPECT_EQ(test_case.expected_fraction, cust_time.fractional_seconds()) << "TC: "
506  << i;
507  if (!test_case.should_format) continue;
508  int buff_len = dt_ctx.fmt_out_len + 1;
509  char buff[buff_len];
510  int actual_len = cust_tv.Format(dt_ctx, buff_len, buff);
511  EXPECT_GT(actual_len, 0) << "TC: " << i;
512  EXPECT_LE(actual_len, dt_ctx.fmt_len) << "TC: " << i;
513  EXPECT_EQ(string(test_case.str, strlen(test_case.str)), string(buff, actual_len))
514  << "TC: " << i;
515  } else {
516  EXPECT_EQ(cust_time, not_a_date_time) << test_case.fmt << " " << test_case.str;
517  }
518  }
519  // Test complex formatting of date/times
520  vector<TimestampFormatTC> fmt_test_cases = list_of
521  (TimestampFormatTC(1382337792, "yyyy-MM-dd HH:mm:ss.SSSSSSSSS",
522  "2013-10-21 06:43:12.000000000"))
523  // Test just formatting time tokens
524  (TimestampFormatTC(1382337792, "HH:mm:ss.SSSSSSSSS", "06:43:12.000000000"))
525  (TimestampFormatTC(0, "yyyy-MM-ddTHH:mm:SS.SSSSSSSSSZ",
526  "1970-01-01T00:00:00.000000000Z"))
527  // Test just formatting date tokens
528  (TimestampFormatTC(965779200, "yyyy-MM-dd", "2000-08-09"))
529  // Test short form date tokens
530  (TimestampFormatTC(965779200, "yyyy-M-d", "2000-8-9"))
531  // Test short form tokens on wide dates
532  (TimestampFormatTC(1382337792, "d", "21"))
533  // Test month expansion
534  (TimestampFormatTC(965779200, "MMM/MM/M", "Aug/08/8"))
535  // Test padding on single digits
536  (TimestampFormatTC(965779200, "dddddd/dd/d", "000009/09/9"))
537  // Test padding on double digits
538  (TimestampFormatTC(1382337792, "dddddd/dd/dd", "000021/21/21"))
539  // Test just formatting time tokens on a ts value generated from a date
540  (TimestampFormatTC(965779200, "HH:mm:ss", "00:00:00"));
541  // Loop through format test cases
542  for (int i = 0; i < fmt_test_cases.size(); ++i) {
543  TimestampFormatTC test_case = fmt_test_cases[i];
544  DateTimeFormatContext dt_ctx(test_case.fmt, strlen(test_case.fmt));
545  ASSERT_TRUE(TimestampParser::ParseFormatTokens(&dt_ctx)) << "TC: " << i;
546  TimestampValue cust_tv(test_case.ts);
547  EXPECT_NE(cust_tv.date(), not_a_date) << "TC: " << i;
548  EXPECT_NE(cust_tv.time(), not_a_date_time) << "TC: " << i;
549  EXPECT_GE(dt_ctx.fmt_out_len, dt_ctx.fmt_len);
550  int buff_len = dt_ctx.fmt_out_len + 1;
551  char buff[buff_len];
552  int actual_len = cust_tv.Format(dt_ctx, buff_len, buff);
553  EXPECT_GT(actual_len, 0) << "TC: " << i;
554  EXPECT_LE(actual_len, dt_ctx.fmt_out_len) << "TC: " << i;
555  EXPECT_EQ(string(buff, actual_len),
556  string(test_case.str, strlen(test_case.str))) << "TC: " << i;
557  }
558  // Test edge cases
559  TimestampValue min_date = TimestampValue("1400-01-01", 10);
560  EXPECT_TRUE(min_date.HasDate());
561  EXPECT_TRUE(min_date.HasTime());
562  EXPECT_EQ(-17987443200, min_date.ToUnixTime());
563  EXPECT_EQ("1400-01-01 00:00:00", TimestampValue(-17987443200).DebugString());
564  TimestampValue too_early(-17987443201);
565  EXPECT_FALSE(too_early.HasDate());
566  EXPECT_FALSE(too_early.HasTime());
567  // Apparently 5 digit years don't parse (at least by default) but can be printed.
568  // Boost's documented says the max year supported is 9,999 but 10K seems to be
569  // the actual limit.
570  TimestampValue max_date =
571  TimestampValue(date(10000, Dec, 31), time_duration(23, 59, 59));
572  EXPECT_TRUE(max_date.HasDate());
573  EXPECT_TRUE(max_date.HasTime());
574  EXPECT_EQ(253433923199, max_date.ToUnixTime());
575  EXPECT_EQ("10000-12-31 23:59:59", TimestampValue(253433923199).DebugString());
576  TimestampValue too_late(253433923200);
577  EXPECT_FALSE(too_late.HasDate());
578  EXPECT_FALSE(too_late.HasTime());
579 
580  // Regression tests for IMPALA-1676, Unix times overflow int32 during year 2038
581  EXPECT_EQ("2038-01-19 03:14:08", TimestampValue(2147483648).DebugString());
582  EXPECT_EQ("2038-01-19 03:14:09", TimestampValue(2147483649).DebugString());
583 
584  // Test Unix time as a float
585  EXPECT_EQ(1382337792.07,
586  TimestampValue("2013-10-21 06:43:12.07", 22).ToSubsecondUnixTime());
587  EXPECT_EQ("1970-01-01 00:00:00.008000000", TimestampValue(0.008).DebugString());
588 }
589 
590 }
591 
592 int main(int argc, char **argv) {
593  ::testing::InitGoogleTest(&argc, argv);
594  impala::InitCommonRuntime(argc, argv, false);
595  return RUN_ALL_TESTS();
596 }
int Format(const DateTimeFormatContext &dt_ctx, int len, char *buff)
TimestampFormatTC(long ts, const char *fmt, const char *str, bool should_fail=false)
static bool ParseFormatTokens(DateTimeFormatContext *dt_ctx)
void InitCommonRuntime(int argc, char **argv, bool init_jvm, TestInfo::Mode m=TestInfo::NON_TEST)
Definition: init.cc:122
TEST(AtomicTest, Basic)
Definition: atomic-test.cc:28
friend bool operator<(const TimestampToken &lhs, const TimestampToken &rhs)
const boost::posix_time::time_duration & time() const
int main(int argc, char **argv)
std::string DebugString(const T &val)
Definition: udf-debug.h:27
TimestampToken(const char *fmt, int val, const char *str)
void TestTimestampTokens(vector< TimestampToken > *toks, int year, int month, int day, int hours, int mins, int secs, int frac)
TimestampTC(const char *fmt, const char *str, bool fmt_should_fail=true, bool str_should_fail=true)
TimestampTC(const char *fmt, const char *str, bool should_format, bool fmt_has_date_toks, bool fmt_has_time_toks, int expected_year, int expected_month, int expected_day, int expected_hours=0, int expected_minutes=0, int expected_seconds=0, int expected_fraction=0)
TimestampToken(const char *fmt, int val)
const boost::gregorian::date & date() const
time_t ToUnixTime() const
static uint32_t GetHashValue(const void *v, const ColumnType &type, uint32_t seed=0)
Definition: raw-value.h:168
void ValidateTimestamp(TimestampValue &tv, string &fmt, string &val, string &fmt_val, int year, int month, int day, int hours, int mins, int secs, int frac)