From 336a2716e03f1b0ecf27af92c1fcc18cb3fef9cf Mon Sep 17 00:00:00 2001 From: Michael Clayton Date: Sun, 20 Mar 2022 17:01:01 -0400 Subject: [PATCH] switch from chrono to time (#1790) * switch from chrono to time * remove some unused time features * get utc offset before threading begins --- Cargo.lock | 12 ++++++-- Cargo.toml | 1 + components/front_matter/Cargo.toml | 2 +- components/front_matter/src/page.rs | 43 +++++++++++++++++---------- components/library/src/content/ser.rs | 4 +-- components/library/src/sorting.rs | 4 +-- components/libs/Cargo.toml | 3 +- components/libs/src/lib.rs | 2 +- docs/content/themes/anpu/index.md | 4 +-- src/cmd/serve.rs | 14 +++++++-- src/console.rs | 7 +++-- src/main.rs | 2 ++ 12 files changed, 65 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a2bb4c8e7..c6b23fb705 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -260,8 +260,6 @@ dependencies = [ "libc", "num-integer", "num-traits", - "serde", - "time 0.1.43", "winapi 0.3.9", ] @@ -759,6 +757,7 @@ dependencies = [ "libs", "serde", "test-case", + "time 0.3.7", "utils", ] @@ -1390,7 +1389,6 @@ version = "0.1.0" dependencies = [ "ammonia", "base64", - "chrono", "csv", "elasticlunr-rs", "filetime", @@ -1419,6 +1417,7 @@ dependencies = [ "svg_metadata", "syntect", "tera", + "time 0.3.7", "toml", "unic-langid", "unicode-segmentation", @@ -3264,8 +3263,15 @@ dependencies = [ "itoa 1.0.1", "libc", "num_threads", + "time-macros", ] +[[package]] +name = "time-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25eb0ca3468fc0acc11828786797f6ef9aa1555e4a211a60d64cc8e4d1be47d6" + [[package]] name = "tinystr" version = "0.3.4" diff --git a/Cargo.toml b/Cargo.toml index 316c5f0c4e..0449bdda1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ termcolor = "1.0.4" # Below is for the serve cmd hyper = { version = "0.14.1", default-features = false, features = ["runtime", "server", "http2", "http1"] } tokio = { version = "1.0.1", default-features = false, features = ["rt", "fs", "time"] } +time = { version = "0.3", features = ["formatting", "macros", "local-offset"] } notify = "4" ws = "0.9" ctrlc = "3" diff --git a/components/front_matter/Cargo.toml b/components/front_matter/Cargo.toml index ad7dbe76c1..3edb3fd680 100644 --- a/components/front_matter/Cargo.toml +++ b/components/front_matter/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] serde = {version = "1.0", features = ["derive"] } - +time = { version = "0.3", features = ["macros"] } errors = { path = "../errors" } utils = { path = "../utils" } libs = { path = "../libs" } diff --git a/components/front_matter/src/page.rs b/components/front_matter/src/page.rs index 7c2c14e2c7..8d116cac9c 100644 --- a/components/front_matter/src/page.rs +++ b/components/front_matter/src/page.rs @@ -1,8 +1,10 @@ use std::collections::HashMap; -use libs::chrono::prelude::*; use libs::tera::{Map, Value}; use serde::Deserialize; +use time::format_description::well_known::Rfc3339; +use time::macros::{format_description, time}; +use time::{Date, OffsetDateTime, PrimitiveDateTime}; use errors::{bail, Result}; use utils::de::{fix_toml_dates, from_toml_datetime}; @@ -20,21 +22,21 @@ pub struct PageFrontMatter { /// Updated date #[serde(default, deserialize_with = "from_toml_datetime")] pub updated: Option, - /// Chrono converted update datatime + /// Datetime content was last updated #[serde(default, skip_deserializing)] - pub updated_datetime: Option, + pub updated_datetime: Option, /// The converted update datetime into a (year, month, day) tuple #[serde(default, skip_deserializing)] - pub updated_datetime_tuple: Option<(i32, u32, u32)>, + pub updated_datetime_tuple: Option<(i32, u8, u8)>, /// Date if we want to order pages (ie blog post) #[serde(default, deserialize_with = "from_toml_datetime")] pub date: Option, - /// Chrono converted datetime + /// Datetime content was created #[serde(default, skip_deserializing)] - pub datetime: Option, + pub datetime: Option, /// The converted date into a (year, month, day) tuple #[serde(default, skip_deserializing)] - pub datetime_tuple: Option<(i32, u32, u32)>, + pub datetime_tuple: Option<(i32, u8, u8)>, /// Whether this page is a draft pub draft: bool, /// The page slug. Will be used instead of the filename if present @@ -68,11 +70,13 @@ pub struct PageFrontMatter { /// 2. a local datetime (RFC3339 with timezone omitted) /// 3. a local date (YYYY-MM-DD). /// This tries each in order. -fn parse_datetime(d: &str) -> Option { - DateTime::parse_from_rfc3339(d) - .or_else(|_| DateTime::parse_from_rfc3339(format!("{}Z", d).as_ref())) - .map(|s| s.naive_local()) - .or_else(|_| NaiveDate::parse_from_str(d, "%Y-%m-%d").map(|s| s.and_hms(0, 0, 0))) +fn parse_datetime(d: &str) -> Option { + OffsetDateTime::parse(d, &Rfc3339) + .or_else(|_| OffsetDateTime::parse(format!("{}Z", d).as_ref(), &Rfc3339)) + .or_else(|_| match Date::parse(d, &format_description!("[year]-[month]-[day]")) { + Ok(date) => Ok(PrimitiveDateTime::new(date, time!(0:00)).assume_utc()), + Err(e) => Err(e), + }) .ok() } @@ -108,15 +112,15 @@ impl PageFrontMatter { Ok(f) } - /// Converts the TOML datetime to a Chrono naive datetime + /// Converts the TOML datetime to a time::OffsetDateTime /// Also grabs the year/month/day tuple that will be used in serialization pub fn date_to_datetime(&mut self) { self.datetime = self.date.as_ref().map(|s| s.as_ref()).and_then(parse_datetime); - self.datetime_tuple = self.datetime.map(|dt| (dt.year(), dt.month(), dt.day())); + self.datetime_tuple = self.datetime.map(|dt| (dt.year(), dt.month().into(), dt.day())); self.updated_datetime = self.updated.as_ref().map(|s| s.as_ref()).and_then(parse_datetime); self.updated_datetime_tuple = - self.updated_datetime.map(|dt| (dt.year(), dt.month(), dt.day())); + self.updated_datetime.map(|dt| (dt.year(), dt.month().into(), dt.day())); } pub fn weight(&self) -> usize { @@ -154,6 +158,7 @@ mod tests { use super::RawFrontMatter; use libs::tera::to_value; use test_case::test_case; + use time::macros::datetime; #[test_case(&RawFrontMatter::Toml(r#" "#); "toml")] #[test_case(&RawFrontMatter::Toml(r#" "#); "yaml")] @@ -229,6 +234,7 @@ date: 2016-10-10 fn can_parse_date_yyyy_mm_dd(content: &RawFrontMatter) { let res = PageFrontMatter::parse(content).unwrap(); assert!(res.datetime.is_some()); + assert_eq!(res.datetime.unwrap(), datetime!(2016 - 10 - 10 0:00 UTC)); } #[test_case(&RawFrontMatter::Toml(r#" @@ -244,6 +250,7 @@ date: 2002-10-02T15:00:00Z fn can_parse_date_rfc3339(content: &RawFrontMatter) { let res = PageFrontMatter::parse(content).unwrap(); assert!(res.datetime.is_some()); + assert_eq!(res.datetime.unwrap(), datetime!(2002 - 10 - 02 15:00:00 UTC)); } #[test_case(&RawFrontMatter::Toml(r#" @@ -259,6 +266,7 @@ date: 2002-10-02T15:00:00 fn can_parse_date_rfc3339_without_timezone(content: &RawFrontMatter) { let res = PageFrontMatter::parse(content).unwrap(); assert!(res.datetime.is_some()); + assert_eq!(res.datetime.unwrap(), datetime!(2002 - 10 - 02 15:00:00 UTC)); } #[test_case(&RawFrontMatter::Toml(r#" @@ -274,6 +282,7 @@ date: 2002-10-02 15:00:00+02:00 fn can_parse_date_rfc3339_with_space(content: &RawFrontMatter) { let res = PageFrontMatter::parse(content).unwrap(); assert!(res.datetime.is_some()); + assert_eq!(res.datetime.unwrap(), datetime!(2002 - 10 - 02 15:00:00+02:00)); } #[test_case(&RawFrontMatter::Toml(r#" @@ -289,6 +298,7 @@ date: 2002-10-02 15:00:00 fn can_parse_date_rfc3339_with_space_without_timezone(content: &RawFrontMatter) { let res = PageFrontMatter::parse(content).unwrap(); assert!(res.datetime.is_some()); + assert_eq!(res.datetime.unwrap(), datetime!(2002 - 10 - 02 15:00:00 UTC)); } #[test_case(&RawFrontMatter::Toml(r#" @@ -304,6 +314,7 @@ date: 2002-10-02T15:00:00.123456Z fn can_parse_date_rfc3339_with_microseconds(content: &RawFrontMatter) { let res = PageFrontMatter::parse(content).unwrap(); assert!(res.datetime.is_some()); + assert_eq!(res.datetime.unwrap(), datetime!(2002 - 10 - 02 15:00:00.123456 UTC)); } #[test_case(&RawFrontMatter::Toml(r#" @@ -349,6 +360,8 @@ date: "2016-10-10" fn can_parse_valid_date_as_string(content: &RawFrontMatter) { let res = PageFrontMatter::parse(content).unwrap(); assert!(res.date.is_some()); + assert!(res.datetime.is_some()); + assert_eq!(res.datetime.unwrap(), datetime!(2016 - 10 - 10 0:00 UTC)); } #[test_case(&RawFrontMatter::Toml(r#" diff --git a/components/library/src/content/ser.rs b/components/library/src/content/ser.rs index 252aed7258..b7a7775294 100644 --- a/components/library/src/content/ser.rs +++ b/components/library/src/content/ser.rs @@ -76,8 +76,8 @@ pub struct SerializingPage<'a> { updated: &'a Option, date: &'a Option, year: Option, - month: Option, - day: Option, + month: Option, + day: Option, taxonomies: &'a HashMap>, extra: &'a Map, path: &'a str, diff --git a/components/library/src/sorting.rs b/components/library/src/sorting.rs index 69b5ec2f73..8d27e61af0 100644 --- a/components/library/src/sorting.rs +++ b/components/library/src/sorting.rs @@ -1,9 +1,9 @@ use std::cmp::Ordering; -use libs::chrono::NaiveDateTime; use libs::lexical_sort::natural_lexical_cmp; use libs::rayon::prelude::*; use libs::slotmap::DefaultKey; +use libs::time::OffsetDateTime; use crate::content::Page; @@ -23,7 +23,7 @@ pub fn sort_actual_pages_by_date(a: &&Page, b: &&Page) -> Ordering { /// Pages without date will be put in the unsortable bucket /// The permalink is used to break ties pub fn sort_pages_by_date( - pages: Vec<(&DefaultKey, Option, &str)>, + pages: Vec<(&DefaultKey, Option, &str)>, ) -> (Vec, Vec) { let (mut can_be_sorted, cannot_be_sorted): (Vec<_>, Vec<_>) = pages.into_par_iter().partition(|page| page.1.is_some()); diff --git a/components/libs/Cargo.toml b/components/libs/Cargo.toml index 8f8d5bd66c..dd88e18a95 100644 --- a/components/libs/Cargo.toml +++ b/components/libs/Cargo.toml @@ -18,8 +18,7 @@ globset = "0.4" unic-langid = "0.9" image = "0.24" regex = "1" -# TODO: replace chrono with time -chrono = { version = "0.4", features = ["serde"] } +time = { version = "0.3" } rayon = "1" webp = "0.2" svg_metadata = "0.4" diff --git a/components/libs/src/lib.rs b/components/libs/src/lib.rs index ed61426b04..ebf29693dc 100644 --- a/components/libs/src/lib.rs +++ b/components/libs/src/lib.rs @@ -6,7 +6,6 @@ pub use ammonia; pub use base64; -pub use chrono; pub use csv; pub use elasticlunr; pub use filetime; @@ -35,6 +34,7 @@ pub use slug; pub use svg_metadata; pub use syntect; pub use tera; +pub use time; pub use toml; pub use unic_langid; pub use unicode_segmentation; diff --git a/docs/content/themes/anpu/index.md b/docs/content/themes/anpu/index.md index a37b504653..2eb08fda51 100644 --- a/docs/content/themes/anpu/index.md +++ b/docs/content/themes/anpu/index.md @@ -81,6 +81,6 @@ Example: anpu_date_format = "%e %B %Y" ``` -The formatting uses the standart `date` filter in Tera. The date format options you can use are listed in the [chrono crate documentation](https://tera.netlify.app/docs/#date). +The formatting uses the standard `date` filter in Tera. The date format options you can use are listed in the [chrono crate documentation](https://tera.netlify.app/docs/#date). - \ No newline at end of file + diff --git a/src/cmd/serve.rs b/src/cmd/serve.rs index 8a488cd7a2..1ca01113aa 100644 --- a/src/cmd/serve.rs +++ b/src/cmd/serve.rs @@ -32,9 +32,10 @@ use hyper::header; use hyper::server::Server; use hyper::service::{make_service_fn, service_fn}; use hyper::{Body, Method, Request, Response, StatusCode}; +use time::macros::format_description; +use time::{OffsetDateTime, UtcOffset}; use mime_guess::from_path as mimetype_from_path; -use libs::chrono::prelude::*; use libs::percent_encoding; use libs::serde_json; use notify::{watcher, RecursiveMode, Watcher}; @@ -286,6 +287,7 @@ pub fn serve( open: bool, include_drafts: bool, fast_rebuild: bool, + utc_offset: UtcOffset ) -> Result<()> { let start = Instant::now(); let (mut site, address) = create_new_site( @@ -529,7 +531,15 @@ pub fn serve( if path.is_dir() && is_folder_empty(&path) { continue; } - println!("Change detected @ {}", Local::now().format("%Y-%m-%d %H:%M:%S")); + + let format = format_description!("[year]-[month]-[day] [hour]:[minute]:[second]"); + let current_time = OffsetDateTime::now_utc().to_offset(utc_offset).format(&format); + if let Ok(time_str) = current_time { + println!("Change detected @ {}", time_str); + } else { + // if formatting fails for some reason + println!("Change detected"); + }; let start = Instant::now(); match detect_change_kind(root_dir, &path, &config_path) { diff --git a/src/console.rs b/src/console.rs index 077a913a93..1698c10bdb 100644 --- a/src/console.rs +++ b/src/console.rs @@ -1,10 +1,10 @@ -use std::env; use std::error::Error as StdError; use std::io::Write; use std::time::Instant; +use std::{convert::TryInto, env}; -use libs::chrono::Duration; use libs::once_cell::sync::Lazy; +use libs::time::Duration; use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; use errors::Error; @@ -90,7 +90,8 @@ pub fn warn_about_ignored_pages(site: &Site) { /// Print the time elapsed rounded to 1 decimal pub fn report_elapsed_time(instant: Instant) { - let duration_ms = Duration::from_std(instant.elapsed()).unwrap().num_milliseconds() as f64; + let duration: Duration = instant.elapsed().try_into().unwrap(); + let duration_ms = duration.whole_milliseconds() as f64; if duration_ms < 1000.0 { success(&format!("Done in {}ms.\n", duration_ms)); diff --git a/src/main.rs b/src/main.rs index c104442fc9..0519f49fcb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ use cli::{Cli, Command}; use utils::net::{get_available_port, port_is_available}; use clap::Parser; +use time::UtcOffset; mod cli; mod cmd; @@ -79,6 +80,7 @@ fn main() { open, drafts, fast, + UtcOffset::current_local_offset().unwrap_or(UtcOffset::UTC), ) { console::unravel_errors("Failed to serve the site", &e); std::process::exit(1);