Skip to content

Commit c7af4b1

Browse files
Date can cast to tz-aware timestamp
1 parent a0c3186 commit c7af4b1

File tree

1 file changed

+76
-19
lines changed

1 file changed

+76
-19
lines changed

arrow-cast/src/cast/mod.rs

+76-19
Original file line numberDiff line numberDiff line change
@@ -265,8 +265,8 @@ pub fn can_cast_types(from_type: &DataType, to_type: &DataType) -> bool {
265265
}
266266
(Timestamp(_, _), _) if to_type.is_numeric() => true,
267267
(_, Timestamp(_, _)) if from_type.is_numeric() => true,
268-
(Date64, Timestamp(_, None)) => true,
269-
(Date32, Timestamp(_, None)) => true,
268+
(Date64, Timestamp(_, _)) => true,
269+
(Date32, Timestamp(_, _)) => true,
270270
(
271271
Timestamp(_, _),
272272
Timestamp(_, _)
@@ -1806,43 +1806,54 @@ pub fn cast_with_options(
18061806
})?,
18071807
))
18081808
}
1809-
(Date64, Timestamp(TimeUnit::Second, None)) => Ok(Arc::new(
1809+
(Date64, Timestamp(TimeUnit::Second, to_tz)) => Ok(Arc::new(
18101810
array
18111811
.as_primitive::<Date64Type>()
1812-
.unary::<_, TimestampSecondType>(|x| x / MILLISECONDS),
1812+
.unary::<_, TimestampSecondType>(|x| x / MILLISECONDS)
1813+
.with_timezone_opt(to_tz.clone()),
18131814
)),
1814-
(Date64, Timestamp(TimeUnit::Millisecond, None)) => {
1815-
cast_reinterpret_arrays::<Date64Type, TimestampMillisecondType>(array)
1816-
}
1817-
(Date64, Timestamp(TimeUnit::Microsecond, None)) => Ok(Arc::new(
1815+
(Date64, Timestamp(TimeUnit::Millisecond, to_tz)) => Ok(Arc::new(
1816+
array
1817+
.as_primitive::<Date64Type>()
1818+
.reinterpret_cast::<TimestampMillisecondType>()
1819+
.with_timezone_opt(to_tz.clone()),
1820+
)),
1821+
1822+
(Date64, Timestamp(TimeUnit::Microsecond, to_tz)) => Ok(Arc::new(
18181823
array
18191824
.as_primitive::<Date64Type>()
1820-
.unary::<_, TimestampMicrosecondType>(|x| x * (MICROSECONDS / MILLISECONDS)),
1825+
.unary::<_, TimestampMicrosecondType>(|x| x * (MICROSECONDS / MILLISECONDS))
1826+
.with_timezone_opt(to_tz.clone()),
18211827
)),
1822-
(Date64, Timestamp(TimeUnit::Nanosecond, None)) => Ok(Arc::new(
1828+
(Date64, Timestamp(TimeUnit::Nanosecond, to_tz)) => Ok(Arc::new(
18231829
array
18241830
.as_primitive::<Date64Type>()
1825-
.unary::<_, TimestampNanosecondType>(|x| x * (NANOSECONDS / MILLISECONDS)),
1831+
.unary::<_, TimestampNanosecondType>(|x| x * (NANOSECONDS / MILLISECONDS))
1832+
.with_timezone_opt(to_tz.clone()),
18261833
)),
1827-
(Date32, Timestamp(TimeUnit::Second, None)) => Ok(Arc::new(
1834+
(Date32, Timestamp(TimeUnit::Second, to_tz)) => Ok(Arc::new(
18281835
array
18291836
.as_primitive::<Date32Type>()
1830-
.unary::<_, TimestampSecondType>(|x| (x as i64) * SECONDS_IN_DAY),
1837+
.unary::<_, TimestampSecondType>(|x| (x as i64) * SECONDS_IN_DAY)
1838+
.with_timezone_opt(to_tz.clone()),
18311839
)),
1832-
(Date32, Timestamp(TimeUnit::Millisecond, None)) => Ok(Arc::new(
1840+
(Date32, Timestamp(TimeUnit::Millisecond, to_tz)) => Ok(Arc::new(
18331841
array
18341842
.as_primitive::<Date32Type>()
1835-
.unary::<_, TimestampMillisecondType>(|x| (x as i64) * MILLISECONDS_IN_DAY),
1843+
.unary::<_, TimestampMillisecondType>(|x| (x as i64) * MILLISECONDS_IN_DAY)
1844+
.with_timezone_opt(to_tz.clone()),
18361845
)),
1837-
(Date32, Timestamp(TimeUnit::Microsecond, None)) => Ok(Arc::new(
1846+
(Date32, Timestamp(TimeUnit::Microsecond, to_tz)) => Ok(Arc::new(
18381847
array
18391848
.as_primitive::<Date32Type>()
1840-
.unary::<_, TimestampMicrosecondType>(|x| (x as i64) * MICROSECONDS_IN_DAY),
1849+
.unary::<_, TimestampMicrosecondType>(|x| (x as i64) * MICROSECONDS_IN_DAY)
1850+
.with_timezone_opt(to_tz.clone()),
18411851
)),
1842-
(Date32, Timestamp(TimeUnit::Nanosecond, None)) => Ok(Arc::new(
1852+
(Date32, Timestamp(TimeUnit::Nanosecond, to_tz)) => Ok(Arc::new(
18431853
array
18441854
.as_primitive::<Date32Type>()
1845-
.unary::<_, TimestampNanosecondType>(|x| (x as i64) * NANOSECONDS_IN_DAY),
1855+
.unary::<_, TimestampNanosecondType>(|x| (x as i64) * NANOSECONDS_IN_DAY)
1856+
.with_timezone_opt(to_tz.clone()),
18461857
)),
18471858

18481859
(_, Duration(unit)) if from_type.is_numeric() => {
@@ -5217,6 +5228,52 @@ mod tests {
52175228
}};
52185229
}
52195230

5231+
#[test]
5232+
fn test_cast_date64_to_timestamp_with_timezone() {
5233+
let array = Date64Array::from(vec![Some(864000000005), Some(1545696000001), None]);
5234+
let tz = "+0545"; // UTC + 0545 is Asia/Kathmandu
5235+
let b = cast(
5236+
&array,
5237+
&DataType::Timestamp(TimeUnit::Millisecond, Some(tz.into())),
5238+
)
5239+
.unwrap();
5240+
5241+
let c = b.as_primitive::<TimestampMillisecondType>();
5242+
assert_eq!(864000000005, c.value(0));
5243+
assert_eq!(1545696000001, c.value(1));
5244+
assert!(c.is_null(2));
5245+
5246+
let expected = vec![
5247+
Some("1997-05-19 05:45:00.005000"),
5248+
Some("2018-12-25 05:45:00.001000"),
5249+
None,
5250+
];
5251+
5252+
let ts_format = "%Y-%m-%d %H:%M:%S%.6f";
5253+
let cast_options = CastOptions {
5254+
safe: true,
5255+
format_options: FormatOptions::default()
5256+
.with_timestamp_format(Some(ts_format))
5257+
.with_timestamp_tz_format(Some(ts_format)),
5258+
};
5259+
5260+
assert_cast_timestamp_to_string!(
5261+
c,
5262+
DataType::Utf8View,
5263+
StringViewArray,
5264+
cast_options,
5265+
expected
5266+
);
5267+
assert_cast_timestamp_to_string!(c, DataType::Utf8, StringArray, cast_options, expected);
5268+
assert_cast_timestamp_to_string!(
5269+
c,
5270+
DataType::LargeUtf8,
5271+
LargeStringArray,
5272+
cast_options,
5273+
expected
5274+
);
5275+
}
5276+
52205277
#[test]
52215278
fn test_cast_timestamp_to_strings() {
52225279
// "2018-12-25T00:00:02.001", "1997-05-19T00:00:03.005", None

0 commit comments

Comments
 (0)