Skip to content

Commit

Permalink
feat: support set timezone in db (#2992)
Browse files Browse the repository at this point in the history
* feat: support set timezone in db

* chore: fix  ci

* chore: fix code advice

* fix: rename `time_zone` to `timezone`
  • Loading branch information
Taylor-lagrange authored Dec 27, 2023
1 parent feec4e2 commit d1ee1ba
Show file tree
Hide file tree
Showing 30 changed files with 261 additions and 189 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions config/frontend.example.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Node running mode, see `standalone.example.toml`.
mode = "distributed"
# The default timezone of the server
# default_timezone = "UTC"

[heartbeat]
# Interval for sending heartbeat task to the Metasrv, 5 seconds by default.
Expand Down
2 changes: 2 additions & 0 deletions config/standalone.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
mode = "standalone"
# Whether to enable greptimedb telemetry, true by default.
enable_telemetry = true
# The default timezone of the server
# default_timezone = "UTC"

# HTTP server options.
[http]
Expand Down
1 change: 1 addition & 0 deletions src/cmd/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ common-recordbatch.workspace = true
common-telemetry = { workspace = true, features = [
"deadlock_detection",
] }
common-time.workspace = true
config = "0.13"
datanode.workspace = true
datatypes.workspace = true
Expand Down
7 changes: 7 additions & 0 deletions src/cmd/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ pub enum Error {
source: common_meta::error::Error,
},

#[snafu(display("Failed to init default timezone"))]
InitTimezone {
location: Location,
source: common_time::error::Error,
},

#[snafu(display("Failed to start procedure manager"))]
StartProcedureManager {
location: Location,
Expand Down Expand Up @@ -268,6 +274,7 @@ impl ErrorExt for Error {
| Error::LoadLayeredConfig { .. }
| Error::IllegalConfig { .. }
| Error::InvalidReplCommand { .. }
| Error::InitTimezone { .. }
| Error::ConnectEtcd { .. }
| Error::NotDataFromOutput { .. }
| Error::CreateDir { .. }
Expand Down
5 changes: 4 additions & 1 deletion src/cmd/src/frontend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use client::client_manager::DatanodeClients;
use common_meta::heartbeat::handler::parse_mailbox_message::ParseMailboxMessageHandler;
use common_meta::heartbeat::handler::HandlerGroupExecutor;
use common_telemetry::logging;
use common_time::timezone::set_default_timezone;
use frontend::frontend::FrontendOptions;
use frontend::heartbeat::handler::invalidate_table_cache::InvalidateTableCacheHandler;
use frontend::heartbeat::HeartbeatTask;
Expand All @@ -32,7 +33,7 @@ use servers::tls::{TlsMode, TlsOption};
use servers::Mode;
use snafu::{OptionExt, ResultExt};

use crate::error::{self, MissingConfigSnafu, Result, StartFrontendSnafu};
use crate::error::{self, InitTimezoneSnafu, MissingConfigSnafu, Result, StartFrontendSnafu};
use crate::options::{CliOptions, Options};
use crate::App;

Expand Down Expand Up @@ -217,6 +218,8 @@ impl StartCommand {
logging::info!("Frontend start command: {:#?}", self);
logging::info!("Frontend options: {:#?}", opts);

set_default_timezone(opts.default_timezone.as_deref()).context(InitTimezoneSnafu)?;

let meta_client_options = opts.meta_client.as_ref().context(MissingConfigSnafu {
msg: "'meta_client'",
})?;
Expand Down
11 changes: 9 additions & 2 deletions src/cmd/src/standalone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ use common_meta::wal::{WalOptionsAllocator, WalOptionsAllocatorRef};
use common_procedure::ProcedureManagerRef;
use common_telemetry::info;
use common_telemetry::logging::LoggingOptions;
use common_time::timezone::set_default_timezone;
use datanode::config::{DatanodeOptions, ProcedureConfig, RegionEngineConfig, StorageConfig};
use datanode::datanode::{Datanode, DatanodeBuilder};
use file_engine::config::EngineConfig as FileEngineConfig;
Expand All @@ -51,8 +52,8 @@ use servers::Mode;
use snafu::ResultExt;

use crate::error::{
CreateDirSnafu, IllegalConfigSnafu, InitDdlManagerSnafu, InitMetadataSnafu, Result,
ShutdownDatanodeSnafu, ShutdownFrontendSnafu, StartDatanodeSnafu, StartFrontendSnafu,
CreateDirSnafu, IllegalConfigSnafu, InitDdlManagerSnafu, InitMetadataSnafu, InitTimezoneSnafu,
Result, ShutdownDatanodeSnafu, ShutdownFrontendSnafu, StartDatanodeSnafu, StartFrontendSnafu,
StartProcedureManagerSnafu, StartWalOptionsAllocatorSnafu, StopProcedureManagerSnafu,
};
use crate::options::{CliOptions, MixOptions, Options};
Expand Down Expand Up @@ -98,6 +99,7 @@ impl SubCommand {
pub struct StandaloneOptions {
pub mode: Mode,
pub enable_telemetry: bool,
pub default_timezone: Option<String>,
pub http: HttpOptions,
pub grpc: GrpcOptions,
pub mysql: MysqlOptions,
Expand All @@ -121,6 +123,7 @@ impl Default for StandaloneOptions {
Self {
mode: Mode::Standalone,
enable_telemetry: true,
default_timezone: None,
http: HttpOptions::default(),
grpc: GrpcOptions::default(),
mysql: MysqlOptions::default(),
Expand All @@ -147,6 +150,7 @@ impl StandaloneOptions {
fn frontend_options(self) -> FrontendOptions {
FrontendOptions {
mode: self.mode,
default_timezone: self.default_timezone,
http: self.http,
grpc: self.grpc,
mysql: self.mysql,
Expand Down Expand Up @@ -369,6 +373,9 @@ impl StartCommand {

info!("Building standalone instance with {opts:#?}");

set_default_timezone(opts.frontend.default_timezone.as_deref())
.context(InitTimezoneSnafu)?;

// Ensure the data_home directory exists.
fs::create_dir_all(path::Path::new(&opts.data_home)).context(CreateDirSnafu {
dir: &opts.data_home,
Expand Down
1 change: 1 addition & 0 deletions src/common/time/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ chrono-tz = "0.8"
chrono.workspace = true
common-error.workspace = true
common-macro.workspace = true
once_cell.workspace = true
serde = { version = "1.0", features = ["derive"] }
serde_json.workspace = true
snafu.workspace = true
Expand Down
15 changes: 8 additions & 7 deletions src/common/time/src/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use chrono::{Days, LocalResult, Months, NaiveDateTime, TimeZone as ChronoTimeZon
use serde::{Deserialize, Serialize};

use crate::error::{Error, InvalidDateStrSnafu, Result};
use crate::timezone::TimeZone;
use crate::timezone::Timezone;
use crate::util::{format_utc_datetime, local_datetime_to_utc};
use crate::{Date, Interval};

Expand Down Expand Up @@ -110,11 +110,11 @@ impl DateTime {
NaiveDateTime::from_timestamp_millis(self.0)
}

pub fn to_chrono_datetime_with_timezone(&self, tz: Option<TimeZone>) -> Option<NaiveDateTime> {
pub fn to_chrono_datetime_with_timezone(&self, tz: Option<Timezone>) -> Option<NaiveDateTime> {
let datetime = self.to_chrono_datetime();
datetime.map(|v| match tz {
Some(TimeZone::Offset(offset)) => offset.from_utc_datetime(&v).naive_local(),
Some(TimeZone::Named(tz)) => tz.from_utc_datetime(&v).naive_local(),
Some(Timezone::Offset(offset)) => offset.from_utc_datetime(&v).naive_local(),
Some(Timezone::Named(tz)) => tz.from_utc_datetime(&v).naive_local(),
None => Utc.from_utc_datetime(&v).naive_local(),
})
}
Expand Down Expand Up @@ -155,18 +155,19 @@ impl DateTime {
#[cfg(test)]
mod tests {
use super::*;
use crate::timezone::set_default_timezone;

#[test]
pub fn test_new_date_time() {
std::env::set_var("TZ", "Asia/Shanghai");
set_default_timezone(Some("Asia/Shanghai")).unwrap();
assert_eq!("1970-01-01 08:00:00+0800", DateTime::new(0).to_string());
assert_eq!("1970-01-01 08:00:01+0800", DateTime::new(1000).to_string());
assert_eq!("1970-01-01 07:59:59+0800", DateTime::new(-1000).to_string());
}

#[test]
pub fn test_parse_from_string() {
std::env::set_var("TZ", "Asia/Shanghai");
set_default_timezone(Some("Asia/Shanghai")).unwrap();
let time = "1970-01-01 00:00:00+0800";
let dt = DateTime::from_str(time).unwrap();
assert_eq!(time, &dt.to_string());
Expand Down Expand Up @@ -194,7 +195,7 @@ mod tests {

#[test]
fn test_parse_local_date_time() {
std::env::set_var("TZ", "Asia/Shanghai");
set_default_timezone(Some("Asia/Shanghai")).unwrap();
assert_eq!(
-28800000,
DateTime::from_str("1970-01-01 00:00:00").unwrap().val()
Expand Down
16 changes: 8 additions & 8 deletions src/common/time/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ pub enum Error {
#[snafu(display("Timestamp arithmetic overflow, msg: {}", msg))]
ArithmeticOverflow { msg: String, location: Location },

#[snafu(display("Invalid time zone offset: {hours}:{minutes}"))]
InvalidTimeZoneOffset {
#[snafu(display("Invalid timezone offset: {hours}:{minutes}"))]
InvalidTimezoneOffset {
hours: i32,
minutes: u32,
location: Location,
Expand All @@ -66,18 +66,18 @@ pub enum Error {
location: Location,
},

#[snafu(display("Invalid time zone string {raw}"))]
ParseTimeZoneName { raw: String, location: Location },
#[snafu(display("Invalid timezone string {raw}"))]
ParseTimezoneName { raw: String, location: Location },
}

impl ErrorExt for Error {
fn status_code(&self) -> StatusCode {
match self {
Error::ParseDateStr { .. }
| Error::ParseTimestamp { .. }
| Error::InvalidTimeZoneOffset { .. }
| Error::InvalidTimezoneOffset { .. }
| Error::ParseOffsetStr { .. }
| Error::ParseTimeZoneName { .. } => StatusCode::InvalidArguments,
| Error::ParseTimezoneName { .. } => StatusCode::InvalidArguments,
Error::TimestampOverflow { .. } => StatusCode::Internal,
Error::InvalidDateStr { .. } | Error::ArithmeticOverflow { .. } => {
StatusCode::InvalidArguments
Expand All @@ -96,9 +96,9 @@ impl ErrorExt for Error {
| Error::TimestampOverflow { location, .. }
| Error::ArithmeticOverflow { location, .. } => Some(*location),
Error::ParseDateStr { .. }
| Error::InvalidTimeZoneOffset { .. }
| Error::InvalidTimezoneOffset { .. }
| Error::ParseOffsetStr { .. }
| Error::ParseTimeZoneName { .. } => None,
| Error::ParseTimezoneName { .. } => None,
Error::InvalidDateStr { location, .. } => Some(*location),
Error::ParseInterval { location, .. } => Some(*location),
}
Expand Down
2 changes: 1 addition & 1 deletion src/common/time/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ pub use interval::Interval;
pub use range::RangeMillis;
pub use timestamp::Timestamp;
pub use timestamp_millis::TimestampMillis;
pub use timezone::TimeZone;
pub use timezone::Timezone;
Loading

0 comments on commit d1ee1ba

Please sign in to comment.