// 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. use arrow_arith::numeric::{add, sub}; use arrow_arith::temporal::{DatePart, date_part}; use arrow_array::cast::AsArray; use arrow_array::temporal_conversions::as_datetime_with_timezone; use arrow_array::timezone::Tz; use arrow_array::types::*; use arrow_array::*; use chrono::{DateTime, TimeZone}; #[test] fn test_temporal_array_timestamp_hour_with_timezone_using_chrono_tz() { let a = TimestampSecondArray::from(vec![60 * 60 * 10]).with_timezone("Asia/Kolkata".to_string()); let b = date_part(&a, DatePart::Hour).unwrap(); let b = b.as_primitive::(); assert_eq!(15, b.value(0)); } #[test] fn test_temporal_array_timestamp_hour_with_dst_timezone_using_chrono_tz() { // // 1635577147 converts to 2021-10-30 17:59:07 in time zone Australia/Sydney (AEDT) // The offset (difference to UTC) is +11:00. Note that daylight savings is in effect on 2021-10-30. // When daylight savings is not in effect, Australia/Sydney has an offset difference of +10:00. let a = TimestampMillisecondArray::from(vec![Some(1635577147000)]) .with_timezone("Australia/Sydney".to_string()); let b = date_part(&a, DatePart::Hour).unwrap(); let b = b.as_primitive::(); assert_eq!(17, b.value(0)); } fn test_timestamp_with_timezone_impl(tz_str: &str) { let tz: Tz = tz_str.parse().unwrap(); let transform_array = |x: &dyn Array| -> Vec> { x.as_primitive::() .values() .into_iter() .map(|x| as_datetime_with_timezone::(*x, tz).unwrap()) .collect() }; let values = vec![ tz.with_ymd_and_hms(1970, 1, 28, 23, 0, 0) .unwrap() .naive_utc(), tz.with_ymd_and_hms(1970, 1, 1, 0, 0, 0) .unwrap() .naive_utc(), tz.with_ymd_and_hms(2010, 4, 1, 4, 0, 20) .unwrap() .naive_utc(), tz.with_ymd_and_hms(1960, 1, 30, 4, 23, 20) .unwrap() .naive_utc(), tz.with_ymd_and_hms(2023, 3, 25, 14, 0, 0) .unwrap() .naive_utc(), ] .into_iter() .map(|x| T::make_value(x).unwrap()) .collect(); let a = PrimitiveArray::::new(values, None).with_timezone(tz_str); // IntervalYearMonth let b = IntervalYearMonthArray::from(vec![ IntervalYearMonthType::make_value(0, 1), IntervalYearMonthType::make_value(5, 34), IntervalYearMonthType::make_value(-2, 4), IntervalYearMonthType::make_value(7, -4), IntervalYearMonthType::make_value(0, 1), ]); let r1 = add(&a, &b).unwrap(); assert_eq!( &transform_array(r1.as_ref()), &[ tz.with_ymd_and_hms(1970, 2, 28, 23, 0, 0).unwrap(), tz.with_ymd_and_hms(1977, 11, 1, 0, 0, 0).unwrap(), tz.with_ymd_and_hms(2008, 8, 1, 4, 0, 20).unwrap(), tz.with_ymd_and_hms(1966, 9, 30, 4, 23, 20).unwrap(), tz.with_ymd_and_hms(2023, 4, 25, 14, 0, 0).unwrap(), ] ); let r2 = sub(&r1, &b).unwrap(); assert_eq!(r2.as_ref(), &a); // IntervalDayTime let b = IntervalDayTimeArray::from(vec![ IntervalDayTimeType::make_value(0, 0), IntervalDayTimeType::make_value(5, 454000), IntervalDayTimeType::make_value(-34, 0), IntervalDayTimeType::make_value(7, -4000), IntervalDayTimeType::make_value(1, 0), ]); let r3 = add(&a, &b).unwrap(); assert_eq!( &transform_array(r3.as_ref()), &[ tz.with_ymd_and_hms(1970, 1, 28, 23, 0, 0).unwrap(), tz.with_ymd_and_hms(1970, 1, 6, 0, 7, 34).unwrap(), tz.with_ymd_and_hms(2010, 2, 26, 4, 0, 20).unwrap(), tz.with_ymd_and_hms(1960, 2, 6, 4, 23, 16).unwrap(), tz.with_ymd_and_hms(2023, 3, 26, 14, 0, 0).unwrap(), ] ); let r4 = sub(&r3, &b).unwrap(); assert_eq!(r4.as_ref(), &a); // IntervalMonthDayNano let b = IntervalMonthDayNanoArray::from(vec![ IntervalMonthDayNanoType::make_value(1, 0, 0), IntervalMonthDayNanoType::make_value(344, 34, -43_000_000_000), IntervalMonthDayNanoType::make_value(-593, -33, 13_000_000_000), IntervalMonthDayNanoType::make_value(5, 2, 493_000_000_000), IntervalMonthDayNanoType::make_value(1, 0, 0), ]); let r5 = add(&a, &b).unwrap(); assert_eq!( &transform_array(r5.as_ref()), &[ tz.with_ymd_and_hms(1970, 2, 28, 23, 0, 0).unwrap(), tz.with_ymd_and_hms(1998, 10, 4, 23, 59, 17).unwrap(), tz.with_ymd_and_hms(1960, 9, 29, 4, 0, 33).unwrap(), tz.with_ymd_and_hms(1960, 7, 2, 4, 31, 33).unwrap(), tz.with_ymd_and_hms(2023, 4, 25, 14, 0, 0).unwrap(), ] ); let r6 = sub(&r5, &b).unwrap(); assert_eq!( &transform_array(r6.as_ref()), &[ tz.with_ymd_and_hms(1970, 1, 28, 23, 0, 0).unwrap(), tz.with_ymd_and_hms(1970, 1, 2, 0, 0, 0).unwrap(), tz.with_ymd_and_hms(2010, 4, 2, 4, 0, 20).unwrap(), tz.with_ymd_and_hms(1960, 1, 31, 4, 23, 20).unwrap(), tz.with_ymd_and_hms(2023, 3, 25, 14, 0, 0).unwrap(), ] ); } #[test] fn test_timestamp_with_offset_timezone() { let timezones = ["+00:00", "+01:00", "-01:00", "+03:30"]; for timezone in timezones { test_timestamp_with_timezone_impl::(timezone); test_timestamp_with_timezone_impl::(timezone); test_timestamp_with_timezone_impl::(timezone); test_timestamp_with_timezone_impl::(timezone); } } #[test] fn test_timestamp_with_timezone() { let timezones = [ "Europe/Paris", "Europe/London", "Africa/Bamako", "America/Dominica", "Asia/Seoul", "Asia/Shanghai", ]; for timezone in timezones { test_timestamp_with_timezone_impl::(timezone); test_timestamp_with_timezone_impl::(timezone); test_timestamp_with_timezone_impl::(timezone); test_timestamp_with_timezone_impl::(timezone); } }