-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(rust, python): respect time_zone in lazy date_range #8591
Changes from 6 commits
1145bd7
9fdf7a7
b603479
f340971
02f292a
616c56d
e169e23
4a4a143
b692a5c
6124f9e
f7aec53
0685215
c340635
c254f0f
9da2bbc
94a4875
c59fff1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -59,7 +59,38 @@ impl FunctionExpr { | |
} | ||
#[cfg(feature = "timezones")] | ||
TzLocalize(tz) => return mapper.map_datetime_dtype_timezone(Some(tz)), | ||
DateRange { .. } => return mapper.map_to_supertype(), | ||
DateRange { | ||
every: _, | ||
closed: _, | ||
tz, | ||
} => { | ||
let mut ret = mapper.map_to_supertype()?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we hoist this into a function. That keeps the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yup! by doing that, I realised that I hadn't quite done it correctly, and that it was wrong for (lazy) time_range too #9036 +1 for smaller functions and leaner logic, thanks! |
||
let ret_dtype = match (&ret.dtype, tz) { | ||
#[cfg(feature = "timezones")] | ||
(DataType::Datetime(tu, Some(field_tz)), Some(tz)) => { | ||
if field_tz != tz { | ||
polars_bail!(ComputeError: format!("Given time_zone is different from that of timezone aware datetimes. \ | ||
Given: '{}', got: '{}'.", tz, field_tz)) | ||
} | ||
DataType::Datetime(*tu, Some(tz.to_string())) | ||
} | ||
#[cfg(feature = "timezones")] | ||
(DataType::Datetime(tu, Some(tz)), _) => { | ||
DataType::Datetime(*tu, Some(tz.to_string())) | ||
} | ||
#[cfg(feature = "timezones")] | ||
(DataType::Datetime(tu, _), Some(tz)) => { | ||
DataType::Datetime(*tu, Some(tz.to_string())) | ||
} | ||
(DataType::Datetime(tu, _), _) => DataType::Datetime(*tu, None), | ||
(DataType::Date, _) => DataType::Date, | ||
(dtype, _) => { | ||
polars_bail!(ComputeError: "expected Date or Datetime, got {}", dtype) | ||
} | ||
}; | ||
ret.coerce(ret_dtype); | ||
return mapper.map_to_supertype(); | ||
} | ||
TimeRange { .. } => DataType::Time, | ||
Combine(tu) => match mapper.with_same_dtype().unwrap().dtype { | ||
DataType::Datetime(_, tz) => DataType::Datetime(*tu, tz), | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -82,7 +82,7 @@ pub(super) fn temporal_range_dispatch( | |
name: &str, | ||
every: Duration, | ||
closed: ClosedWindow, | ||
_tz: Option<TimeZone>, // todo: respect _tz: https://github.com/pola-rs/polars/issues/8512 | ||
tz: Option<TimeZone>, | ||
) -> PolarsResult<Series> { | ||
let start = &s[0]; | ||
let stop = &s[1]; | ||
|
@@ -93,21 +93,45 @@ pub(super) fn temporal_range_dispatch( | |
); | ||
const TO_MS: i64 = SECONDS_IN_DAY * 1000; | ||
|
||
let rng_start = start.to_physical_repr(); | ||
let rng_stop = stop.to_physical_repr(); | ||
let dtype = start.dtype(); | ||
let start_dtype = start.dtype(); | ||
|
||
let mut start = rng_start.cast(&DataType::Int64)?; | ||
let mut stop = rng_stop.cast(&DataType::Int64)?; | ||
// Note: `start` and `stop` have already been cast to their supertype, | ||
// so only `start`'s dtype needs to be matched against. | ||
let (mut start, mut stop) = match start_dtype { | ||
#[cfg(feature = "timezones")] | ||
DataType::Datetime(_, Some(_)) => ( | ||
start | ||
.datetime() | ||
.unwrap() | ||
.replace_time_zone(None, None)? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if |
||
.into_series() | ||
.to_physical_repr() | ||
.cast(&DataType::Int64)?, | ||
stop.datetime() | ||
.unwrap() | ||
.replace_time_zone(None, None)? | ||
.into_series() | ||
.to_physical_repr() | ||
.cast(&DataType::Int64)?, | ||
), | ||
_ => ( | ||
start.to_physical_repr().cast(&DataType::Int64)?, | ||
stop.to_physical_repr().cast(&DataType::Int64)?, | ||
), | ||
}; | ||
|
||
let (tu, tz) = match dtype { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the output dtype isn't necessarily Then,
|
||
DataType::Date => { | ||
let dtype = match (start_dtype, tz) { | ||
(DataType::Date, _) => { | ||
start = &start * TO_MS; | ||
stop = &stop * TO_MS; | ||
(TimeUnit::Milliseconds, None) | ||
DataType::Date | ||
} | ||
DataType::Datetime(tu, tz) => (*tu, tz.as_ref()), | ||
DataType::Time => (TimeUnit::Nanoseconds, None), | ||
#[cfg(feature = "timezones")] | ||
(DataType::Datetime(tu, _), Some(tz)) => DataType::Datetime(*tu, Some(tz)), | ||
#[cfg(feature = "timezones")] | ||
(DataType::Datetime(tu, Some(tz)), None) => DataType::Datetime(*tu, Some(tz.to_string())), | ||
(DataType::Datetime(tu, _), _) => DataType::Datetime(*tu, None), | ||
(DataType::Time, _) => DataType::Time, | ||
_ => unimplemented!(), | ||
}; | ||
let start = start.i64().unwrap(); | ||
|
@@ -124,7 +148,15 @@ pub(super) fn temporal_range_dispatch( | |
for (start, stop) in start.into_iter().zip(stop.into_iter()) { | ||
match (start, stop) { | ||
(Some(start), Some(stop)) => { | ||
let rng = date_range_impl("", start, stop, every, closed, tu, tz)?; | ||
let rng = date_range_impl( | ||
"", | ||
start, | ||
stop, | ||
every, | ||
closed, | ||
TimeUnit::Milliseconds, | ||
None, | ||
)?; | ||
let rng = rng.cast(&DataType::Date).unwrap(); | ||
let rng = rng.to_physical_repr(); | ||
let rng = rng.i32().unwrap(); | ||
|
@@ -135,7 +167,25 @@ pub(super) fn temporal_range_dispatch( | |
} | ||
builder.finish().into_series() | ||
} | ||
DataType::Datetime(_, _) | DataType::Time => { | ||
DataType::Datetime(tu, ref tz) => { | ||
Comment on lines
-138
to
+170
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. separating the |
||
let mut builder = ListPrimitiveChunkedBuilder::<Int64Type>::new( | ||
name, | ||
start.len(), | ||
start.len() * 5, | ||
DataType::Int64, | ||
); | ||
for (start, stop) in start.into_iter().zip(stop.into_iter()) { | ||
match (start, stop) { | ||
(Some(start), Some(stop)) => { | ||
let rng = date_range_impl("", start, stop, every, closed, tu, tz.as_ref())?; | ||
builder.append_slice(rng.cont_slice().unwrap()) | ||
} | ||
_ => builder.append_null(), | ||
} | ||
} | ||
builder.finish().into_series() | ||
} | ||
DataType::Time => { | ||
let mut builder = ListPrimitiveChunkedBuilder::<Int64Type>::new( | ||
name, | ||
start.len(), | ||
|
@@ -145,7 +195,15 @@ pub(super) fn temporal_range_dispatch( | |
for (start, stop) in start.into_iter().zip(stop.into_iter()) { | ||
match (start, stop) { | ||
(Some(start), Some(stop)) => { | ||
let rng = date_range_impl("", start, stop, every, closed, tu, tz)?; | ||
let rng = date_range_impl( | ||
"", | ||
start, | ||
stop, | ||
every, | ||
closed, | ||
TimeUnit::Nanoseconds, | ||
None, | ||
)?; | ||
builder.append_slice(rng.cont_slice().unwrap()) | ||
} | ||
_ => builder.append_null(), | ||
|
@@ -156,6 +214,6 @@ pub(super) fn temporal_range_dispatch( | |
_ => unimplemented!(), | ||
}; | ||
|
||
let to_type = DataType::List(Box::new(dtype.clone())); | ||
let to_type = DataType::List(Box::new(dtype)); | ||
list.cast(&to_type) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the output dtype may change according to
tz
, so need to do some extra computation hereThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, can you add that as comment?