From 8cacfb1d0779dc1c532c4c9f6ed5fc71f0682a56 Mon Sep 17 00:00:00 2001 From: "Nathan.fooo" <86001920+appflowy@users.noreply.github.com> Date: Wed, 3 May 2023 11:50:02 +0800 Subject: [PATCH] feat: use user local timezone (#2407) --- .../application/database_controller.dart | 3 +- .../calendar/application/calendar_bloc.dart | 2 ++ .../date_type_option/date_type_option.rs | 32 ++++++++++--------- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/application/database_controller.dart b/frontend/appflowy_flutter/lib/plugins/database_view/application/database_controller.dart index 648621e869..2ceca90de7 100644 --- a/frontend/appflowy_flutter/lib/plugins/database_view/application/database_controller.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_view/application/database_controller.dart @@ -341,9 +341,10 @@ class RowDataBuilder { _cellDataByFieldId[fieldInfo.field.id] = num.toString(); } + /// The date should use the UTC timezone. Becuase the backend uses UTC timezone to format the time string. void insertDate(FieldInfo fieldInfo, DateTime date) { assert(fieldInfo.fieldType == FieldType.DateTime); - final timestamp = (date.millisecondsSinceEpoch ~/ 1000); + final timestamp = (date.toUtc().millisecondsSinceEpoch ~/ 1000); _cellDataByFieldId[fieldInfo.field.id] = timestamp.toString(); } diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/calendar/application/calendar_bloc.dart b/frontend/appflowy_flutter/lib/plugins/database_view/calendar/application/calendar_bloc.dart index ded3cb3326..6880454553 100644 --- a/frontend/appflowy_flutter/lib/plugins/database_view/calendar/application/calendar_bloc.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_view/calendar/application/calendar_bloc.dart @@ -240,6 +240,8 @@ class CalendarBloc extends Bloc { cellId: cellId, ); + // The timestamp is using UTC in the backend, so we need to convert it + // to local time. final date = DateTime.fromMillisecondsSinceEpoch( eventPB.timestamp.toInt() * 1000, ); diff --git a/frontend/rust-lib/flowy-database/src/services/field/type_options/date_type_option/date_type_option.rs b/frontend/rust-lib/flowy-database/src/services/field/type_options/date_type_option/date_type_option.rs index a42b5fd100..4cd3444cf7 100644 --- a/frontend/rust-lib/flowy-database/src/services/field/type_options/date_type_option/date_type_option.rs +++ b/frontend/rust-lib/flowy-database/src/services/field/type_options/date_type_option/date_type_option.rs @@ -8,7 +8,7 @@ use crate::services::field::{ }; use bytes::Bytes; use chrono::format::strftime::StrftimeItems; -use chrono::NaiveDateTime; +use chrono::{Local, NaiveDateTime}; use database_model::{FieldRevision, TypeOptionDataDeserializer, TypeOptionDataSerializer}; use flowy_derive::ProtoBuf; use flowy_error::{ErrorCode, FlowyError, FlowyResult}; @@ -60,22 +60,26 @@ impl DateTypeOptionPB { fn today_desc_from_timestamp(&self, cell_data: DateCellData) -> DateCellDataPB { let timestamp = cell_data.timestamp.unwrap_or_default(); - let include_time = cell_data.include_time; - - let naive = chrono::NaiveDateTime::from_timestamp_opt(timestamp, 0); - if naive.is_none() { - return DateCellDataPB::default(); - } - let naive = naive.unwrap(); if timestamp == 0 { return DateCellDataPB::default(); } + + let include_time = cell_data.include_time; + let native = chrono::NaiveDateTime::from_timestamp_opt(timestamp, 0); + if native.is_none() { + return DateCellDataPB::default(); + } + + // Use the local timezone to calculate the formatted date string. We can use the timezone that + // specified by the user in the future. + let offset = Local::now().offset().clone(); + let native = chrono::DateTime::::from_utc(native.unwrap(), offset); let fmt = self.date_format.format_str(); - let date = format!("{}", naive.format_with_items(StrftimeItems::new(fmt))); + let date = format!("{}", native.format_with_items(StrftimeItems::new(fmt))); let time = if include_time { let fmt = self.time_format.format_str(); - format!("{}", naive.format_with_items(StrftimeItems::new(fmt))) + format!("{}", native.format_with_items(StrftimeItems::new(fmt))) } else { "".to_string() }; @@ -97,13 +101,11 @@ impl DateTypeOptionPB { if !time_str.is_empty() { let naive_time = chrono::NaiveTime::parse_from_str(time_str, self.time_format.format_str()); - match naive_time { - Ok(naive_time) => { - return Ok(naive_date.date().and_time(naive_time).timestamp()); - }, + return match naive_time { + Ok(naive_time) => Ok(naive_date.date().and_time(naive_time).timestamp()), Err(_e) => { let msg = format!("Parse {} failed", time_str); - return Err(FlowyError::new(ErrorCode::InvalidDateTimeFormat, &msg)); + Err(FlowyError::new(ErrorCode::InvalidDateTimeFormat, &msg)) }, }; }