common_time/
util.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::str::FromStr;
16
17use chrono::{LocalResult, NaiveDateTime, TimeZone};
18use chrono_tz::Tz;
19
20use crate::timezone::get_timezone;
21use crate::Timezone;
22
23pub fn format_utc_datetime(utc: &NaiveDateTime, pattern: &str) -> String {
24    match get_timezone(None) {
25        crate::Timezone::Offset(offset) => {
26            offset.from_utc_datetime(utc).format(pattern).to_string()
27        }
28        crate::Timezone::Named(tz) => tz.from_utc_datetime(utc).format(pattern).to_string(),
29    }
30}
31
32/// Cast a [`NaiveDateTime`] with the given timezone.
33pub fn datetime_to_utc(
34    datetime: &NaiveDateTime,
35    timezone: &Timezone,
36) -> LocalResult<NaiveDateTime> {
37    match timezone {
38        crate::Timezone::Offset(offset) => {
39            offset.from_local_datetime(datetime).map(|x| x.naive_utc())
40        }
41        crate::Timezone::Named(tz) => tz.from_local_datetime(datetime).map(|x| x.naive_utc()),
42    }
43}
44
45pub fn find_tz_from_env() -> Option<Tz> {
46    // Windows does not support "TZ" env variable, which is used in the `Local` timezone under Unix.
47    // However, we are used to set "TZ" env as the default timezone without actually providing a
48    // timezone argument (especially in tests), and it's very convenient to do so, we decide to make
49    // it work under Windows as well.
50    std::env::var("TZ")
51        .ok()
52        .and_then(|tz| Tz::from_str(&tz).ok())
53}
54
55/// Returns the time duration since UNIX_EPOCH in milliseconds.
56pub fn current_time_millis() -> i64 {
57    chrono::Utc::now().timestamp_millis()
58}
59
60/// Returns the current time in rfc3339 format.
61pub fn current_time_rfc3339() -> String {
62    chrono::Utc::now().to_rfc3339()
63}
64
65/// Returns the yesterday time in rfc3339 format.
66pub fn yesterday_rfc3339() -> String {
67    let now = chrono::Utc::now();
68    let day_before = now
69        - chrono::Duration::try_days(1).unwrap_or_else(|| {
70            panic!("now time ('{now}') is too early to calculate the day before")
71        });
72    day_before.to_rfc3339()
73}
74
75/// Port of rust unstable features `int_roundings`.
76pub(crate) fn div_ceil(this: i64, rhs: i64) -> i64 {
77    let d = this / rhs;
78    let r = this % rhs;
79    if r > 0 && rhs > 0 {
80        d + 1
81    } else {
82        d
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use std::time::{self, SystemTime};
89
90    use chrono::{Datelike, TimeZone, Timelike};
91
92    use super::*;
93
94    #[test]
95    fn test_current_time_millis() {
96        let now = current_time_millis();
97
98        let millis_from_std = SystemTime::now()
99            .duration_since(time::UNIX_EPOCH)
100            .unwrap()
101            .as_millis() as i64;
102        let datetime_now = chrono::Utc.timestamp_millis_opt(now).unwrap();
103        let datetime_std = chrono::Utc.timestamp_millis_opt(millis_from_std).unwrap();
104
105        assert_eq!(datetime_std.year(), datetime_now.year());
106        assert_eq!(datetime_std.month(), datetime_now.month());
107        assert_eq!(datetime_std.day(), datetime_now.day());
108        assert_eq!(datetime_std.hour(), datetime_now.hour());
109        assert_eq!(datetime_std.minute(), datetime_now.minute());
110    }
111
112    #[test]
113    fn test_div_ceil() {
114        let v0 = 9223372036854676001;
115        assert_eq!(9223372036854677, div_ceil(v0, 1000));
116    }
117}