Skip to content

Commit c396d63

Browse files
committed
feat: add configurable UDF for now() function with timezone support
1 parent b81ebf6 commit c396d63

File tree

3 files changed

+44
-1
lines changed

3 files changed

+44
-1
lines changed

datafusion/core/src/execution/context/mod.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ use datafusion_expr::{
8181
planner::ExprPlanner,
8282
Expr, UserDefinedLogicalNode, WindowUDF,
8383
};
84+
use datafusion_functions::datetime::now::NowFunc;
85+
use datafusion_functions::make_udf_function_with_config;
8486
use datafusion_optimizer::analyzer::type_coercion::TypeCoercion;
8587
use datafusion_optimizer::Analyzer;
8688
use datafusion_optimizer::{AnalyzerRule, OptimizerRule};
@@ -1073,6 +1075,19 @@ impl SessionContext {
10731075
let mut state = self.state.write();
10741076
state.config_mut().options_mut().set(&variable, &value)?;
10751077
drop(state);
1078+
1079+
// Register UDFs that return values based on session configuration
1080+
// e.g. now() which depends on the time_zone configuration option
1081+
if variable == "datafusion.execution.time_zone" {
1082+
let state = self.state.read();
1083+
let config_options = state.config().options().clone();
1084+
drop(state);
1085+
let now_udf = {
1086+
make_udf_function_with_config!(NowFunc, now, &ConfigOptions);
1087+
now(&config_options)
1088+
};
1089+
self.state.write().register_udf(now_udf)?;
1090+
}
10761091
}
10771092

10781093
self.return_empty_dataframe()

datafusion/functions/src/datetime/now.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ use arrow::datatypes::DataType::Timestamp;
1919
use arrow::datatypes::TimeUnit::Nanosecond;
2020
use arrow::datatypes::{DataType, Field, FieldRef};
2121
use std::any::Any;
22+
use std::sync::Arc;
2223

24+
use datafusion_common::config::ConfigOptions;
2325
use datafusion_common::{internal_err, Result, ScalarValue};
2426
use datafusion_expr::simplify::{ExprSimplifyResult, SimplifyInfo};
2527
use datafusion_expr::{
@@ -41,6 +43,7 @@ The `now()` return value is determined at query time and will return the same ti
4143
pub struct NowFunc {
4244
signature: Signature,
4345
aliases: Vec<String>,
46+
timezone: Option<Arc<str>>,
4447
}
4548

4649
impl Default for NowFunc {
@@ -54,6 +57,15 @@ impl NowFunc {
5457
Self {
5558
signature: Signature::nullary(Volatility::Stable),
5659
aliases: vec!["current_timestamp".to_string()],
60+
timezone: Some(Arc::from("+00")),
61+
}
62+
}
63+
64+
pub fn new_with_config(config: &ConfigOptions) -> Self {
65+
Self {
66+
signature: Signature::nullary(Volatility::Stable),
67+
aliases: vec!["current_timestamp".to_string()],
68+
timezone: Some(Arc::from(config.execution.time_zone.as_str())),
5769
}
5870
}
5971
}
@@ -80,7 +92,7 @@ impl ScalarUDFImpl for NowFunc {
8092
fn return_field_from_args(&self, _args: ReturnFieldArgs) -> Result<FieldRef> {
8193
Ok(Field::new(
8294
self.name(),
83-
Timestamp(Nanosecond, Some("+00".into())),
95+
Timestamp(Nanosecond, self.timezone.clone()),
8496
false,
8597
)
8698
.into())

datafusion/functions/src/macros.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,22 @@ macro_rules! make_udf_function {
8989
};
9090
}
9191

92+
/// Creates a singleton `ScalarUDF` of the `$UDF` function and a function
93+
/// named `$NAME` which returns that singleton. The function takes a
94+
/// configuration argument of type `$CONFIG_TYPE` to create the UDF.
95+
#[macro_export]
96+
macro_rules! make_udf_function_with_config {
97+
($UDF:ty, $NAME:ident, $CONFIG_TYPE:ty) => {
98+
#[allow(rustdoc::redundant_explicit_links)]
99+
#[doc = concat!("Return a [`ScalarUDF`](datafusion_expr::ScalarUDF) implementation of ", stringify!($NAME))]
100+
pub fn $NAME(config: $CONFIG_TYPE) -> std::sync::Arc<datafusion_expr::ScalarUDF> {
101+
std::sync::Arc::new(datafusion_expr::ScalarUDF::new_from_impl(
102+
<$UDF>::new_with_config(&config),
103+
))
104+
}
105+
};
106+
}
107+
92108
/// Macro creates a sub module if the feature is not enabled
93109
///
94110
/// The rationale for providing stub functions is to help users to configure datafusion

0 commit comments

Comments
 (0)