Skip to content

Commit a2f5478

Browse files
committed
expr: convert a few more date functions
Signed-off-by: Petros Angelatos <[email protected]>
1 parent 1476f43 commit a2f5478

File tree

3 files changed

+195
-98
lines changed

3 files changed

+195
-98
lines changed

src/expr/src/scalar/func.rs

Lines changed: 32 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1817,43 +1817,11 @@ where
18171817
{
18181818
let units = a.unwrap_str();
18191819
match units.parse() {
1820-
Ok(units) => date_trunc_inner(units, ts),
1820+
Ok(units) => Ok(date_trunc_inner(units, ts)?.into()),
18211821
Err(_) => Err(EvalError::UnknownUnits(units.to_owned())),
18221822
}
18231823
}
18241824

1825-
fn date_trunc_inner<'a, T>(units: DateTimeUnits, ts: T) -> Result<Datum<'a>, EvalError>
1826-
where
1827-
T: TimestampLike,
1828-
{
1829-
match units {
1830-
DateTimeUnits::Millennium => Ok(ts.truncate_millennium().into()),
1831-
DateTimeUnits::Century => Ok(ts.truncate_century().into()),
1832-
DateTimeUnits::Decade => Ok(ts.truncate_decade().into()),
1833-
DateTimeUnits::Year => Ok(ts.truncate_year().into()),
1834-
DateTimeUnits::Quarter => Ok(ts.truncate_quarter().into()),
1835-
DateTimeUnits::Week => Ok(ts.truncate_week()?.into()),
1836-
DateTimeUnits::Day => Ok(ts.truncate_day().into()),
1837-
DateTimeUnits::Hour => Ok(ts.truncate_hour().into()),
1838-
DateTimeUnits::Minute => Ok(ts.truncate_minute().into()),
1839-
DateTimeUnits::Second => Ok(ts.truncate_second().into()),
1840-
DateTimeUnits::Month => Ok(ts.truncate_month().into()),
1841-
DateTimeUnits::Milliseconds => Ok(ts.truncate_milliseconds().into()),
1842-
DateTimeUnits::Microseconds => Ok(ts.truncate_microseconds().into()),
1843-
DateTimeUnits::Epoch
1844-
| DateTimeUnits::Timezone
1845-
| DateTimeUnits::TimezoneHour
1846-
| DateTimeUnits::TimezoneMinute
1847-
| DateTimeUnits::DayOfWeek
1848-
| DateTimeUnits::DayOfYear
1849-
| DateTimeUnits::IsoDayOfWeek
1850-
| DateTimeUnits::IsoDayOfYear => Err(EvalError::Unsupported {
1851-
feature: format!("'{}' timestamp units", units),
1852-
issue_no: None,
1853-
}),
1854-
}
1855-
}
1856-
18571825
fn date_trunc_interval<'a>(a: Datum, b: Datum) -> Result<Datum<'a>, EvalError> {
18581826
let mut interval = b.unwrap_interval();
18591827
let units = a.unwrap_str();
@@ -1883,40 +1851,6 @@ fn timezone_time(tz: Timezone, t: NaiveTime, wall_time: &NaiveDateTime) -> Datum
18831851
(t + offset).into()
18841852
}
18851853

1886-
/// Converts the timestamp `dt`, which is assumed to be in the time of the timezone `tz` to a timestamptz in UTC.
1887-
/// This operation is fallible because certain timestamps at timezones that observe DST are simply impossible or
1888-
/// ambiguous. In case of ambiguity (when a hour repeats) we will prefer the latest variant, and when an hour is
1889-
/// impossible, we will attempt to fix it by advancing it. For example, `EST` and `2020-11-11T12:39:14` would return
1890-
/// `2020-11-11T17:39:14Z`. A DST observing timezone like `America/New_York` would cause the following DST anomalies:
1891-
/// `2020-11-01T00:59:59` -> `2020-11-01T04:59:59Z` and `2020-11-01T01:00:00` -> `2020-11-01T06:00:00Z`
1892-
/// `2020-03-08T02:59:59` -> `2020-03-08T07:59:59Z` and `2020-03-08T03:00:00` -> `2020-03-08T07:00:00Z`
1893-
fn timezone_timestamp(tz: Timezone, mut dt: NaiveDateTime) -> Result<Datum<'static>, EvalError> {
1894-
let offset = match tz {
1895-
Timezone::FixedOffset(offset) => offset,
1896-
Timezone::Tz(tz) => match tz.offset_from_local_datetime(&dt).latest() {
1897-
Some(offset) => offset.fix(),
1898-
None => {
1899-
dt += Duration::hours(1);
1900-
tz.offset_from_local_datetime(&dt)
1901-
.latest()
1902-
.ok_or(EvalError::InvalidTimezoneConversion)?
1903-
.fix()
1904-
}
1905-
},
1906-
};
1907-
Ok(DateTime::from_utc(dt - offset, Utc).into())
1908-
}
1909-
1910-
/// Converts the UTC timestamptz `utc` to the local timestamp of the timezone `tz`.
1911-
/// For example, `EST` and `2020-11-11T17:39:14Z` would return `2020-11-11T12:39:14`.
1912-
fn timezone_timestamptz(tz: Timezone, utc: DateTime<Utc>) -> Datum<'static> {
1913-
let offset = match tz {
1914-
Timezone::FixedOffset(offset) => offset,
1915-
Timezone::Tz(tz) => tz.offset_from_utc_datetime(&utc.naive_utc()).fix(),
1916-
};
1917-
(utc.naive_utc() + offset).into()
1918-
}
1919-
19201854
/// Converts the time datum `b`, which is assumed to be in UTC, to the timezone that the interval datum `a` is assumed
19211855
/// to represent. The interval is not allowed to hold months, but there are no limits on the amount of seconds.
19221856
/// The interval acts like a `chrono::FixedOffset`, without the `-86,400 < x < 86,400` limitation.
@@ -2274,11 +2208,11 @@ impl BinaryFunc {
22742208
}
22752209
BinaryFunc::TimezoneTimestamp => {
22762210
eager!(|a: Datum, b: Datum| parse_timezone(a.unwrap_str())
2277-
.and_then(|tz| timezone_timestamp(tz, b.unwrap_timestamp())))
2211+
.and_then(|tz| Ok(timezone_timestamp(tz, b.unwrap_timestamp())?.into())))
22782212
}
22792213
BinaryFunc::TimezoneTimestampTz => {
22802214
eager!(|a: Datum, b: Datum| parse_timezone(a.unwrap_str())
2281-
.map(|tz| timezone_timestamptz(tz, b.unwrap_timestamptz())))
2215+
.map(|tz| timezone_timestamptz(tz, b.unwrap_timestamptz()).into()))
22822216
}
22832217
BinaryFunc::TimezoneTime { wall_time } => {
22842218
eager!(
@@ -3155,14 +3089,14 @@ pub enum UnaryFunc {
31553089
ExtractTimestampTz(ExtractTimestampTz),
31563090
DatePartTimestamp(DatePartTimestamp),
31573091
DatePartTimestampTz(DatePartTimestampTz),
3092+
DateTruncTimestamp(DateTruncTimestamp),
3093+
DateTruncTimestampTz(DateTruncTimestampTz),
3094+
TimezoneTimestamp(TimezoneTimestamp),
3095+
TimezoneTimestampTz(TimezoneTimestampTz),
31583096

31593097
ExtractDate(DateTimeUnits),
31603098
ExtractTime(DateTimeUnits),
31613099
DatePartTime(DateTimeUnits),
3162-
DateTruncTimestamp(DateTimeUnits),
3163-
DateTruncTimestampTz(DateTimeUnits),
3164-
TimezoneTimestamp(Timezone),
3165-
TimezoneTimestampTz(Timezone),
31663100
TimezoneTime {
31673101
tz: Timezone,
31683102
wall_time: NaiveDateTime,
@@ -3410,7 +3344,11 @@ derive_unary!(
34103344
ExtractTimestamp,
34113345
ExtractTimestampTz,
34123346
DatePartTimestamp,
3413-
DatePartTimestampTz
3347+
DatePartTimestampTz,
3348+
DateTruncTimestamp,
3349+
DateTruncTimestampTz,
3350+
TimezoneTimestamp,
3351+
TimezoneTimestampTz
34143352
);
34153353

34163354
impl UnaryFunc {
@@ -3621,6 +3559,10 @@ impl UnaryFunc {
36213559
| ExtractTimestampTz(_)
36223560
| DatePartTimestamp(_)
36233561
| DatePartTimestampTz(_)
3562+
| DateTruncTimestamp(_)
3563+
| DateTruncTimestampTz(_)
3564+
| TimezoneTimestamp(_)
3565+
| TimezoneTimestampTz(_)
36243566
| Chr(_) => unreachable!(),
36253567
CastRecordToString { ty }
36263568
| CastArrayToString { ty }
@@ -3636,10 +3578,6 @@ impl UnaryFunc {
36363578
ExtractTime(units) => date_part_time_inner::<Numeric>(*units, a),
36373579
ExtractDate(units) => extract_date_inner(*units, a),
36383580
DatePartTime(units) => date_part_time_inner::<f64>(*units, a),
3639-
DateTruncTimestamp(units) => date_trunc_inner(*units, a.unwrap_timestamp()),
3640-
DateTruncTimestampTz(units) => date_trunc_inner(*units, a.unwrap_timestamptz()),
3641-
TimezoneTimestamp(tz) => timezone_timestamp(*tz, a.unwrap_timestamp()),
3642-
TimezoneTimestampTz(tz) => Ok(timezone_timestamptz(*tz, a.unwrap_timestamptz())),
36433581
TimezoneTime { tz, wall_time } => Ok(timezone_time(*tz, a.unwrap_time(), wall_time)),
36443582
RecordGet(i) => Ok(record_get(a, *i)),
36453583
ListLength => list_length(a),
@@ -3852,6 +3790,10 @@ impl UnaryFunc {
38523790
| ExtractTimestampTz(_)
38533791
| DatePartTimestamp(_)
38543792
| DatePartTimestampTz(_)
3793+
| DateTruncTimestamp(_)
3794+
| DateTruncTimestampTz(_)
3795+
| TimezoneTimestamp(_)
3796+
| TimezoneTimestampTz(_)
38553797
| Chr(_) => unreachable!(),
38563798

38573799
CastRecordToString { .. }
@@ -3862,10 +3804,6 @@ impl UnaryFunc {
38623804

38633805
TimezoneTime { .. } => ScalarType::Time.nullable(nullable),
38643806

3865-
TimezoneTimestampTz(_) => ScalarType::Timestamp.nullable(nullable),
3866-
3867-
TimezoneTimestamp(_) => ScalarType::TimestampTz.nullable(nullable),
3868-
38693807
CastRecord1ToRecord2 { return_ty, .. } => {
38703808
return_ty.without_modifiers().nullable(nullable)
38713809
}
@@ -3878,9 +3816,6 @@ impl UnaryFunc {
38783816

38793817
DatePartTime(_) => ScalarType::Float64.nullable(nullable),
38803818

3881-
DateTruncTimestamp(_) => ScalarType::Timestamp.nullable(nullable),
3882-
DateTruncTimestampTz(_) => ScalarType::TimestampTz.nullable(nullable),
3883-
38843819
RecordGet(i) => match input_type.scalar_type {
38853820
ScalarType::Record { mut fields, .. } => {
38863821
let (_name, mut ty) = fields.swap_remove(*i);
@@ -4106,6 +4041,10 @@ impl UnaryFunc {
41064041
| ExtractTimestampTz(_)
41074042
| DatePartTimestamp(_)
41084043
| DatePartTimestampTz(_)
4044+
| DateTruncTimestamp(_)
4045+
| DateTruncTimestampTz(_)
4046+
| TimezoneTimestamp(_)
4047+
| TimezoneTimestampTz(_)
41094048
| Chr(_) => unreachable!(),
41104049
// Return null if the inner field is null
41114050
RecordGet(_) => true,
@@ -4116,13 +4055,10 @@ impl UnaryFunc {
41164055
| CastMapToString { .. }
41174056
| CastInt2VectorToString => false,
41184057
TimezoneTime { .. } => false,
4119-
TimezoneTimestampTz(_) => false,
4120-
TimezoneTimestamp(_) => false,
41214058
CastList1ToList2 { .. } | CastRecord1ToRecord2 { .. } => false,
41224059
ListLength | MapLength => false,
41234060
ExtractTime(_) | ExtractDate(_) => false,
41244061
DatePartTime(_) => false,
4125-
DateTruncTimestamp(_) | DateTruncTimestampTz(_) => false,
41264062
RescaleNumeric(_) => false,
41274063
}
41284064
}
@@ -4230,6 +4166,10 @@ impl UnaryFunc {
42304166
| ExtractTimestampTz(_)
42314167
| DatePartTimestamp(_)
42324168
| DatePartTimestampTz(_)
4169+
| DateTruncTimestamp(_)
4170+
| DateTruncTimestampTz(_)
4171+
| TimezoneTimestamp(_)
4172+
| TimezoneTimestampTz(_)
42334173
| CastVarCharToString(_) => unreachable!(),
42344174
_ => false,
42354175
}
@@ -4432,6 +4372,10 @@ impl UnaryFunc {
44324372
| ExtractTimestampTz(_)
44334373
| DatePartTimestamp(_)
44344374
| DatePartTimestampTz(_)
4375+
| DateTruncTimestamp(_)
4376+
| DateTruncTimestampTz(_)
4377+
| TimezoneTimestamp(_)
4378+
| TimezoneTimestampTz(_)
44354379
| Chr(_) => unreachable!(),
44364380
CastRecordToString { .. } => f.write_str("recordtostr"),
44374381
CastRecord1ToRecord2 { .. } => f.write_str("record1torecord2"),
@@ -4443,10 +4387,6 @@ impl UnaryFunc {
44434387
ExtractTime(units) => write!(f, "extract_{}_t", units),
44444388
ExtractDate(units) => write!(f, "extract_{}_d", units),
44454389
DatePartTime(units) => write!(f, "date_part_{}_t", units),
4446-
DateTruncTimestamp(units) => write!(f, "date_trunc_{}_ts", units),
4447-
DateTruncTimestampTz(units) => write!(f, "date_trunc_{}_tstz", units),
4448-
TimezoneTimestamp(tz) => write!(f, "timezone_{}_ts", tz),
4449-
TimezoneTimestampTz(tz) => write!(f, "timezone_{}_tstz", tz),
44504390
TimezoneTime { tz, .. } => write!(f, "timezone_{}_t", tz),
44514391
RecordGet(i) => write!(f, "record_get[{}]", i),
44524392
ListLength => f.write_str("list_length"),

0 commit comments

Comments
 (0)