mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2026-01-08 05:10:48 +00:00
241 lines
7.6 KiB
Rust
241 lines
7.6 KiB
Rust
use crate::impl_from_and_to_type_option;
|
|
use crate::services::row::CellDataSerde;
|
|
|
|
use chrono::format::strftime::StrftimeItems;
|
|
use chrono::NaiveDateTime;
|
|
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
|
use flowy_error::FlowyError;
|
|
use flowy_grid_data_model::entities::{FieldMeta, FieldType};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use strum_macros::EnumIter;
|
|
|
|
// Date
|
|
#[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)]
|
|
pub struct DateDescription {
|
|
#[pb(index = 1)]
|
|
pub date_format: DateFormat,
|
|
|
|
#[pb(index = 2)]
|
|
pub time_format: TimeFormat,
|
|
}
|
|
impl_from_and_to_type_option!(DateDescription, FieldType::DateTime);
|
|
|
|
impl DateDescription {
|
|
#[allow(dead_code)]
|
|
fn today_from_timestamp(&self, timestamp: i64) -> String {
|
|
let native = chrono::NaiveDateTime::from_timestamp(timestamp, 0);
|
|
self.today_from_native(native)
|
|
}
|
|
|
|
fn today_from_native(&self, naive: chrono::NaiveDateTime) -> String {
|
|
let utc: chrono::DateTime<chrono::Utc> = chrono::DateTime::from_utc(naive, chrono::Utc);
|
|
let local: chrono::DateTime<chrono::Local> = chrono::DateTime::from(utc);
|
|
|
|
let fmt_str = format!("{} {}", self.date_format.format_str(), self.time_format.format_str());
|
|
let output = format!("{}", local.format_with_items(StrftimeItems::new(&fmt_str)));
|
|
output
|
|
}
|
|
}
|
|
|
|
impl CellDataSerde for DateDescription {
|
|
fn deserialize_cell_data(&self, data: String) -> String {
|
|
match data.parse::<i64>() {
|
|
Ok(timestamp) => {
|
|
let native = NaiveDateTime::from_timestamp(timestamp, 0);
|
|
self.today_from_native(native)
|
|
}
|
|
Err(e) => {
|
|
tracing::debug!("DateDescription format {} fail. error: {:?}", data, e);
|
|
String::new()
|
|
}
|
|
}
|
|
}
|
|
|
|
fn serialize_cell_data(&self, data: &str) -> Result<String, FlowyError> {
|
|
if let Err(e) = data.parse::<i64>() {
|
|
tracing::error!("Parse {} to i64 failed: {}", data, e);
|
|
return Err(FlowyError::internal().context(e));
|
|
};
|
|
Ok(data.to_owned())
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, Copy, EnumIter, Serialize, Deserialize, ProtoBuf_Enum)]
|
|
pub enum DateFormat {
|
|
Local = 0,
|
|
US = 1,
|
|
ISO = 2,
|
|
Friendly = 3,
|
|
}
|
|
impl std::default::Default for DateFormat {
|
|
fn default() -> Self {
|
|
DateFormat::Friendly
|
|
}
|
|
}
|
|
|
|
impl std::convert::From<i32> for DateFormat {
|
|
fn from(value: i32) -> Self {
|
|
match value {
|
|
0 => DateFormat::Local,
|
|
1 => DateFormat::US,
|
|
2 => DateFormat::ISO,
|
|
3 => DateFormat::Friendly,
|
|
_ => {
|
|
tracing::error!("Unsupported date format, fallback to friendly");
|
|
DateFormat::Friendly
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl DateFormat {
|
|
pub fn value(&self) -> i32 {
|
|
*self as i32
|
|
}
|
|
// https://docs.rs/chrono/0.4.19/chrono/format/strftime/index.html
|
|
pub fn format_str(&self) -> &'static str {
|
|
match self {
|
|
DateFormat::Local => "%Y/%m/%d",
|
|
DateFormat::US => "%Y/%m/%d",
|
|
DateFormat::ISO => "%Y-%m-%d",
|
|
DateFormat::Friendly => "%b %d,%Y",
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, EnumIter, Debug, Hash, Serialize, Deserialize, ProtoBuf_Enum)]
|
|
pub enum TimeFormat {
|
|
TwelveHour = 0,
|
|
TwentyFourHour = 1,
|
|
}
|
|
|
|
impl std::convert::From<i32> for TimeFormat {
|
|
fn from(value: i32) -> Self {
|
|
match value {
|
|
0 => TimeFormat::TwelveHour,
|
|
1 => TimeFormat::TwentyFourHour,
|
|
_ => {
|
|
tracing::error!("Unsupported time format, fallback to TwentyFourHour");
|
|
TimeFormat::TwentyFourHour
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TimeFormat {
|
|
pub fn value(&self) -> i32 {
|
|
*self as i32
|
|
}
|
|
|
|
// https://docs.rs/chrono/0.4.19/chrono/format/strftime/index.html
|
|
pub fn format_str(&self) -> &'static str {
|
|
match self {
|
|
TimeFormat::TwelveHour => "%r",
|
|
TimeFormat::TwentyFourHour => "%R",
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::default::Default for TimeFormat {
|
|
fn default() -> Self {
|
|
TimeFormat::TwentyFourHour
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::services::cell::{DateDescription, DateFormat, TimeFormat};
|
|
use crate::services::row::CellDataSerde;
|
|
use strum::IntoEnumIterator;
|
|
|
|
#[test]
|
|
fn date_description_date_format_test() {
|
|
let mut description = DateDescription::default();
|
|
let _timestamp = 1647251762;
|
|
|
|
for date_format in DateFormat::iter() {
|
|
description.date_format = date_format;
|
|
match date_format {
|
|
DateFormat::Friendly => {
|
|
assert_eq!(
|
|
"Mar 14,2022 17:56".to_owned(),
|
|
description.today_from_timestamp(1647251762)
|
|
);
|
|
assert_eq!(
|
|
"Mar 14,2022 17:56".to_owned(),
|
|
description.deserialize_cell_data("1647251762".to_owned())
|
|
);
|
|
}
|
|
DateFormat::US => {
|
|
assert_eq!(
|
|
"2022/03/14 17:56".to_owned(),
|
|
description.today_from_timestamp(1647251762)
|
|
);
|
|
assert_eq!(
|
|
"2022/03/14 17:56".to_owned(),
|
|
description.deserialize_cell_data("1647251762".to_owned())
|
|
);
|
|
}
|
|
DateFormat::ISO => {
|
|
assert_eq!(
|
|
"2022-03-14 17:56".to_owned(),
|
|
description.today_from_timestamp(1647251762)
|
|
);
|
|
assert_eq!(
|
|
"2022-03-14 17:56".to_owned(),
|
|
description.deserialize_cell_data("1647251762".to_owned())
|
|
);
|
|
}
|
|
DateFormat::Local => {
|
|
assert_eq!(
|
|
"2022/03/14 17:56".to_owned(),
|
|
description.today_from_timestamp(1647251762)
|
|
);
|
|
assert_eq!(
|
|
"2022/03/14 17:56".to_owned(),
|
|
description.deserialize_cell_data("1647251762".to_owned())
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn date_description_time_format_test() {
|
|
let mut description = DateDescription::default();
|
|
for time_format in TimeFormat::iter() {
|
|
description.time_format = time_format;
|
|
match time_format {
|
|
TimeFormat::TwentyFourHour => {
|
|
assert_eq!(
|
|
"Mar 14,2022 17:56".to_owned(),
|
|
description.today_from_timestamp(1647251762)
|
|
);
|
|
assert_eq!(
|
|
"Mar 14,2022 17:56".to_owned(),
|
|
description.deserialize_cell_data("1647251762".to_owned())
|
|
);
|
|
}
|
|
TimeFormat::TwelveHour => {
|
|
assert_eq!(
|
|
"Mar 14,2022 05:56:02 PM".to_owned(),
|
|
description.today_from_timestamp(1647251762)
|
|
);
|
|
assert_eq!(
|
|
"Mar 14,2022 05:56:02 PM".to_owned(),
|
|
description.deserialize_cell_data("1647251762".to_owned())
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[should_panic]
|
|
fn date_description_invalid_data_test() {
|
|
let description = DateDescription::default();
|
|
description.serialize_cell_data("he").unwrap();
|
|
}
|
|
}
|