Skip to content

Commit

Permalink
fix(query): to_timestmap should always return err if parse err (#15850)
Browse files Browse the repository at this point in the history
* fix(query): to_timestmap should always return err if parse err

If do not want to see err in to_timestamp, could use try_to_timesmtap

* In to_timestmap(string, format)

if not asign the string tz or format do not parse tz,

the string use with current session timezone

* fix fmt err

* fix test
  • Loading branch information
TCeason committed Jun 21, 2024
1 parent 9904f24 commit 0a9d259
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 24 deletions.
51 changes: 37 additions & 14 deletions src/query/functions/src/scalars/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ use chrono::format::StrftimeItems;
use chrono::prelude::*;
use chrono::Datelike;
use chrono::Days;
use chrono::ParseError;
use chrono::MappedLocalTime;
use chrono::Utc;
use chrono_tz::Tz;
use databend_common_arrow::arrow::bitmap::Bitmap;
use databend_common_arrow::arrow::temporal_conversions::EPOCH_DAYS_FROM_CE;
use databend_common_exception::ErrorCode;
use databend_common_expression::error_to_null;
use databend_common_expression::types::date::check_date;
use databend_common_expression::types::date::date_to_string;
Expand Down Expand Up @@ -256,7 +257,7 @@ fn string_to_format_timestmap(
timestamp: &str,
format: &str,
ctx: &mut EvalContext,
) -> Result<(i64, bool), ParseError> {
) -> Result<(i64, bool), ErrorCode> {
if format.is_empty() {
return Ok((0, true));
}
Expand All @@ -271,10 +272,10 @@ fn string_to_format_timestmap(
let parse_tz = timezone_strftime
.iter()
.any(|&pattern| format.contains(pattern));
let res = if ctx.func_ctx.parse_datetime_ignore_remainder {
if ctx.func_ctx.parse_datetime_ignore_remainder {
let mut parsed = Parsed::new();
if parse_and_remainder(&mut parsed, timestamp, StrftimeItems::new(format)).is_err() {
return Ok((0, true));
if let Err(e) = parse_and_remainder(&mut parsed, timestamp, StrftimeItems::new(format)) {
return Err(ErrorCode::BadArguments(format!("{}", e)));
}
// Additional checks and adjustments for parsed timestamp
if parsed.month.is_none() {
Expand All @@ -293,27 +294,49 @@ fn string_to_format_timestmap(
if parsed.second.is_none() {
parsed.second = Some(0);
}

// fn handle_err<T>(result: Result<T, impl ToString>) -> Result<T, ErrorCode> {
// result.map_err(|e| ErrorCode::BadArguments(e.to_string()))
// }
// Convert parsed timestamp to datetime or naive datetime based on parse_tz
if parse_tz {
parsed.offset.get_or_insert(0);
parsed
.to_datetime()
.map(|res| res.with_timezone(&ctx.func_ctx.tz.tz).timestamp_micros())
.map(|res| (res.timestamp_micros(), false))
.map_err(|err| ErrorCode::BadArguments(format!("{err}")))
// handle_err(parsed.to_datetime()).map(|res| (res.timestamp_micros(), false))
} else {
parsed
.to_naive_datetime_with_offset(0)
.map(|res| res.and_utc().timestamp_micros())
.map_err(|err| ErrorCode::BadArguments(format!("{err}")))
.and_then(|res| match res.and_local_timezone(ctx.func_ctx.tz.tz) {
MappedLocalTime::Single(t) => Ok((t.timestamp_micros(), false)),
_ => Err(ErrorCode::BadArguments(
"The local time can not map to a single unique result".to_string(),
)),
})
// handle_err(parsed.to_naive_datetime_with_offset(0))
// .and_then(|res| match res.and_local_timezone(ctx.func_ctx.tz.tz) {
// MappedLocalTime::Single(t) => Ok((t.timestamp_micros(), false)),
// _ => Err(ErrorCode::BadArguments(
// "The local time can not map to a single unique result".to_string(),
// )),
// })
}
} else if parse_tz {
DateTime::parse_from_str(timestamp, format)
.map(|res| res.with_timezone(&ctx.func_ctx.tz.tz).timestamp_micros())
.map(|res| (res.timestamp_micros(), false))
.map_err(|err| ErrorCode::BadArguments(format!("{}", err)))
} else {
NaiveDateTime::parse_from_str(timestamp, format).map(|res| res.and_utc().timestamp_micros())
};

match res {
Ok(res) => Ok((res, false)),
Err(err) => Err(err),
NaiveDateTime::parse_from_str(timestamp, format)
.map_err(|err| ErrorCode::BadArguments(format!("{}", err)))
.and_then(|res| match res.and_local_timezone(ctx.func_ctx.tz.tz) {
MappedLocalTime::Single(t) => Ok((t.timestamp_micros(), false)),
_ => Err(ErrorCode::BadArguments(
"The local time can not map to a single unique result".to_string(),
)),
})
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1084,10 +1084,8 @@ select to_timestamp('2022年02月04日,8时58分59秒', '');
----
NULL

query T
statement error 1006
select to_timestamp('10000-09-09 01:46:39', '%Y-%m-%d %H:%M:%S');
----
NULL

statement error 1006
select to_timestamp('10000-09-09 01:46:39', '%s-%m-%d %H:%M:%S');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -455,46 +455,70 @@ select to_date('1941-03-15 02:00:00');
statement ok
set parse_datetime_ignore_remainder=1;

statement ok
set timezone='UTC';

query T
select to_timestamp('2022年02月04日,8时58分59秒,时区:+0800', '%Y年%m月%d日,%H时%M分%S秒,时区:%z');
----
2022-02-04 00:58:59.000000

statement ok
set timezone='Asia/Shanghai';

query T
select to_timestamp('2022年02月04日,8时58分59秒', '%Y年%m月%d日,%H');
----
2022-02-04 16:00:00.000000
2022-02-04 08:00:00.000000

query T
statement error 1006
select to_timestamp('2022年02月04日,8时58分59秒', '%Y年%m月%d日,%H%z');

query T
select try_to_timestamp('2022年02月04日,8时58分59秒', '%Y年%m月%d日,%H%z');
----
NULL

query T
select to_timestamp('2022年02月04日,8时58分59秒,时区:+0800', '%Y年%m月%d日,%H时');
----
2022-02-04 16:00:00.000000
2022-02-04 08:00:00.000000

query T
select to_timestamp('2022年02月04日,8时58分59秒,时区:+0900', '%Y年%m月%d日,%H时');
----
2022-02-04 08:00:00.000000

query T
select to_timestamp('2022年02月04日,8时58分59秒,时区:+0800', '%Y年%m月%d日,%H时%M分%S秒,时区:%z');
----
2022-02-04 08:58:59.000000

query T
select to_timestamp('2022年02月04日,8时58分59秒,时区:+0900', '%Y年%m月%d日,%H时%M分%S秒,时区:%z');
----
2022-02-04 07:58:59.000000

statement ok
set timezone='America/Los_Angeles';

query T
select to_timestamp('2022年02月04日,8时58分59秒', '%Y年%m月%d日,%H');
----
2022-02-04 00:00:00.000000
2022-02-04 08:00:00.000000

query T
statement error 1006
select to_timestamp('2022年02月04日,8时58分59秒', '%Y年%m月%d日,%H%z');

query T
select try_to_timestamp('2022年02月04日,8时58分59秒', '%Y年%m月%d日,%H%z');
----
NULL

query T
select to_timestamp('2022年02月04日,8时58分59秒,时区:+0800', '%Y年%m月%d日,%H时');
----
2022-02-04 00:00:00.000000
2022-02-04 08:00:00.000000

query T
select to_timestamp('2022年02月04日,8时58分59秒,时区:+0800', '%Y年%m月%d日,%H时%M分%S秒,时区:%z');
Expand All @@ -509,8 +533,11 @@ select to_timestamp('2022年02月04日,8时58分59秒', '%Y年%m月%d日,%H'
----
2022-02-04 08:00:00.000000

query T
statement error 1006
select to_timestamp('2022年02月04日,8时58分59秒', '%Y年%m月%d日,%H%z');

query T
select try_to_timestamp('2022年02月04日,8时58分59秒', '%Y年%m月%d日,%H%z');
----
NULL

Expand All @@ -529,3 +556,4 @@ unset timezone;

statement ok
unset parse_datetime_ignore_remainder;

0 comments on commit 0a9d259

Please sign in to comment.