Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support set timezone in db #2992

Merged
merged 4 commits into from
Dec 27, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 time zone of the server
# default_time_zone = "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 time zone of the server
# default_time_zone = "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 time zone"))]
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
6 changes: 5 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_time_zone;
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,9 @@ impl StartCommand {
logging::info!("Frontend start command: {:#?}", self);
logging::info!("Frontend options: {:#?}", opts);

set_default_time_zone(opts.default_time_zone.as_deref().unwrap_or(""))
.context(InitTimeZoneSnafu)?;
Taylor-lagrange marked this conversation as resolved.
Show resolved Hide resolved

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 @@ -31,6 +31,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_time_zone;
use datanode::config::{DatanodeOptions, ProcedureConfig, RegionEngineConfig, StorageConfig};
use datanode::datanode::{Datanode, DatanodeBuilder};
use file_engine::config::EngineConfig as FileEngineConfig;
Expand All @@ -50,8 +51,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 @@ -97,6 +98,7 @@ impl SubCommand {
pub struct StandaloneOptions {
pub mode: Mode,
pub enable_telemetry: bool,
pub default_time_zone: Option<String>,
pub http: HttpOptions,
pub grpc: GrpcOptions,
pub mysql: MysqlOptions,
Expand All @@ -120,6 +122,7 @@ impl Default for StandaloneOptions {
Self {
mode: Mode::Standalone,
enable_telemetry: true,
default_time_zone: None,
http: HttpOptions::default(),
grpc: GrpcOptions::default(),
mysql: MysqlOptions::default(),
Expand All @@ -146,6 +149,7 @@ impl StandaloneOptions {
fn frontend_options(self) -> FrontendOptions {
FrontendOptions {
mode: self.mode,
default_time_zone: self.default_time_zone,
http: self.http,
grpc: self.grpc,
mysql: self.mysql,
Expand Down Expand Up @@ -366,6 +370,9 @@ impl StartCommand {

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

set_default_time_zone(opts.frontend.default_time_zone.as_deref().unwrap_or(""))
.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
7 changes: 4 additions & 3 deletions src/common/time/src/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,18 +155,19 @@ impl DateTime {
#[cfg(test)]
mod tests {
use super::*;
use crate::timezone::set_default_time_zone;

#[test]
pub fn test_new_date_time() {
std::env::set_var("TZ", "Asia/Shanghai");
set_default_time_zone("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_time_zone("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_time_zone("Asia/Shanghai").unwrap();
assert_eq!(
-28800000,
DateTime::from_str("1970-01-01 00:00:00").unwrap().val()
Expand Down
57 changes: 28 additions & 29 deletions src/common/time/src/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ use chrono::{NaiveDateTime, NaiveTime, TimeZone as ChronoTimeZone, Utc};
use serde::{Deserialize, Serialize};

use crate::timestamp::TimeUnit;
use crate::timezone::TimeZone;
use crate::util::format_utc_datetime;
use crate::timezone::{get_time_zone, TimeZone};

/// Time value, represents the elapsed time since midnight in the unit of `TimeUnit`.
#[derive(Debug, Clone, Default, Copy, Serialize, Deserialize)]
Expand Down Expand Up @@ -109,13 +108,13 @@ impl Time {
self.as_formatted_string("%H:%M:%S%.f%z", None)
}

/// Format Time for local timezone.
/// Format Time for server timezone.
pub fn to_local_string(&self) -> String {
Taylor-lagrange marked this conversation as resolved.
Show resolved Hide resolved
self.as_formatted_string("%H:%M:%S%.f", None)
}

/// Format Time for given timezone.
/// When timezone is None, using local time by default.
/// When timezone is None, using server time zone by default.
pub fn to_timezone_aware_string(&self, tz: Option<TimeZone>) -> String {
self.as_formatted_string("%H:%M:%S%.f", tz)
}
Expand All @@ -124,15 +123,13 @@ impl Time {
if let Some(time) = self.to_chrono_time() {
let date = Utc::now().date_naive();
let datetime = NaiveDateTime::new(date, time);

match timezone {
Some(TimeZone::Offset(offset)) => {
match get_time_zone(timezone) {
TimeZone::Offset(offset) => {
format!("{}", offset.from_utc_datetime(&datetime).format(pattern))
}
Some(TimeZone::Named(tz)) => {
TimeZone::Named(tz) => {
format!("{}", tz.from_utc_datetime(&datetime).format(pattern))
}
None => format_utc_datetime(&datetime, pattern),
}
} else {
format!("[Time{}: {}]", self.unit, self.value)
Expand Down Expand Up @@ -223,6 +220,7 @@ mod tests {
use serde_json::Value;

use super::*;
use crate::timezone::set_default_time_zone;

#[test]
fn test_time() {
Expand Down Expand Up @@ -312,57 +310,57 @@ mod tests {

#[test]
fn test_to_iso8601_string() {
std::env::set_var("TZ", "Asia/Shanghai");
set_default_time_zone("+10:00").unwrap();
let time_millis = 1000001;
let ts = Time::new_millisecond(time_millis);
assert_eq!("08:16:40.001+0800", ts.to_iso8601_string());
assert_eq!("10:16:40.001+1000", ts.to_iso8601_string());

let time_millis = 1000;
let ts = Time::new_millisecond(time_millis);
assert_eq!("08:00:01+0800", ts.to_iso8601_string());
assert_eq!("10:00:01+1000", ts.to_iso8601_string());

let time_millis = 1;
let ts = Time::new_millisecond(time_millis);
assert_eq!("08:00:00.001+0800", ts.to_iso8601_string());
assert_eq!("10:00:00.001+1000", ts.to_iso8601_string());

let time_seconds = 9 * 3600;
let ts = Time::new_second(time_seconds);
assert_eq!("17:00:00+0800", ts.to_iso8601_string());
assert_eq!("19:00:00+1000", ts.to_iso8601_string());

let time_seconds = 23 * 3600;
let ts = Time::new_second(time_seconds);
assert_eq!("07:00:00+0800", ts.to_iso8601_string());
assert_eq!("09:00:00+1000", ts.to_iso8601_string());
}

#[test]
fn test_serialize_to_json_value() {
std::env::set_var("TZ", "Asia/Shanghai");
set_default_time_zone("+10:00").unwrap();
assert_eq!(
"08:00:01+0800",
"10:00:01+1000",
match serde_json::Value::from(Time::new(1, TimeUnit::Second)) {
Value::String(s) => s,
_ => unreachable!(),
}
);

assert_eq!(
"08:00:00.001+0800",
"10:00:00.001+1000",
match serde_json::Value::from(Time::new(1, TimeUnit::Millisecond)) {
Value::String(s) => s,
_ => unreachable!(),
}
);

assert_eq!(
"08:00:00.000001+0800",
"10:00:00.000001+1000",
match serde_json::Value::from(Time::new(1, TimeUnit::Microsecond)) {
Value::String(s) => s,
_ => unreachable!(),
}
);

assert_eq!(
"08:00:00.000000001+0800",
"10:00:00.000000001+1000",
match serde_json::Value::from(Time::new(1, TimeUnit::Nanosecond)) {
Value::String(s) => s,
_ => unreachable!(),
Expand All @@ -372,46 +370,47 @@ mod tests {

#[test]
fn test_to_timezone_aware_string() {
std::env::set_var("TZ", "Asia/Shanghai");
set_default_time_zone("+10:00").unwrap();

assert_eq!(
"08:00:00.001",
"10:00:00.001",
Time::new(1, TimeUnit::Millisecond).to_timezone_aware_string(None)
);
std::env::set_var("TZ", "Asia/Shanghai");
assert_eq!(
"08:00:00.001",
Time::new(1, TimeUnit::Millisecond)
.to_timezone_aware_string(TimeZone::from_tz_string("SYSTEM").unwrap())
.to_timezone_aware_string(Some(TimeZone::from_tz_string("SYSTEM").unwrap()))
);
assert_eq!(
"08:00:00.001",
Time::new(1, TimeUnit::Millisecond)
.to_timezone_aware_string(TimeZone::from_tz_string("+08:00").unwrap())
.to_timezone_aware_string(Some(TimeZone::from_tz_string("+08:00").unwrap()))
);
assert_eq!(
"07:00:00.001",
Time::new(1, TimeUnit::Millisecond)
.to_timezone_aware_string(TimeZone::from_tz_string("+07:00").unwrap())
.to_timezone_aware_string(Some(TimeZone::from_tz_string("+07:00").unwrap()))
);
assert_eq!(
"23:00:00.001",
Time::new(1, TimeUnit::Millisecond)
.to_timezone_aware_string(TimeZone::from_tz_string("-01:00").unwrap())
.to_timezone_aware_string(Some(TimeZone::from_tz_string("-01:00").unwrap()))
);
assert_eq!(
"08:00:00.001",
Time::new(1, TimeUnit::Millisecond)
.to_timezone_aware_string(TimeZone::from_tz_string("Asia/Shanghai").unwrap())
.to_timezone_aware_string(Some(TimeZone::from_tz_string("Asia/Shanghai").unwrap()))
);
assert_eq!(
"00:00:00.001",
Time::new(1, TimeUnit::Millisecond)
.to_timezone_aware_string(TimeZone::from_tz_string("UTC").unwrap())
.to_timezone_aware_string(Some(TimeZone::from_tz_string("UTC").unwrap()))
);
assert_eq!(
"03:00:00.001",
Time::new(1, TimeUnit::Millisecond)
.to_timezone_aware_string(TimeZone::from_tz_string("Europe/Moscow").unwrap())
.to_timezone_aware_string(Some(TimeZone::from_tz_string("Europe/Moscow").unwrap()))
);
}
}
Loading
Loading