diff --git a/Cargo.toml b/Cargo.toml index 9ae25fbfc..da610bd2c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Kisio Digital ", "Guillaume Pinot "] name = "transit_model" -version = "0.27.0" +version = "0.28.0" license = "AGPL-3.0-only" description = "Transit data management" repository = "https://github.com/CanalTP/transit_model" @@ -39,6 +39,7 @@ xmllint = ["proj"] [dependencies] chrono = "0.4" +chrono-tz = { version = "0.5", features = ["serde"] } csv = "1" derivative = "2" failure = "0.1" diff --git a/gtfs2netexfr/Cargo.toml b/gtfs2netexfr/Cargo.toml index f368bfd2c..b206bf8ac 100644 --- a/gtfs2netexfr/Cargo.toml +++ b/gtfs2netexfr/Cargo.toml @@ -22,4 +22,4 @@ slog-scope = "4.1" slog-stdlog = "4.0" slog-term = "2.4" structopt = "0.3" -transit_model = { version = "0.27", path = "../", features = ["proj"] } +transit_model = { version = "0.28", path = "../", features = ["proj"] } diff --git a/gtfs2ntfs/Cargo.toml b/gtfs2ntfs/Cargo.toml index b23a4df1f..bb9ebde8a 100644 --- a/gtfs2ntfs/Cargo.toml +++ b/gtfs2ntfs/Cargo.toml @@ -22,4 +22,4 @@ slog-scope = "4.1" slog-stdlog = "4.0" slog-term = "2.4" structopt = "0.3" -transit_model = { version = "0.27", path = "../" } +transit_model = { version = "0.28", path = "../" } diff --git a/ntfs2gtfs/Cargo.toml b/ntfs2gtfs/Cargo.toml index 73a3a19bc..592bb32a0 100644 --- a/ntfs2gtfs/Cargo.toml +++ b/ntfs2gtfs/Cargo.toml @@ -22,4 +22,4 @@ slog-scope = "4.1" slog-stdlog = "4.0" slog-term = "2.4" structopt = "0.3" -transit_model = { version = "0.27", path = "../" } +transit_model = { version = "0.28", path = "../" } diff --git a/ntfs2netexfr/Cargo.toml b/ntfs2netexfr/Cargo.toml index 8835a6f83..da298b4eb 100644 --- a/ntfs2netexfr/Cargo.toml +++ b/ntfs2netexfr/Cargo.toml @@ -22,4 +22,4 @@ slog-scope = "4.1" slog-stdlog = "4.0" slog-term = "2.4" structopt = "0.3" -transit_model = { version = "0.27", path = "../", features = ["proj"] } +transit_model = { version = "0.28", path = "../", features = ["proj"] } diff --git a/ntfs2ntfs/Cargo.toml b/ntfs2ntfs/Cargo.toml index 3e21236b7..87da1954f 100644 --- a/ntfs2ntfs/Cargo.toml +++ b/ntfs2ntfs/Cargo.toml @@ -22,4 +22,4 @@ slog-scope = "4.1" slog-stdlog = "4.0" slog-term = "2.4" structopt = "0.3" -transit_model = { version = "0.27", path = "../" } +transit_model = { version = "0.28", path = "../" } diff --git a/restrict-validity-period/Cargo.toml b/restrict-validity-period/Cargo.toml index 7f6efe77a..281fb7826 100644 --- a/restrict-validity-period/Cargo.toml +++ b/restrict-validity-period/Cargo.toml @@ -21,4 +21,4 @@ slog-scope = "4.1" slog-stdlog = "4.0" slog-term = "2.4" structopt = "0.3" -transit_model = { version = "0.27", path = "../" } +transit_model = { version = "0.28", path = "../" } diff --git a/src/gtfs/mod.rs b/src/gtfs/mod.rs index f80b8424c..4fda77dfa 100644 --- a/src/gtfs/mod.rs +++ b/src/gtfs/mod.rs @@ -21,7 +21,7 @@ use crate::{ calendars::{manage_calendars, write_calendar_dates}, gtfs::read::EquipmentList, model::{Collections, Model}, - objects::{self, Availability, Contributor, Dataset, StopPoint, StopType, Time}, + objects::{self, Availability, Contributor, Dataset, StopPoint, StopType, Time, TzExt}, read_utils, utils::*, validity_period, AddPrefix, PrefixConfiguration, Result, @@ -41,7 +41,7 @@ struct Agency { #[serde(rename = "agency_url")] url: String, #[serde(rename = "agency_timezone")] - timezone: String, + pub timezone: TzExt, #[serde(rename = "agency_lang")] lang: Option, #[serde(rename = "agency_phone")] @@ -62,7 +62,7 @@ impl<'a> From<&'a objects::Network> for Agency { timezone: obj .timezone .clone() - .unwrap_or_else(|| "Europe/Paris".to_string()), + .unwrap_or_else(|| TzExt(chrono_tz::Europe::Paris)), lang: obj.lang.clone(), phone: obj.phone.clone(), email: None, @@ -137,7 +137,7 @@ struct Stop { #[serde(default, deserialize_with = "de_option_without_slashes")] parent_station: Option, #[serde(rename = "stop_timezone")] - timezone: Option, + timezone: Option, level_id: Option, #[serde(deserialize_with = "de_with_empty_default", default)] wheelchair_boarding: Availability, diff --git a/src/gtfs/write.rs b/src/gtfs/write.rs index 6c476bddd..f78547435 100644 --- a/src/gtfs/write.rs +++ b/src/gtfs/write.rs @@ -104,7 +104,7 @@ fn ntfs_stop_point_to_gtfs_stop( desc: get_first_comment_name(sp, comments), wheelchair_boarding: wheelchair, url: None, - timezone: sp.timezone.clone(), + timezone: sp.timezone, level_id: sp.level_id.clone(), platform_code: sp.platform_code.clone(), } @@ -133,7 +133,7 @@ fn ntfs_stop_area_to_gtfs_stop( desc: get_first_comment_name(sa, comments), wheelchair_boarding: wheelchair, url: None, - timezone: sa.timezone.clone(), + timezone: sa.timezone, level_id: sa.level_id.clone(), platform_code: None, } @@ -164,7 +164,7 @@ fn ntfs_stop_location_to_gtfs_stop( desc: get_first_comment_name(sl, comments), wheelchair_boarding: wheelchair, url: None, - timezone: sl.timezone.clone(), + timezone: sl.timezone, level_id: sl.level_id.clone(), platform_code: None, } @@ -543,7 +543,7 @@ mod tests { id: "OIF:101".to_string(), name: "SAVAC".to_string(), url: Some("http://www.vianavigo.com,Europe/Paris".to_string()), - timezone: Some("Europe/Madrid".to_string()), + timezone: Some(TzExt(chrono_tz::Europe::Madrid)), lang: Some("fr".to_string()), phone: Some("0123456789".to_string()), address: Some("somewhere".to_string()), @@ -555,7 +555,7 @@ mod tests { id: Some("OIF:101".to_string()), name: "SAVAC".to_string(), url: "http://www.vianavigo.com,Europe/Paris".to_string(), - timezone: "Europe/Madrid".to_string(), + timezone: TzExt(chrono_tz::Europe::Madrid), lang: Some("fr".to_string()), phone: Some("0123456789".to_string()), email: None, @@ -582,7 +582,7 @@ mod tests { id: Some("OIF:101".to_string()), name: "SAVAC".to_string(), url: "http://www.navitia.io/".to_string(), - timezone: "Europe/Paris".to_string(), + timezone: TzExt(chrono_tz::Europe::Paris), lang: None, phone: None, email: None, @@ -647,7 +647,7 @@ mod tests { lat: 48.799_115, }, stop_area_id: "OIF:SA:8739322".to_string(), - timezone: Some("Europe/Paris".to_string()), + timezone: Some(TzExt(chrono_tz::Europe::Paris)), equipment_id: Some("1".to_string()), fare_zone_id: Some("1".to_string()), stop_type: StopType::Point, @@ -666,7 +666,7 @@ mod tests { desc: Some("bar".to_string()), wheelchair_boarding: Availability::Available, url: None, - timezone: Some("Europe/Paris".to_string()), + timezone: Some(TzExt(chrono_tz::Europe::Paris)), level_id: None, platform_code: None, }; @@ -773,7 +773,7 @@ mod tests { lon: 2.073_034, lat: 48.799_115, }, - timezone: Some("Europe/Paris".to_string()), + timezone: Some(TzExt(chrono_tz::Europe::Paris)), geometry_id: None, equipment_id: Some("1".to_string()), level_id: None, @@ -791,7 +791,7 @@ mod tests { desc: Some("bar".to_string()), wheelchair_boarding: Availability::NotAvailable, url: None, - timezone: Some("Europe/Paris".to_string()), + timezone: Some(TzExt(chrono_tz::Europe::Paris)), level_id: None, platform_code: None, }; diff --git a/src/ntfs/mod.rs b/src/ntfs/mod.rs index 7db3e4043..384a95945 100644 --- a/src/ntfs/mod.rs +++ b/src/ntfs/mod.rs @@ -122,7 +122,7 @@ struct Stop { location_type: StopLocationType, parent_station: Option, #[serde(rename = "stop_timezone")] - timezone: Option, + timezone: Option, geometry_id: Option, equipment_id: Option, level_id: Option, @@ -412,7 +412,7 @@ mod tests { id: "OIF:101".to_string(), name: "SAVAC".to_string(), url: Some("http://www.vianavigo.com,Europe/Paris".to_string()), - timezone: Some("Europe/Paris".to_string()), + timezone: Some(TzExt(chrono_tz::Europe::Paris)), lang: Some("fr".to_string()), phone: Some("0123456789".to_string()), address: Some("somewhere".to_string()), @@ -584,7 +584,7 @@ mod tests { lat: 48.799_115, }, stop_area_id: "OIF:SA:8739322".to_string(), - timezone: Some("Europe/Paris".to_string()), + timezone: Some(TzExt(chrono_tz::Europe::Paris)), fare_zone_id: Some("1".to_string()), stop_type: StopType::Point, ..Default::default() @@ -598,7 +598,7 @@ mod tests { lat: 48.800_598, }, stop_area_id: "OIF:SA:2:1468".to_string(), - timezone: Some("Europe/Paris".to_string()), + timezone: Some(TzExt(chrono_tz::Europe::Paris)), stop_type: StopType::Point, ..Default::default() }, @@ -828,7 +828,7 @@ mod tests { lon: 2.073_034, lat: 48.799_115, }, - timezone: Some("Europe/Paris".to_string()), + timezone: Some(TzExt(chrono_tz::Europe::Paris)), geometry_id: Some("geometry_1".to_string()), equipment_id: Some("equipment_1".to_string()), stop_area_id: "sa_1".to_string(), @@ -880,7 +880,7 @@ mod tests { lon: 2.073_034, lat: 48.799_115, }, - timezone: Some("Europe/Paris".to_string()), + timezone: Some(TzExt(chrono_tz::Europe::Paris)), geometry_id: Some("geometry_3".to_string()), equipment_id: Some("equipment_1".to_string()), level_id: Some("level2".to_string()), diff --git a/src/ntfs/write.rs b/src/ntfs/write.rs index 7fc979bd0..4486b25be 100644 --- a/src/ntfs/write.rs +++ b/src/ntfs/write.rs @@ -544,7 +544,7 @@ pub fn write_stops( fare_zone_id: None, location_type: StopLocationType::from(sl.stop_type.clone()), parent_station: sl.parent_id.clone(), - timezone: sl.timezone.clone(), + timezone: sl.timezone, equipment_id: sl.equipment_id.clone(), geometry_id: sl.geometry_id.clone(), level_id: sl.level_id.clone(), @@ -574,7 +574,7 @@ pub fn write_stops( fare_zone_id: st.fare_zone_id.clone(), location_type, parent_station: stop_areas.get(&st.stop_area_id).map(|sa| sa.id.clone()), - timezone: st.timezone.clone(), + timezone: st.timezone, equipment_id: st.equipment_id.clone(), geometry_id: st.geometry_id.clone(), level_id: st.level_id.clone(), @@ -594,7 +594,7 @@ pub fn write_stops( fare_zone_id: None, location_type: StopLocationType::StopArea, parent_station: None, - timezone: sa.timezone.clone(), + timezone: sa.timezone, equipment_id: sa.equipment_id.clone(), geometry_id: sa.geometry_id.clone(), level_id: sa.level_id.clone(), diff --git a/src/objects.rs b/src/objects.rs index cb5f16575..cf464b1a6 100644 --- a/src/objects.rs +++ b/src/objects.rs @@ -18,6 +18,7 @@ use crate::{utils::*, AddPrefix, PrefixConfiguration}; use chrono::NaiveDate; +use chrono_tz::Tz; use derivative::Derivative; use geo::{Geometry as GeoGeometry, Point as GeoPoint}; use rust_decimal::Decimal; @@ -344,8 +345,9 @@ pub struct Network { pub url: Option, #[serde(skip)] pub codes: KeysValues, + #[derivative(Default(value = "\"Europe/Paris\".parse().ok()"))] #[serde(rename = "network_timezone")] - pub timezone: Option, + pub timezone: Option, #[serde(rename = "network_lang")] pub lang: Option, #[serde(rename = "network_phone")] @@ -355,6 +357,7 @@ pub struct Network { #[serde(rename = "network_sort_order")] pub sort_order: Option, } + impl_id!(Network); impl_codes!(Network); impl_with_id!(Network); @@ -1017,7 +1020,7 @@ pub struct StopArea { pub comment_links: CommentLinksT, pub visible: bool, pub coord: Coord, - pub timezone: Option, + pub timezone: Option, pub geometry_id: Option, pub equipment_id: Option, pub level_id: Option, @@ -1095,7 +1098,7 @@ pub struct StopPoint { pub visible: bool, pub coord: Coord, pub stop_area_id: String, - pub timezone: Option, + pub timezone: Option, pub geometry_id: Option, pub equipment_id: Option, pub fare_zone_id: Option, @@ -1148,7 +1151,7 @@ pub struct StopLocation { pub visible: bool, pub coord: Coord, pub parent_id: Option, - pub timezone: Option, + pub timezone: Option, pub geometry_id: Option, pub equipment_id: Option, pub level_id: Option, @@ -1809,6 +1812,31 @@ impl AddPrefix for GridRelCalendarLine { } } +/// Wrapper around [`Tz`] that implements [`Display`]. +/// +/// [`Display`] is implemented for [`Tz`] +/// but not released yet. Wait for [chrono-tz] version > 0.5.2 +/// +/// [`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html +/// [`Tz`]: https://docs.rs/chrono-tz/0.5.2/chrono_tz/enum.Tz.html +/// [chrono-tz]: https://crates.io/crates/chrono-tz +#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq)] +pub struct TzExt(pub Tz); + +impl std::fmt::Display for TzExt { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let name = self.0.name(); + f.write_str(name.as_ref()) + } +} + +impl FromStr for TzExt { + type Err = String; + fn from_str(s: &str) -> std::result::Result { + Tz::from_str(s).map(TzExt) + } +} + #[cfg(test)] mod tests { use super::*;