15 #include <boost/date_time/posix_time/posix_time.hpp>
16 #include <boost/date_time/gregorian/gregorian.hpp>
17 #include <boost/date_time/time_zone_base.hpp>
18 #include <boost/date_time/local_time/local_time.hpp>
19 #include <boost/algorithm/string.hpp>
20 #include <gutil/strings/substitute.h>
34 #define TIMEZONE_DATABASE "be/files/date_time_zonespec.csv"
38 using boost::algorithm::iequals;
39 using boost::gregorian::days;
40 using boost::gregorian::months;
41 using boost::gregorian::weeks;
42 using boost::gregorian::years;
43 using boost::local_time::local_date_time;
44 using boost::local_time::time_zone_ptr;
45 using boost::posix_time::hours;
46 using boost::posix_time::microseconds;
47 using boost::posix_time::milliseconds;
48 using boost::posix_time::minutes;
49 using boost::posix_time::nanoseconds;
50 using boost::posix_time::ptime;
51 using boost::posix_time::seconds;
52 using namespace impala_udf;
53 using namespace strings;
58 const char* TimestampFunctions::SUNDAY =
"Sunday";
59 const char* TimestampFunctions::MONDAY =
"Monday";
60 const char* TimestampFunctions::TUESDAY =
"Tuesday";
61 const char* TimestampFunctions::WEDNESDAY =
"Wednesday";
62 const char* TimestampFunctions::THURSDAY =
"Thursday";
63 const char* TimestampFunctions::FRIDAY =
"Friday";
64 const char* TimestampFunctions::SATURDAY =
"Saturday";
72 const StringValue& fmt_ref = StringValue::FromStringVal(fmt_val);
74 TimestampFunctions::ReportBadFormat(context, fmt_val,
true);
78 bool parse_result = TimestampParser::ParseFormatTokens(dt_ctx);
81 TimestampFunctions::ReportBadFormat(context, fmt_val,
true);
102 template <
class TIME>
106 return AnyValUtil::FromString(context, lexical_cast<string>(t));
109 template <
class TIME>
113 TimestampFunctions::ReportBadFormat(context, fmt,
false);
122 dt_ctx->
Reset(reinterpret_cast<const char*>(fmt.
ptr), fmt.
len);
123 if (!TimestampParser::ParseFormatTokens(dt_ctx)){
124 TimestampFunctions::ReportBadFormat(context, fmt,
false);
131 result.
len = t.
Format(*dt_ctx, buff_len, reinterpret_cast<char*>(result.
ptr));
139 TimestampFunctions::ReportBadFormat(context, fmt,
false);
147 dt_ctx->
Reset(reinterpret_cast<const char*>(fmt.
ptr), fmt.
len);
148 if (!TimestampParser::ParseFormatTokens(dt_ctx)) {
149 ReportBadFormat(context, fmt,
false);
155 reinterpret_cast<const char*>(string_val.
ptr), string_val.
len, *dt_ctx);
162 const TimestampValue& tv = TimestampValue::FromTimestampVal(ts_val);
181 const StringVal& format,
bool is_error) {
183 const StringValue& fmt = StringValue::FromStringVal(format);
185 ss <<
"Bad date/time conversion format: format string is NULL or has 0 length";
187 ss <<
"Bad date/time conversion format: " << fmt.
DebugString();
190 context->
SetError(ss.str().c_str());
198 IntVal dow = DayOfWeek(context, ts);
213 const TimestampValue& ts_value = TimestampValue::FromTimestampVal(ts_val);
221 const TimestampValue& ts_value = TimestampValue::FromTimestampVal(ts_val);
230 const TimestampValue& ts_value = TimestampValue::FromTimestampVal(ts_val);
233 return IntVal(ts_value.
date().day_of_week() + 1);
239 const TimestampValue& ts_value = TimestampValue::FromTimestampVal(ts_val);
247 const TimestampValue& ts_value = TimestampValue::FromTimestampVal(ts_val);
255 const TimestampValue& ts_value = TimestampValue::FromTimestampVal(ts_val);
262 const TimestampValue& ts_value = TimestampValue::FromTimestampVal(ts_val);
269 const TimestampValue& ts_value = TimestampValue::FromTimestampVal(ts_val);
276 const TimestampValue& ts_value = TimestampValue::FromTimestampVal(ts_val);
292 const TimestampValue ts_value = TimestampValue::FromTimestampVal(ts_val);
293 string result = to_iso_extended_string(ts_value.
date());
294 return AnyValUtil::FromString(context, result);
297 template <
bool ISADD,
class VALTYPE,
class UNIT>
301 const TimestampValue& ts_value = TimestampValue::FromTimestampVal(ts_val);
304 UNIT unit(count.val);
309 (ISADD ? ts_value.
date() + unit : ts_value.
date() - unit), ts_value.
time());
310 }
catch (
const std::exception& e) {
311 context->
AddWarning(Substitute(
"Cannot $0 date interval $1: $2",
312 ISADD ?
"add" :
"subtract", count.val, e.what()).c_str());
320 template <
bool ISADD,
class VALTYPE,
class UNIT>
324 const TimestampValue& ts_value = TimestampValue::FromTimestampVal(ts_val);
326 UNIT unit(count.val);
327 ptime p(ts_value.
date(), ts_value.
time());
330 value.ToTimestampVal(&return_val);
338 const TimestampValue& ts_value1 = TimestampValue::FromTimestampVal(ts_val1);
339 const TimestampValue& ts_value2 = TimestampValue::FromTimestampVal(ts_val2);
352 const TimestampValue& ts_value = TimestampValue::FromTimestampVal(ts_val);
355 const StringValue& tz_string_value = StringValue::FromStringVal(tz_string_val);
356 time_zone_ptr timezone =
357 TimezoneDatabase::FindTimezone(tz_string_value.
DebugString(), ts_value);
358 if (timezone == NULL) {
361 ss <<
"Unknown timezone '" << tz_string_value <<
"'" << endl;
368 local_date_time lt(temp, timezone);
381 const TimestampValue& ts_value = TimestampValue::FromTimestampVal(ts_val);
384 const StringValue& tz_string_value = StringValue::FromStringVal(tz_string_val);
385 time_zone_ptr timezone =
386 TimezoneDatabase::FindTimezone(tz_string_value.
DebugString(), ts_value);
388 if (timezone == NULL) {
390 ss <<
"Unknown timezone '" << tz_string_value <<
"'" << endl;
395 local_date_time lt(ts_value.
date(), ts_value.
time(),
396 timezone, local_date_time::NOT_DATE_TIME_ON_ERROR);
399 return_value.ToTimestampVal(&return_val);
403 TimezoneDatabase::TimezoneDatabase() {
408 char filestr[] =
"/tmp/impala.tzdb.XXXXXXX";
411 if ((fd = mkstemp(filestr)) == -1) {
412 LOG(ERROR) <<
"Could not create temporary timezone file: " << filestr;
415 if ((file = fopen(filestr,
"w")) == NULL) {
418 LOG(ERROR) <<
"Could not open temporary timezone file: " << filestr;
421 if (fputs(TIMEZONE_DATABASE_STR, file) == EOF) {
425 LOG(ERROR) <<
"Could not load temporary timezone file: " << filestr;
429 tz_database_.load_from_file(
string(filestr));
430 tz_region_list_ = tz_database_.region_list();
435 TimezoneDatabase::~TimezoneDatabase() { }
437 time_zone_ptr TimezoneDatabase::FindTimezone(
const string& tz,
const TimestampValue& tv) {
439 if ((tv.
date().year() > 2011 || (tv.
date().year() == 2011 && tv.
date().month() >= 4)) &&
440 (iequals(
"Europe/Moscow", tz) || iequals(
"Moscow", tz) || iequals(
"MSK", tz))) {
451 return TIMEZONE_MSK_2011_NODST;
455 if (tz.find_first_of(
'/') != string::npos) {
456 return tz_database_.time_zone_from_region(tz);
458 for (vector<string>::const_iterator iter = tz_region_list_.begin();
459 iter != tz_region_list_.end(); ++iter) {
460 time_zone_ptr tzp = tz_database_.time_zone_from_region(*iter);
462 if (tzp->dst_zone_abbrev() == tz)
464 if (tzp->std_zone_abbrev() == tz)
466 if (tzp->dst_zone_name() == tz)
468 if (tzp->std_zone_name() == tz)
471 return time_zone_ptr();
490 TimestampFunctions::DateAddSub<true, IntVal, years>(
FunctionContext* context,
493 TimestampFunctions::DateAddSub<true, BigIntVal, years>(
FunctionContext* context,
496 TimestampFunctions::DateAddSub<false, IntVal, years>(
FunctionContext* context,
499 TimestampFunctions::DateAddSub<false, BigIntVal, years>(
FunctionContext* context,
502 TimestampFunctions::DateAddSub<true, IntVal, months>(
FunctionContext* context,
505 TimestampFunctions::DateAddSub<true, BigIntVal, months>(
FunctionContext* context,
508 TimestampFunctions::DateAddSub<false, IntVal, months>(
FunctionContext* context,
511 TimestampFunctions::DateAddSub<false, BigIntVal, months>(
FunctionContext* context,
514 TimestampFunctions::DateAddSub<true, IntVal, weeks>(
FunctionContext* context,
517 TimestampFunctions::DateAddSub<true, BigIntVal, weeks>(
FunctionContext* context,
520 TimestampFunctions::DateAddSub<false, IntVal, weeks>(
FunctionContext* context,
523 TimestampFunctions::DateAddSub<false, BigIntVal, weeks>(
FunctionContext* context,
526 TimestampFunctions::DateAddSub<true, IntVal, days>(
FunctionContext* context,
529 TimestampFunctions::DateAddSub<true, BigIntVal, days>(
FunctionContext* context,
532 TimestampFunctions::DateAddSub<false, IntVal, days>(
FunctionContext* context,
535 TimestampFunctions::DateAddSub<false, BigIntVal, days>(
FunctionContext* context,
539 TimestampFunctions::TimeAddSub<true, IntVal, hours>(
FunctionContext* context,
542 TimestampFunctions::TimeAddSub<true, BigIntVal, hours>(
FunctionContext* context,
545 TimestampFunctions::TimeAddSub<false, IntVal, hours>(
FunctionContext* context,
548 TimestampFunctions::TimeAddSub<false, BigIntVal, hours>(
FunctionContext* context,
551 TimestampFunctions::TimeAddSub<true, IntVal, minutes>(
FunctionContext* context,
554 TimestampFunctions::TimeAddSub<true, BigIntVal, minutes>(
FunctionContext* context,
557 TimestampFunctions::TimeAddSub<false, IntVal, minutes>(
FunctionContext* context,
560 TimestampFunctions::TimeAddSub<false, BigIntVal, minutes>(
FunctionContext* context,
563 TimestampFunctions::TimeAddSub<true, IntVal, seconds>(
FunctionContext* context,
566 TimestampFunctions::TimeAddSub<true, BigIntVal, seconds>(
FunctionContext* context,
569 TimestampFunctions::TimeAddSub<false, IntVal, seconds>(
FunctionContext* context,
572 TimestampFunctions::TimeAddSub<false, BigIntVal, seconds>(
FunctionContext* context,
575 TimestampFunctions::TimeAddSub<true, IntVal, milliseconds>(
FunctionContext* context,
578 TimestampFunctions::TimeAddSub<true, BigIntVal, milliseconds>(
FunctionContext* context,
581 TimestampFunctions::TimeAddSub<false, IntVal, milliseconds>(
FunctionContext* context,
584 TimestampFunctions::TimeAddSub<false, BigIntVal, milliseconds>(
FunctionContext* context,
587 TimestampFunctions::TimeAddSub<true, IntVal, microseconds>(
FunctionContext* context,
590 TimestampFunctions::TimeAddSub<true, BigIntVal, microseconds>(
FunctionContext* context,
593 TimestampFunctions::TimeAddSub<false, IntVal, microseconds>(
FunctionContext* context,
596 TimestampFunctions::TimeAddSub<false, BigIntVal, microseconds>(
FunctionContext* context,
599 TimestampFunctions::TimeAddSub<true, IntVal, nanoseconds>(
FunctionContext* context,
602 TimestampFunctions::TimeAddSub<true, BigIntVal, nanoseconds>(
FunctionContext* context,
605 TimestampFunctions::TimeAddSub<false, IntVal, nanoseconds>(
FunctionContext* context,
608 TimestampFunctions::TimeAddSub<false, BigIntVal, nanoseconds>(
FunctionContext* context,
int Format(const DateTimeFormatContext &dt_ctx, int len, char *buff)
impala::FunctionContextImpl * impl()
TODO: Add mechanism for UDAs to update stats similar to runtime profile counters. ...
void Reset(const char *fmt, int fmt_len)
bool HasDateOrTime() const
const boost::posix_time::time_duration & time() const
This object has a compatible storage format with boost::ptime.
void ToTimestampVal(impala_udf::TimestampVal *tv) const
bool AddWarning(const char *warning_msg)
static TimestampVal null()
void * GetFunctionState(FunctionStateScope scope) const
bool IsArgConstant(int arg_idx) const
void SetFunctionState(FunctionStateScope scope, void *ptr)
void ToPtime(boost::posix_time::ptime *ptp) const
const TimestampValue * now() const
void SetError(const char *error_msg)
const boost::gregorian::date & date() const
AnyVal * GetConstantArg(int arg_idx) const
time_t ToUnixTime() const
std::string DebugString() const