datafusion_functions/datetime/
now.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use arrow::datatypes::DataType::Timestamp;
19use arrow::datatypes::TimeUnit::Nanosecond;
20use arrow::datatypes::{DataType, Field, FieldRef};
21use std::any::Any;
22use std::sync::Arc;
23
24use datafusion_common::config::ConfigOptions;
25use datafusion_common::{internal_err, Result, ScalarValue};
26use datafusion_expr::simplify::{ExprSimplifyResult, SimplifyInfo};
27use datafusion_expr::{
28    ColumnarValue, Documentation, Expr, ReturnFieldArgs, ScalarUDF, ScalarUDFImpl,
29    Signature, Volatility,
30};
31use datafusion_macros::user_doc;
32
33#[user_doc(
34    doc_section(label = "Time and Date Functions"),
35    description = r#"
36Returns the current timestamp in the system configured timezone (None by default).
37
38The `now()` return value is determined at query time and will return the same timestamp, no matter when in the query plan the function executes.
39"#,
40    syntax_example = "now()"
41)]
42#[derive(Debug, PartialEq, Eq, Hash)]
43pub struct NowFunc {
44    signature: Signature,
45    aliases: Vec<String>,
46    timezone: Option<Arc<str>>,
47}
48
49impl Default for NowFunc {
50    fn default() -> Self {
51        Self::new_with_config(&ConfigOptions::default())
52    }
53}
54
55impl NowFunc {
56    #[deprecated(since = "50.2.0", note = "use `new_with_config` instead")]
57    /// Deprecated constructor retained for backwards compatibility.
58    ///
59    /// Prefer [`NowFunc::new_with_config`] which allows specifying the
60    /// timezone via [`ConfigOptions`]. This helper now mirrors the
61    /// canonical default offset (None) provided by `ConfigOptions::default()`.
62    pub fn new() -> Self {
63        Self::new_with_config(&ConfigOptions::default())
64    }
65
66    pub fn new_with_config(config: &ConfigOptions) -> Self {
67        Self {
68            signature: Signature::nullary(Volatility::Stable),
69            aliases: vec!["current_timestamp".to_string()],
70            timezone: config
71                .execution
72                .time_zone
73                .as_ref()
74                .map(|tz| Arc::from(tz.as_str())),
75        }
76    }
77}
78
79/// Create an implementation of `now()` that always returns the
80/// specified timestamp.
81///
82/// The semantics of `now()` require it to return the same value
83/// wherever it appears within a single statement. This value is
84/// chosen during planning time.
85impl ScalarUDFImpl for NowFunc {
86    fn as_any(&self) -> &dyn Any {
87        self
88    }
89
90    fn name(&self) -> &str {
91        "now"
92    }
93
94    fn signature(&self) -> &Signature {
95        &self.signature
96    }
97
98    fn with_updated_config(&self, config: &ConfigOptions) -> Option<ScalarUDF> {
99        Some(Self::new_with_config(config).into())
100    }
101
102    fn return_field_from_args(&self, _args: ReturnFieldArgs) -> Result<FieldRef> {
103        Ok(Field::new(
104            self.name(),
105            Timestamp(Nanosecond, self.timezone.clone()),
106            false,
107        )
108        .into())
109    }
110
111    fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
112        internal_err!("return_field_from_args should be called instead")
113    }
114
115    fn invoke_with_args(
116        &self,
117        _args: datafusion_expr::ScalarFunctionArgs,
118    ) -> Result<ColumnarValue> {
119        internal_err!("invoke should not be called on a simplified now() function")
120    }
121
122    fn simplify(
123        &self,
124        _args: Vec<Expr>,
125        info: &dyn SimplifyInfo,
126    ) -> Result<ExprSimplifyResult> {
127        let now_ts = info
128            .execution_props()
129            .query_execution_start_time
130            .timestamp_nanos_opt();
131
132        Ok(ExprSimplifyResult::Simplified(Expr::Literal(
133            ScalarValue::TimestampNanosecond(now_ts, self.timezone.clone()),
134            None,
135        )))
136    }
137
138    fn aliases(&self) -> &[String] {
139        &self.aliases
140    }
141
142    fn documentation(&self) -> Option<&Documentation> {
143        self.doc()
144    }
145}
146
147#[cfg(test)]
148mod tests {
149    use super::*;
150
151    #[allow(deprecated)]
152    #[test]
153    fn now_func_default_matches_config() {
154        let default_config = ConfigOptions::default();
155
156        let legacy_now = NowFunc::new();
157        let configured_now = NowFunc::new_with_config(&default_config);
158
159        let empty_fields: [FieldRef; 0] = [];
160        let empty_scalars: [Option<&ScalarValue>; 0] = [];
161
162        let legacy_field = legacy_now
163            .return_field_from_args(ReturnFieldArgs {
164                arg_fields: &empty_fields,
165                scalar_arguments: &empty_scalars,
166            })
167            .expect("legacy now() return field");
168
169        let configured_field = configured_now
170            .return_field_from_args(ReturnFieldArgs {
171                arg_fields: &empty_fields,
172                scalar_arguments: &empty_scalars,
173            })
174            .expect("configured now() return field");
175
176        assert_eq!(legacy_field.as_ref(), configured_field.as_ref());
177
178        let legacy_scalar =
179            ScalarValue::TimestampNanosecond(None, legacy_now.timezone.clone());
180        let configured_scalar =
181            ScalarValue::TimestampNanosecond(None, configured_now.timezone.clone());
182
183        assert_eq!(legacy_scalar, configured_scalar);
184        assert_eq!(None, legacy_now.timezone.as_deref());
185    }
186}