## Coverage Report

#### Created: 2025-11-22 06:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /Users/andrewlamb/Software/datafusion/datafusion/functions/src/datetime/now.rs

    Line
    Count
    Source
    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
    18
    use arrow::datatypes::DataType::Timestamp;
    19
    use arrow::datatypes::TimeUnit::Nanosecond;
    20
    use arrow::datatypes::{DataType, Field, FieldRef};
    21
    use std::any::Any;
    22
    use std::sync::Arc;
    23
    24
    use datafusion_common::config::ConfigOptions;
    25
    use datafusion_common::{internal_err, Result, ScalarValue};
    26
    use datafusion_expr::simplify::{ExprSimplifyResult, SimplifyInfo};
    27
    use datafusion_expr::{
    28
        ColumnarValue, Documentation, Expr, ReturnFieldArgs, ScalarUDF, ScalarUDFImpl,
    29
        Signature, Volatility,
    30
    };
    31
    use datafusion_macros::user_doc;
    32
    33
    #[user_doc(
    34
        doc_section(label = "Time and Date Functions"),
    35
        description = r#"
    36
    Returns the current timestamp in the system configured timezone (None by default).
    37
    38
    The `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)]
    43
    pub struct NowFunc {
    44
        signature: Signature,
    45
        aliases: Vec<String>,
    46
        timezone: Option<Arc<str>>,
    47
    }
    48
    49
    impl Default for NowFunc {
    50
    0
        fn default() -> Self {
    51
    0
            Self::new_with_config(&ConfigOptions::default())
    52
    0
        }
    53
    }
    54
    55
    impl 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
    0
        pub fn new() -> Self {
    63
    0
            Self::new_with_config(&ConfigOptions::default())
    64
    0
        }
    65
    66
    0
        pub fn new_with_config(config: &ConfigOptions) -> Self {
    67
            Self {
    68
    0
                signature: Signature::nullary(Volatility::Stable),
    69
    0
                aliases: vec!["current_timestamp".to_string()],
    70
    0
                timezone: config
    71
    0
                    .execution
    72
    0
                    .time_zone
    73
    0
                    .as_ref()
    74
    0
                    .map(|tz| Arc::from(tz.as_str())),
    75
            }
    76
    0
        }
    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.
    85
    impl ScalarUDFImpl for NowFunc {
    86
    0
        fn as_any(&self) -> &dyn Any {
    87
    0
            self
    88
    0
        }
    89
    90
    0
        fn name(&self) -> &str {
    91
    0
            "now"
    92
    0
        }
    93
    94
    0
        fn signature(&self) -> &Signature {
    95
    0
            &self.signature
    96
    0
        }
    97
    98
    0
        fn with_updated_config(&self, config: &ConfigOptions) -> Option<ScalarUDF> {
    99
    0
            Some(Self::new_with_config(config).into())
    100
    0
        }
    101
    102
    0
        fn return_field_from_args(&self, _args: ReturnFieldArgs) -> Result<FieldRef> {
    103
    0
            Ok(Field::new(
    104
    0
                self.name(),
    105
    0
                Timestamp(Nanosecond, self.timezone.clone()),
    106
    0
                false,
    107
    0
            )
    108
    0
            .into())
    109
    0
        }
    110
    111
    0
        fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
    112
    0
            internal_err!("return_field_from_args should be called instead")
    113
    0
        }
    114
    115
    0
        fn invoke_with_args(
    116
    0
            &self,
    117
    0
            _args: datafusion_expr::ScalarFunctionArgs,
    118
    0
        ) -> Result<ColumnarValue> {
    119
    0
            internal_err!("invoke should not be called on a simplified now() function")
    120
    0
        }
    121
    122
    0
        fn simplify(
    123
    0
            &self,
    124
    0
            _args: Vec<Expr>,
    125
    0
            info: &dyn SimplifyInfo,
    126
    0
        ) -> Result<ExprSimplifyResult> {
    127
    0
            let now_ts = info
    128
    0
                .execution_props()
    129
    0
                .query_execution_start_time
    130
    0
                .timestamp_nanos_opt();
    131
    132
    0
            Ok(ExprSimplifyResult::Simplified(Expr::Literal(
    133
    0
                ScalarValue::TimestampNanosecond(now_ts, self.timezone.clone()),
    134
    0
                None,
    135
    0
            )))
    136
    0
        }
    137
    138
    0
        fn aliases(&self) -> &[String] {
    139
    0
            &self.aliases
    140
    0
        }
    141
    142
    0
        fn documentation(&self) -> Option<&Documentation> {
    143
    0
            self.doc()
    144
    0
        }
    145
    }
    146
    147
    #[cfg(test)]
    148
    mod 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
    }