609 lines
19 KiB
C++
609 lines
19 KiB
C++
// Licensed to the Apache Software Foundation (ASF) under one
|
|
// or more contributor license agreements. See the NOTICE file
|
|
// distributed with this work for additional information
|
|
// regarding copyright ownership. The ASF licenses this file
|
|
// to you under the Apache License, Version 2.0 (the
|
|
// "License"); you may not use this file except in compliance
|
|
// with the License. You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing,
|
|
// software distributed under the License is distributed on an
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
#include "exprs/timestamp_functions.h"
|
|
|
|
#include <boost/date_time/posix_time/posix_time.hpp>
|
|
#include <boost/date_time/gregorian/gregorian.hpp>
|
|
#include <boost/date_time/time_zone_base.hpp>
|
|
#include <boost/date_time/local_time/local_time.hpp>
|
|
|
|
#include "exprs/expr.h"
|
|
#include "exprs/anyval_util.h"
|
|
#include "runtime/tuple_row.h"
|
|
#include "runtime/datetime_value.h"
|
|
#include "runtime/runtime_state.h"
|
|
#include "util/path_builder.h"
|
|
#include "runtime/string_value.hpp"
|
|
#include "util/debug_util.h"
|
|
|
|
#define TIMEZONE_DATABASE "be/files/date_time_zonespec.csv"
|
|
|
|
namespace doris {
|
|
|
|
boost::local_time::tz_database TimezoneDatabase::_s_tz_database;
|
|
std::vector<std::string> TimezoneDatabase::_s_tz_region_list;
|
|
|
|
void TimestampFunctions::init() {
|
|
}
|
|
|
|
StringVal TimestampFunctions::from_unix(
|
|
FunctionContext* context, const IntVal& unix_time) {
|
|
if (unix_time.is_null) {
|
|
return StringVal::null();
|
|
}
|
|
DateTimeValue t;
|
|
if (!t.from_unixtime(unix_time.val)) {
|
|
return StringVal::null();
|
|
}
|
|
// default fmt means return DATE_TIME
|
|
t.set_type(TIME_DATETIME);
|
|
char buf[64];
|
|
t.to_string(buf);
|
|
return AnyValUtil::from_string_temp(context, buf);
|
|
}
|
|
|
|
StringVal TimestampFunctions::from_unix(
|
|
FunctionContext* context, const IntVal& unix_time, const StringVal& fmt) {
|
|
if (unix_time.is_null || fmt.is_null) {
|
|
return StringVal::null();
|
|
}
|
|
DateTimeValue t;
|
|
if (!t.from_unixtime(unix_time.val)) {
|
|
return StringVal::null();
|
|
}
|
|
|
|
if (!check_format(fmt, t)) {
|
|
return StringVal::null();
|
|
}
|
|
|
|
char buf[64];
|
|
t.to_string(buf);
|
|
return AnyValUtil::from_string_temp(context, buf);
|
|
}
|
|
|
|
IntVal TimestampFunctions::to_unix(FunctionContext* context) {
|
|
return IntVal(context->impl()->state()->now()->unix_timestamp());
|
|
}
|
|
|
|
IntVal TimestampFunctions::to_unix(
|
|
FunctionContext* context, const StringVal& string_val, const StringVal& fmt) {
|
|
if (string_val.is_null || fmt.is_null) {
|
|
return IntVal::null();
|
|
}
|
|
// const DateTimeVal& tv_val = ToTimestamp(context, string_val, fmt);
|
|
DateTimeValue tv_val;
|
|
if (!tv_val.from_date_format_str(
|
|
(const char*)fmt.ptr, fmt.len, (const char*)string_val.ptr, string_val.len)) {
|
|
return IntVal::null();
|
|
}
|
|
return IntVal(tv_val.unix_timestamp());
|
|
}
|
|
|
|
IntVal TimestampFunctions::to_unix(
|
|
FunctionContext* context, const DateTimeVal& ts_val) {
|
|
if (ts_val.is_null) {
|
|
return IntVal::null();
|
|
}
|
|
const DateTimeValue& tv = DateTimeValue::from_datetime_val(ts_val);
|
|
return IntVal(tv.unix_timestamp());
|
|
}
|
|
|
|
// TODO: accept Java data/time format strings:
|
|
// http://docs.oracle.com/javase/1.4.2/docs/api/java/text/SimpleDateFormat.html
|
|
// Convert them to boost format strings.
|
|
bool TimestampFunctions::check_format(const StringVal& format, DateTimeValue& t) {
|
|
// For now the format must be of the form: yyyy-MM-dd HH:mm:ss
|
|
// where the time part is optional.
|
|
switch (format.len) {
|
|
case 10:
|
|
if (strncmp((const char*)format.ptr, "yyyy-MM-dd", 10) == 0) {
|
|
t.set_type(TIME_DATE);
|
|
return true;
|
|
}
|
|
|
|
break;
|
|
|
|
case 19:
|
|
if (strncmp((const char*)format.ptr, "yyyy-MM-dd HH:mm:ss", 19) == 0) {
|
|
t.set_type(TIME_DATETIME);
|
|
return true;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
report_bad_format(&format);
|
|
return false;
|
|
}
|
|
|
|
void TimestampFunctions::report_bad_format(const StringVal* format) {
|
|
std::string format_str((char *)format->ptr, format->len);
|
|
// LOG(WARNING) << "Bad date/time conversion format: " << format_str
|
|
// << " Format must be: 'yyyy-MM-dd[ HH:mm:ss]'";
|
|
}
|
|
|
|
IntVal TimestampFunctions::year(
|
|
FunctionContext* context, const DateTimeVal& ts_val) {
|
|
if (ts_val.is_null) {
|
|
return IntVal::null();
|
|
}
|
|
const DateTimeValue& ts_value = DateTimeValue::from_datetime_val(ts_val);
|
|
return IntVal(ts_value.year());
|
|
}
|
|
|
|
IntVal TimestampFunctions::quarter(
|
|
FunctionContext* context, const DateTimeVal& ts_val) {
|
|
if (ts_val.is_null) {
|
|
return IntVal::null();
|
|
}
|
|
const DateTimeValue& ts_value = DateTimeValue::from_datetime_val(ts_val);
|
|
return IntVal((ts_value.month() - 1) / 3 + 1);
|
|
}
|
|
|
|
IntVal TimestampFunctions::month(
|
|
FunctionContext* context, const DateTimeVal& ts_val) {
|
|
if (ts_val.is_null) {
|
|
return IntVal::null();
|
|
}
|
|
const DateTimeValue& ts_value = DateTimeValue::from_datetime_val(ts_val);
|
|
return IntVal(ts_value.month());
|
|
}
|
|
|
|
IntVal TimestampFunctions::day_of_month(
|
|
FunctionContext* context, const DateTimeVal& ts_val) {
|
|
if (ts_val.is_null) {
|
|
return IntVal::null();
|
|
}
|
|
const DateTimeValue& ts_value = DateTimeValue::from_datetime_val(ts_val);
|
|
return IntVal(ts_value.day());
|
|
}
|
|
|
|
IntVal TimestampFunctions::day_of_year(
|
|
FunctionContext* context, const DateTimeVal& ts_val) {
|
|
if (ts_val.is_null) {
|
|
return IntVal::null();
|
|
}
|
|
const DateTimeValue& ts_value = DateTimeValue::from_datetime_val(ts_val);
|
|
return IntVal(ts_value.day_of_year());
|
|
}
|
|
|
|
IntVal TimestampFunctions::week_of_year(
|
|
FunctionContext* context, const DateTimeVal& ts_val) {
|
|
if (ts_val.is_null) {
|
|
return IntVal::null();
|
|
}
|
|
const DateTimeValue& ts_value = DateTimeValue::from_datetime_val(ts_val);
|
|
return IntVal(ts_value.week(mysql_week_mode(3)));
|
|
}
|
|
|
|
IntVal TimestampFunctions::hour(
|
|
FunctionContext* context, const DateTimeVal& ts_val) {
|
|
if (ts_val.is_null) {
|
|
return IntVal::null();
|
|
}
|
|
const DateTimeValue& ts_value = DateTimeValue::from_datetime_val(ts_val);
|
|
return IntVal(ts_value.hour());
|
|
}
|
|
|
|
IntVal TimestampFunctions::minute(
|
|
FunctionContext* context, const DateTimeVal& ts_val) {
|
|
if (ts_val.is_null) {
|
|
return IntVal::null();
|
|
}
|
|
const DateTimeValue& ts_value = DateTimeValue::from_datetime_val(ts_val);
|
|
return IntVal(ts_value.minute());
|
|
}
|
|
|
|
IntVal TimestampFunctions::second(
|
|
FunctionContext* context, const DateTimeVal& ts_val) {
|
|
if (ts_val.is_null) {
|
|
return IntVal::null();
|
|
}
|
|
const DateTimeValue& ts_value = DateTimeValue::from_datetime_val(ts_val);
|
|
return IntVal(ts_value.second());
|
|
}
|
|
|
|
DateTimeVal TimestampFunctions::now(FunctionContext* context) {
|
|
const DateTimeValue* now = context->impl()->state()->now();
|
|
DateTimeVal return_val;
|
|
now->to_datetime_val(&return_val);
|
|
return return_val;
|
|
}
|
|
|
|
DateTimeVal TimestampFunctions::curtime(FunctionContext* context) {
|
|
DateTimeValue now = *context->impl()->state()->now();
|
|
now.cast_to_time();
|
|
DateTimeVal return_val;
|
|
now.to_datetime_val(&return_val);
|
|
return return_val;
|
|
}
|
|
|
|
DateTimeVal TimestampFunctions::to_date(
|
|
FunctionContext* ctx, const DateTimeVal& ts_val) {
|
|
if (ts_val.is_null) {
|
|
return DateTimeVal::null();
|
|
}
|
|
DateTimeValue ts_value = DateTimeValue::from_datetime_val(ts_val);
|
|
ts_value.cast_to_date();
|
|
DateTimeVal result;
|
|
ts_value.to_datetime_val(&result);
|
|
return result;
|
|
}
|
|
|
|
DateTimeVal TimestampFunctions::str_to_date(
|
|
FunctionContext* ctx, const StringVal& str, const StringVal& format) {
|
|
if (str.is_null || format.is_null) {
|
|
return DateTimeVal::null();
|
|
}
|
|
DateTimeValue ts_value;
|
|
if (!ts_value.from_date_format_str((const char*)format.ptr, format.len,
|
|
(const char*)str.ptr, str.len)) {
|
|
return DateTimeVal::null();
|
|
}
|
|
DateTimeVal ts_val;
|
|
ts_value.to_datetime_val(&ts_val);
|
|
return ts_val;
|
|
}
|
|
|
|
StringVal TimestampFunctions::month_name(
|
|
FunctionContext* ctx, const DateTimeVal& ts_val) {
|
|
if (ts_val.is_null) {
|
|
return StringVal::null();
|
|
}
|
|
const DateTimeValue& ts_value = DateTimeValue::from_datetime_val(ts_val);
|
|
const char* name = ts_value.month_name();
|
|
if (name == NULL) {
|
|
return StringVal::null();
|
|
}
|
|
return AnyValUtil::from_string_temp(ctx, name);
|
|
}
|
|
|
|
StringVal TimestampFunctions::day_name(
|
|
FunctionContext* ctx, const DateTimeVal& ts_val) {
|
|
if (ts_val.is_null) {
|
|
return StringVal::null();
|
|
}
|
|
const DateTimeValue& ts_value = DateTimeValue::from_datetime_val(ts_val);
|
|
const char* name = ts_value.day_name();
|
|
if (name == NULL) {
|
|
return StringVal::null();
|
|
}
|
|
return AnyValUtil::from_string_temp(ctx, name);
|
|
}
|
|
|
|
DateTimeVal TimestampFunctions::years_add(
|
|
FunctionContext* ctx, const DateTimeVal& ts_val,
|
|
const IntVal& count) {
|
|
return timestamp_time_op<YEAR>(ctx, ts_val, count, true);
|
|
}
|
|
|
|
DateTimeVal TimestampFunctions::years_sub(
|
|
FunctionContext* ctx, const DateTimeVal& ts_val,
|
|
const IntVal& count) {
|
|
return timestamp_time_op<YEAR>(ctx, ts_val, count, false);
|
|
}
|
|
|
|
DateTimeVal TimestampFunctions::months_add(
|
|
FunctionContext* ctx, const DateTimeVal& ts_val,
|
|
const IntVal& count) {
|
|
return timestamp_time_op<MONTH>(ctx, ts_val, count, true);
|
|
}
|
|
|
|
DateTimeVal TimestampFunctions::months_sub(
|
|
FunctionContext* ctx, const DateTimeVal& ts_val,
|
|
const IntVal& count) {
|
|
return timestamp_time_op<MONTH>(ctx, ts_val, count, false);
|
|
}
|
|
|
|
DateTimeVal TimestampFunctions::weeks_add(
|
|
FunctionContext* ctx, const DateTimeVal& ts_val,
|
|
const IntVal& count) {
|
|
return timestamp_time_op<WEEK>(ctx, ts_val, count, true);
|
|
}
|
|
|
|
DateTimeVal TimestampFunctions::weeks_sub(
|
|
FunctionContext* ctx, const DateTimeVal& ts_val,
|
|
const IntVal& count) {
|
|
return timestamp_time_op<WEEK>(ctx, ts_val, count, false);
|
|
}
|
|
|
|
DateTimeVal TimestampFunctions::days_add(
|
|
FunctionContext* ctx, const DateTimeVal& ts_val,
|
|
const IntVal& count) {
|
|
return timestamp_time_op<DAY>(ctx, ts_val, count, true);
|
|
}
|
|
|
|
DateTimeVal TimestampFunctions::days_sub(
|
|
FunctionContext* ctx, const DateTimeVal& ts_val,
|
|
const IntVal& count) {
|
|
return timestamp_time_op<DAY>(ctx, ts_val, count, false);
|
|
}
|
|
|
|
DateTimeVal TimestampFunctions::hours_add(
|
|
FunctionContext* ctx, const DateTimeVal& ts_val,
|
|
const IntVal& count) {
|
|
return timestamp_time_op<HOUR>(ctx, ts_val, count, true);
|
|
}
|
|
|
|
DateTimeVal TimestampFunctions::hours_sub(
|
|
FunctionContext* ctx, const DateTimeVal& ts_val,
|
|
const IntVal& count) {
|
|
return timestamp_time_op<HOUR>(ctx, ts_val, count, false);
|
|
}
|
|
|
|
DateTimeVal TimestampFunctions::minutes_add(
|
|
FunctionContext* ctx, const DateTimeVal& ts_val,
|
|
const IntVal& count) {
|
|
return timestamp_time_op<MINUTE>(ctx, ts_val, count, true);
|
|
}
|
|
|
|
DateTimeVal TimestampFunctions::minutes_sub(
|
|
FunctionContext* ctx, const DateTimeVal& ts_val,
|
|
const IntVal& count) {
|
|
return timestamp_time_op<MINUTE>(ctx, ts_val, count, false);
|
|
}
|
|
|
|
DateTimeVal TimestampFunctions::seconds_add(
|
|
FunctionContext* ctx, const DateTimeVal& ts_val,
|
|
const IntVal& count) {
|
|
return timestamp_time_op<SECOND>(ctx, ts_val, count, true);
|
|
}
|
|
|
|
DateTimeVal TimestampFunctions::seconds_sub(
|
|
FunctionContext* ctx, const DateTimeVal& ts_val,
|
|
const IntVal& count) {
|
|
return timestamp_time_op<SECOND>(ctx, ts_val, count, false);
|
|
}
|
|
|
|
DateTimeVal TimestampFunctions::micros_add(
|
|
FunctionContext* ctx, const DateTimeVal& ts_val,
|
|
const IntVal& count) {
|
|
return timestamp_time_op<MICROSECOND>(ctx, ts_val, count, true);
|
|
}
|
|
|
|
DateTimeVal TimestampFunctions::micros_sub(
|
|
FunctionContext* ctx, const DateTimeVal& ts_val,
|
|
const IntVal& count) {
|
|
return timestamp_time_op<MICROSECOND>(ctx, ts_val, count, false);
|
|
}
|
|
|
|
template <TimeUnit unit>
|
|
DateTimeVal TimestampFunctions::timestamp_time_op(
|
|
FunctionContext* ctx, const DateTimeVal& ts_val,
|
|
const IntVal& count, bool is_add) {
|
|
if (ts_val.is_null || count.is_null) {
|
|
return DateTimeVal::null();
|
|
}
|
|
TimeInterval interval(unit, count.val, !is_add);
|
|
|
|
DateTimeValue ts_value = DateTimeValue::from_datetime_val(ts_val);
|
|
if (!ts_value.date_add_interval(interval, unit)) {
|
|
return DateTimeVal::null();
|
|
}
|
|
DateTimeVal new_ts_val;
|
|
ts_value.to_datetime_val(&new_ts_val);
|
|
|
|
return new_ts_val;
|
|
}
|
|
|
|
StringVal TimestampFunctions::date_format(
|
|
FunctionContext* ctx, const DateTimeVal& ts_val, const StringVal& format) {
|
|
if (ts_val.is_null || format.is_null) {
|
|
return StringVal::null();
|
|
}
|
|
DateTimeValue ts_value = DateTimeValue::from_datetime_val(ts_val);
|
|
if (ts_value.compute_format_len((const char*)format.ptr, format.len) >= 128) {
|
|
return StringVal::null();
|
|
}
|
|
char buf[128];
|
|
if (!ts_value.to_format_string((const char*)format.ptr, format.len, buf)) {
|
|
return StringVal::null();
|
|
}
|
|
return AnyValUtil::from_string_temp(ctx, buf);
|
|
}
|
|
|
|
DateTimeVal TimestampFunctions::from_days(
|
|
FunctionContext* ctx, const IntVal& days) {
|
|
if (days.is_null) {
|
|
return DateTimeVal::null();
|
|
}
|
|
DateTimeValue ts_value;
|
|
if (!ts_value.from_date_daynr(days.val)) {
|
|
return DateTimeVal::null();
|
|
}
|
|
DateTimeVal ts_val;
|
|
ts_value.to_datetime_val(&ts_val);
|
|
return ts_val;
|
|
}
|
|
|
|
IntVal TimestampFunctions::to_days(
|
|
FunctionContext* ctx, const DateTimeVal& ts_val) {
|
|
if (ts_val.is_null) {
|
|
return IntVal::null();
|
|
}
|
|
const DateTimeValue& ts_value = DateTimeValue::from_datetime_val(ts_val);
|
|
return IntVal(ts_value.daynr());
|
|
}
|
|
|
|
// TODO(dhc): implement this funciton really
|
|
DateTimeVal TimestampFunctions::time_diff(
|
|
FunctionContext* ctx, const DateTimeVal& ts_val1, const DateTimeVal& ts_val2) {
|
|
if (ts_val1.is_null || ts_val2.is_null) {
|
|
return DateTimeVal::null();
|
|
}
|
|
const DateTimeValue& ts_value1 = DateTimeValue::from_datetime_val(ts_val1);
|
|
const DateTimeValue& ts_value2 = DateTimeValue::from_datetime_val(ts_val2);
|
|
DateTimeValue ts = ts_value1 - ts_value2;
|
|
ts.cast_to_time();
|
|
DateTimeVal result;
|
|
ts.to_datetime_val(&result);
|
|
return result;
|
|
}
|
|
|
|
IntVal TimestampFunctions::date_diff(
|
|
FunctionContext* ctx, const DateTimeVal& ts_val1, const DateTimeVal& ts_val2) {
|
|
if (ts_val1.is_null || ts_val2.is_null) {
|
|
return IntVal::null();
|
|
}
|
|
const DateTimeValue& ts_value1 = DateTimeValue::from_datetime_val(ts_val1);
|
|
const DateTimeValue& ts_value2 = DateTimeValue::from_datetime_val(ts_val2);
|
|
return IntVal(ts_value1.daynr() - ts_value2.daynr());
|
|
}
|
|
|
|
DateTimeVal TimestampFunctions::timestamp(
|
|
FunctionContext* ctx, const DateTimeVal& val) {
|
|
return val;
|
|
}
|
|
|
|
void* TimestampFunctions::from_utc(Expr* e, TupleRow* row) {
|
|
return NULL;
|
|
// DCHECK_EQ(e->get_num_children(), 2);
|
|
// Expr* op1 = e->children()[0];
|
|
// Expr* op2 = e->children()[1];
|
|
// DateTimeValue* tv = reinterpret_cast<DateTimeValue*>(op1->get_value(row));
|
|
// StringValue* tz = reinterpret_cast<StringValue*>(op2->get_value(row));
|
|
|
|
// if (tv == NULL || tz == NULL) {
|
|
// return NULL;
|
|
// }
|
|
|
|
// if (tv->not_a_date_time()) {
|
|
// return NULL;
|
|
// }
|
|
|
|
// boost::local_time::time_zone_ptr timezone = TimezoneDatabase::find_timezone(tz->debug_string());
|
|
|
|
// This should raise some sort of error or at least null. Hive just ignores it.
|
|
// if (timezone == NULL) {
|
|
// LOG(ERROR) << "Unknown timezone '" << *tz << "'" << std::endl;
|
|
// e->_result.timestamp_val = *tv;
|
|
// return &e->_result.timestamp_val;
|
|
// }
|
|
|
|
// boost::posix_time::ptime temp;
|
|
// tv->to_ptime(&temp);
|
|
// boost::local_time::local_date_time lt(temp, timezone);
|
|
// e->_result.timestamp_val = lt.local_time();
|
|
// return &e->_result.timestamp_val;
|
|
}
|
|
|
|
void* TimestampFunctions::to_utc(Expr* e, TupleRow* row) {
|
|
return NULL;
|
|
// DCHECK_EQ(e->get_num_children(), 2);
|
|
// Expr* op1 = e->children()[0];
|
|
// Expr* op2 = e->children()[1];
|
|
// DateTimeValue* tv = reinterpret_cast<DateTimeValue*>(op1->get_value(row));
|
|
// StringValue* tz = reinterpret_cast<StringValue*>(op2->get_value(row));
|
|
|
|
// if (tv == NULL || tz == NULL) {
|
|
// return NULL;
|
|
// }
|
|
|
|
// if (tv->not_a_date_time()) {
|
|
// return NULL;
|
|
// }
|
|
|
|
// boost::local_time::time_zone_ptr timezone = TimezoneDatabase::find_timezone(tz->debug_string());
|
|
|
|
// This should raise some sort of error or at least null. Hive just ignores it.
|
|
// if (timezone == NULL) {
|
|
// LOG(ERROR) << "Unknown timezone '" << *tz << "'" << std::endl;
|
|
// e->_result.timestamp_val = *tv;
|
|
// return &e->_result.timestamp_val;
|
|
// }
|
|
|
|
// boost::local_time::local_date_time lt(tv->date(), tv->time_of_day(),
|
|
// timezone, boost::local_time::local_date_time::NOT_DATE_TIME_ON_ERROR);
|
|
// e->_result.timestamp_val = DateTimeValue(lt.utc_time());
|
|
// return &e->_result.timestamp_val;
|
|
}
|
|
|
|
TimezoneDatabase::TimezoneDatabase() {
|
|
// Create a temporary file and write the timezone information. The boost
|
|
// interface only loads this format from a file. We don't want to raise
|
|
// an error here since this is done when the backend is created and this
|
|
// information might not actually get used by any queries.
|
|
char filestr[] = "/tmp/doris.tzdb.XXXXXXX";
|
|
FILE* file = NULL;
|
|
int fd = -1;
|
|
|
|
if ((fd = mkstemp(filestr)) == -1) {
|
|
LOG(ERROR) << "Could not create temporary timezone file: " << filestr;
|
|
return;
|
|
}
|
|
|
|
if ((file = fopen(filestr, "w")) == NULL) {
|
|
unlink(filestr);
|
|
close(fd);
|
|
LOG(ERROR) << "Could not open temporary timezone file: " << filestr;
|
|
return;
|
|
}
|
|
|
|
if (fputs(_s_timezone_database_str, file) == EOF) {
|
|
unlink(filestr);
|
|
close(fd);
|
|
fclose(file);
|
|
LOG(ERROR) << "Could not load temporary timezone file: " << filestr;
|
|
return;
|
|
}
|
|
|
|
fclose(file);
|
|
_s_tz_database.load_from_file(std::string(filestr));
|
|
_s_tz_region_list = _s_tz_database.region_list();
|
|
unlink(filestr);
|
|
close(fd);
|
|
}
|
|
|
|
TimezoneDatabase::~TimezoneDatabase() { }
|
|
|
|
boost::local_time::time_zone_ptr TimezoneDatabase::find_timezone(const std::string& tz) {
|
|
// See if they specified a zone id
|
|
if (tz.find_first_of('/') != std::string::npos) {
|
|
return _s_tz_database.time_zone_from_region(tz);
|
|
}
|
|
|
|
for (std::vector<std::string>::const_iterator iter = _s_tz_region_list.begin();
|
|
iter != _s_tz_region_list.end(); ++iter) {
|
|
boost::local_time::time_zone_ptr tzp = _s_tz_database.time_zone_from_region(*iter);
|
|
DCHECK(tzp != NULL);
|
|
|
|
if (tzp->dst_zone_abbrev() == tz) {
|
|
return tzp;
|
|
}
|
|
|
|
if (tzp->std_zone_abbrev() == tz) {
|
|
return tzp;
|
|
}
|
|
|
|
if (tzp->dst_zone_name() == tz) {
|
|
return tzp;
|
|
}
|
|
|
|
if (tzp->std_zone_name() == tz) {
|
|
return tzp;
|
|
}
|
|
}
|
|
|
|
return boost::local_time::time_zone_ptr();
|
|
|
|
}
|
|
|
|
}
|