date_description.rs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. use crate::impl_from_and_to_type_option;
  2. use crate::services::row::StringifyCellData;
  3. use chrono::format::strftime::StrftimeItems;
  4. use chrono::NaiveDateTime;
  5. use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
  6. use flowy_error::FlowyError;
  7. use flowy_grid_data_model::entities::{Field, FieldType};
  8. use serde::{Deserialize, Serialize};
  9. use strum_macros::EnumIter;
  10. // Date
  11. #[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)]
  12. pub struct DateDescription {
  13. #[pb(index = 1)]
  14. pub date_format: DateFormat,
  15. #[pb(index = 2)]
  16. pub time_format: TimeFormat,
  17. }
  18. impl_from_and_to_type_option!(DateDescription, FieldType::DateTime);
  19. impl DateDescription {
  20. #[allow(dead_code)]
  21. fn today_from_timestamp(&self, timestamp: i64) -> String {
  22. let native = chrono::NaiveDateTime::from_timestamp(timestamp, 0);
  23. self.today_from_native(native)
  24. }
  25. fn today_from_native(&self, naive: chrono::NaiveDateTime) -> String {
  26. let utc: chrono::DateTime<chrono::Utc> = chrono::DateTime::from_utc(naive, chrono::Utc);
  27. let local: chrono::DateTime<chrono::Local> = chrono::DateTime::from(utc);
  28. let fmt_str = format!("{} {}", self.date_format.format_str(), self.time_format.format_str());
  29. let output = format!("{}", local.format_with_items(StrftimeItems::new(&fmt_str)));
  30. output
  31. }
  32. }
  33. impl StringifyCellData for DateDescription {
  34. fn str_from_cell_data(&self, data: String) -> String {
  35. match data.parse::<i64>() {
  36. Ok(timestamp) => {
  37. let native = NaiveDateTime::from_timestamp(timestamp, 0);
  38. self.today_from_native(native)
  39. }
  40. Err(e) => {
  41. tracing::debug!("DateDescription format {} fail. error: {:?}", data, e);
  42. String::new()
  43. }
  44. }
  45. }
  46. fn str_to_cell_data(&self, s: &str) -> Result<String, FlowyError> {
  47. let timestamp = match s.parse::<i64>() {
  48. Ok(timestamp) => timestamp,
  49. Err(e) => {
  50. tracing::error!("Parse {} to i64 failed: {}", s, e);
  51. chrono::Utc::now().timestamp()
  52. }
  53. };
  54. Ok(format!("{}", timestamp))
  55. }
  56. }
  57. #[derive(Clone, Debug, Copy, EnumIter, Serialize, Deserialize, ProtoBuf_Enum)]
  58. pub enum DateFormat {
  59. Local = 0,
  60. US = 1,
  61. ISO = 2,
  62. Friendly = 3,
  63. }
  64. impl std::default::Default for DateFormat {
  65. fn default() -> Self {
  66. DateFormat::Friendly
  67. }
  68. }
  69. impl std::convert::From<i32> for DateFormat {
  70. fn from(value: i32) -> Self {
  71. match value {
  72. 0 => DateFormat::Local,
  73. 1 => DateFormat::US,
  74. 2 => DateFormat::ISO,
  75. 3 => DateFormat::Friendly,
  76. _ => {
  77. tracing::error!("Unsupported date format, fallback to friendly");
  78. DateFormat::Friendly
  79. }
  80. }
  81. }
  82. }
  83. impl DateFormat {
  84. pub fn value(&self) -> i32 {
  85. *self as i32
  86. }
  87. // https://docs.rs/chrono/0.4.19/chrono/format/strftime/index.html
  88. pub fn format_str(&self) -> &'static str {
  89. match self {
  90. DateFormat::Local => "%Y/%m/%d",
  91. DateFormat::US => "%Y/%m/%d",
  92. DateFormat::ISO => "%Y-%m-%d",
  93. DateFormat::Friendly => "%b %d,%Y",
  94. }
  95. }
  96. }
  97. #[derive(Clone, Copy, PartialEq, Eq, EnumIter, Debug, Hash, Serialize, Deserialize, ProtoBuf_Enum)]
  98. pub enum TimeFormat {
  99. TwelveHour = 0,
  100. TwentyFourHour = 1,
  101. }
  102. impl std::convert::From<i32> for TimeFormat {
  103. fn from(value: i32) -> Self {
  104. match value {
  105. 0 => TimeFormat::TwelveHour,
  106. 1 => TimeFormat::TwentyFourHour,
  107. _ => {
  108. tracing::error!("Unsupported time format, fallback to TwentyFourHour");
  109. TimeFormat::TwentyFourHour
  110. }
  111. }
  112. }
  113. }
  114. impl TimeFormat {
  115. pub fn value(&self) -> i32 {
  116. *self as i32
  117. }
  118. // https://docs.rs/chrono/0.4.19/chrono/format/strftime/index.html
  119. pub fn format_str(&self) -> &'static str {
  120. match self {
  121. TimeFormat::TwelveHour => "%r",
  122. TimeFormat::TwentyFourHour => "%R",
  123. }
  124. }
  125. }
  126. impl std::default::Default for TimeFormat {
  127. fn default() -> Self {
  128. TimeFormat::TwentyFourHour
  129. }
  130. }
  131. #[cfg(test)]
  132. mod tests {
  133. use crate::services::cell::{DateDescription, DateFormat, TimeFormat};
  134. use crate::services::row::StringifyCellData;
  135. use strum::IntoEnumIterator;
  136. #[test]
  137. fn date_description_date_format_test() {
  138. let mut description = DateDescription::default();
  139. let _timestamp = 1647251762;
  140. for date_format in DateFormat::iter() {
  141. description.date_format = date_format;
  142. match date_format {
  143. DateFormat::Friendly => {
  144. assert_eq!(
  145. "Mar 14,2022 17:56".to_owned(),
  146. description.today_from_timestamp(1647251762)
  147. );
  148. assert_eq!(
  149. "Mar 14,2022 17:56".to_owned(),
  150. description.str_from_cell_data("1647251762".to_owned())
  151. );
  152. }
  153. DateFormat::US => {
  154. assert_eq!(
  155. "2022/03/14 17:56".to_owned(),
  156. description.today_from_timestamp(1647251762)
  157. );
  158. assert_eq!(
  159. "2022/03/14 17:56".to_owned(),
  160. description.str_from_cell_data("1647251762".to_owned())
  161. );
  162. }
  163. DateFormat::ISO => {
  164. assert_eq!(
  165. "2022-03-14 17:56".to_owned(),
  166. description.today_from_timestamp(1647251762)
  167. );
  168. assert_eq!(
  169. "2022-03-14 17:56".to_owned(),
  170. description.str_from_cell_data("1647251762".to_owned())
  171. );
  172. }
  173. DateFormat::Local => {
  174. assert_eq!(
  175. "2022/03/14 17:56".to_owned(),
  176. description.today_from_timestamp(1647251762)
  177. );
  178. assert_eq!(
  179. "2022/03/14 17:56".to_owned(),
  180. description.str_from_cell_data("1647251762".to_owned())
  181. );
  182. }
  183. }
  184. }
  185. }
  186. #[test]
  187. fn date_description_time_format_test() {
  188. let mut description = DateDescription::default();
  189. for time_format in TimeFormat::iter() {
  190. description.time_format = time_format;
  191. match time_format {
  192. TimeFormat::TwentyFourHour => {
  193. assert_eq!(
  194. "Mar 14,2022 17:56".to_owned(),
  195. description.today_from_timestamp(1647251762)
  196. );
  197. assert_eq!(
  198. "Mar 14,2022 17:56".to_owned(),
  199. description.str_from_cell_data("1647251762".to_owned())
  200. );
  201. }
  202. TimeFormat::TwelveHour => {
  203. assert_eq!(
  204. "Mar 14,2022 05:56:02 PM".to_owned(),
  205. description.today_from_timestamp(1647251762)
  206. );
  207. assert_eq!(
  208. "Mar 14,2022 05:56:02 PM".to_owned(),
  209. description.str_from_cell_data("1647251762".to_owned())
  210. );
  211. }
  212. }
  213. }
  214. }
  215. #[test]
  216. fn date_description_invalid_data_test() {
  217. let description = DateDescription::default();
  218. description.str_to_cell_data("he").unwrap();
  219. }
  220. }