datafusion_comet_spark_expr/
timezone.rs1use arrow_schema::ArrowError;
20use chrono::{
21 format::{parse, Parsed, StrftimeItems},
22 offset::TimeZone,
23 FixedOffset, LocalResult, NaiveDate, NaiveDateTime, Offset,
24};
25use std::str::FromStr;
26
27fn parse_fixed_offset(tz: &str) -> Result<FixedOffset, ArrowError> {
29 let mut parsed = Parsed::new();
30
31 if let Ok(fixed_offset) =
32 parse(&mut parsed, tz, StrftimeItems::new("%:z")).and_then(|_| parsed.to_fixed_offset())
33 {
34 return Ok(fixed_offset);
35 }
36
37 if let Ok(fixed_offset) =
38 parse(&mut parsed, tz, StrftimeItems::new("%#z")).and_then(|_| parsed.to_fixed_offset())
39 {
40 return Ok(fixed_offset);
41 }
42
43 Err(ArrowError::ParseError(format!(
44 "Invalid timezone \"{}\": Expected format [+-]XX:XX, [+-]XX, or [+-]XXXX",
45 tz
46 )))
47}
48
49#[derive(Debug, Copy, Clone)]
51pub struct TzOffset {
52 tz: Tz,
53 offset: FixedOffset,
54}
55
56impl std::fmt::Display for TzOffset {
57 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58 self.offset.fmt(f)
59 }
60}
61
62impl Offset for TzOffset {
63 fn fix(&self) -> FixedOffset {
64 self.offset
65 }
66}
67
68#[derive(Debug, Copy, Clone)]
70pub struct Tz(TzInner);
71
72#[derive(Debug, Copy, Clone)]
73enum TzInner {
74 Timezone(chrono_tz::Tz),
75 Offset(FixedOffset),
76}
77
78impl FromStr for Tz {
79 type Err = ArrowError;
80
81 fn from_str(tz: &str) -> Result<Self, Self::Err> {
82 if tz.starts_with('+') || tz.starts_with('-') {
83 Ok(Self(TzInner::Offset(parse_fixed_offset(tz)?)))
84 } else {
85 Ok(Self(TzInner::Timezone(tz.parse().map_err(|e| {
86 ArrowError::ParseError(format!("Invalid timezone \"{}\": {}", tz, e))
87 })?)))
88 }
89 }
90}
91
92macro_rules! tz {
93 ($s:ident, $tz:ident, $b:block) => {
94 match $s.0 {
95 TzInner::Timezone($tz) => $b,
96 TzInner::Offset($tz) => $b,
97 }
98 };
99}
100
101impl TimeZone for Tz {
102 type Offset = TzOffset;
103
104 fn from_offset(offset: &Self::Offset) -> Self {
105 offset.tz
106 }
107
108 fn offset_from_local_date(&self, local: &NaiveDate) -> LocalResult<Self::Offset> {
109 tz!(self, tz, {
110 tz.offset_from_local_date(local).map(|x| TzOffset {
111 tz: *self,
112 offset: x.fix(),
113 })
114 })
115 }
116
117 fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<Self::Offset> {
118 tz!(self, tz, {
119 tz.offset_from_local_datetime(local).map(|x| TzOffset {
120 tz: *self,
121 offset: x.fix(),
122 })
123 })
124 }
125
126 fn offset_from_utc_date(&self, utc: &NaiveDate) -> Self::Offset {
127 tz!(self, tz, {
128 TzOffset {
129 tz: *self,
130 offset: tz.offset_from_utc_date(utc).fix(),
131 }
132 })
133 }
134
135 fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> Self::Offset {
136 tz!(self, tz, {
137 TzOffset {
138 tz: *self,
139 offset: tz.offset_from_utc_datetime(utc).fix(),
140 }
141 })
142 }
143}