Skip to main content

rtzlib/
shared.rs

1//! Shared functionality for the `rtz` crate.
2
3#[cfg(any(feature = "admin-osm", feature = "tz-ned", feature = "tz-osm"))]
4use serde::{Deserialize, Serialize};
5
6#[cfg(feature = "web")]
7use utoipa::ToSchema;
8
9#[cfg(feature = "wasm")]
10use tsify::Tsify;
11
12#[cfg(feature = "admin-osm")]
13use rtz_core::geo::admin::osm::OsmAdmin;
14#[cfg(feature = "tz-ned")]
15use rtz_core::geo::tz::ned::NedTimezone;
16#[cfg(feature = "tz-osm")]
17use rtz_core::geo::tz::osm::OsmTimezone;
18
19/// The response type for the NED timezone endpoint when found.
20///
21/// Currently ingested version of this data set is [here](https://github.com/nvkelso/natural-earth-vector/blob/master/geojson/ne_10m_time_zones.geojson).
22#[cfg(feature = "tz-ned")]
23#[derive(Debug, Serialize, Deserialize)]
24#[cfg_attr(feature = "web", derive(ToSchema))]
25#[cfg_attr(feature = "wasm", derive(Tsify))]
26#[serde(rename_all = "camelCase")]
27pub struct NedTimezoneResponse1 {
28    /// The index of this timezone in the global static cache.
29    ///
30    /// This is not stable across builds or new data sets.  It is merely unique during a single build.
31    pub id: usize,
32    /// The IANA time zone identifier (e.g., `America/Los_Angeles`).
33    pub identifier: Option<&'static str>,
34
35    /// The countries and regions this zone covers.
36    pub description: &'static str,
37    /// The daylight savings time information for this zone.
38    pub dst_description: Option<&'static str>,
39
40    /// The UTC offset in display form (e.g., `UTC-8:00`).
41    pub offset: &'static str,
42
43    /// The UTC offset in hours (e.g., `-8`).
44    pub zone: f32,
45    /// The UTC offset in seconds (e.g., `-28800`).
46    pub raw_offset: i32,
47}
48
49#[cfg(feature = "tz-ned")]
50impl From<&'static NedTimezone> for NedTimezoneResponse1 {
51    fn from(value: &'static NedTimezone) -> NedTimezoneResponse1 {
52        NedTimezoneResponse1 {
53            id: value.id,
54            identifier: value.identifier.as_deref(),
55            description: value.description.as_ref(),
56            dst_description: value.dst_description.as_deref(),
57            offset: value.offset.as_ref(),
58            zone: value.zone,
59            raw_offset: value.raw_offset,
60        }
61    }
62}
63
64/// The response type for the OSM timezone endpoint when found.
65///
66/// Currently ingested version of this data set is [here](https://github.com/evansiroky/timezone-boundary-builder/releases/download/2023b/timezones-with-oceans.geojson.zip).
67#[cfg(feature = "tz-osm")]
68#[derive(Debug, Serialize, Deserialize)]
69#[cfg_attr(feature = "web", derive(ToSchema))]
70#[cfg_attr(feature = "wasm", derive(Tsify))]
71#[serde(rename_all = "camelCase")]
72pub struct OsmTimezoneResponse1 {
73    /// The index of this timezone in the global static cache.
74    ///
75    /// This is not stable across builds or new data sets.  It is merely unique during a single build.
76    pub id: usize,
77    /// The IANA time zone identifier (e.g., `America/Los_Angeles`).
78    pub identifier: &'static str,
79    /// The abbreviated name of the offset currently in effect (e.g., `PDT`).
80    pub short_identifier: String,
81
82    /// The current UTC offset in display form (e.g., `UTC-8:00`).
83    pub offset: String,
84
85    /// The current UTC offset in seconds, including any daylight savings adjustment (e.g., `-28800`).
86    pub raw_offset: i32,
87    /// The standard UTC offset in seconds, excluding daylight savings (e.g., `-28800`).
88    pub raw_base_offset: i32,
89    /// The daylight savings adjustment in seconds, or `0` when it is not in effect.
90    pub raw_dst_offset: i32,
91
92    /// The current UTC offset in hours (e.g., `-8`).
93    pub zone: f32,
94
95    /// The current time in this timezone, as an RFC 3339 timestamp.
96    pub current_time: String,
97}
98
99#[cfg(feature = "tz-osm")]
100impl From<&'static OsmTimezone> for OsmTimezoneResponse1 {
101    fn from(value: &'static OsmTimezone) -> OsmTimezoneResponse1 {
102        use chrono::{Offset, Utc};
103        use chrono_tz::{OffsetComponents, Tz};
104
105        let tz: Tz = value.identifier.parse().unwrap();
106        let time = Utc::now().with_timezone(&tz);
107        let tz_offset = time.offset();
108        let fixed_offset = tz_offset.fix();
109
110        let short_identifier = tz_offset.to_string();
111
112        let offset = format!("UTC{}", fixed_offset);
113        let raw_offset = fixed_offset.local_minus_utc();
114        let raw_base_offset = tz_offset.base_utc_offset().num_seconds() as i32;
115        let raw_dst_offset = tz_offset.dst_offset().num_seconds() as i32;
116
117        let zone = raw_offset as f32 / 3600.0;
118
119        let current_time = time.to_rfc3339();
120
121        OsmTimezoneResponse1 {
122            id: value.id,
123            identifier: value.identifier.as_ref(),
124            short_identifier,
125            offset,
126            raw_offset,
127            raw_base_offset,
128            raw_dst_offset,
129            zone,
130            current_time,
131        }
132    }
133}
134
135/// The response type for the OSM admin endpoint when found.
136///
137/// Results are returned broadest-first: ascending by `level`, so a point inside nested areas
138/// yields the containment hierarchy in order (country, then state, then county, then city).
139///
140/// Currently ingested version of this data set is [here](https://planet.openstreetmap.org/).
141#[cfg(feature = "admin-osm")]
142#[derive(Debug, Serialize, Deserialize)]
143#[cfg_attr(feature = "web", derive(ToSchema))]
144#[cfg_attr(feature = "wasm", derive(Tsify))]
145#[serde(rename_all = "camelCase")]
146pub struct OsmAdminResponse1 {
147    /// The index of this admin area in the global static cache.
148    ///
149    /// This is not stable across builds or new data sets.  It is merely unique during a single build.
150    pub id: usize,
151
152    /// The OSM relation id of the admin area (e.g., `1473947`), or `null` if the source boundary
153    /// was not relation-backed.  Unlike `id`, this is stable across builds.
154    pub relation_id: Option<u64>,
155
156    /// The name of the admin area (e.g., `France`).
157    pub name: &'static str,
158
159    /// The OSM admin level of the area (e.g., `2` for a country).
160    pub level: usize,
161}
162
163#[cfg(feature = "admin-osm")]
164impl From<&'static OsmAdmin> for OsmAdminResponse1 {
165    fn from(value: &'static OsmAdmin) -> OsmAdminResponse1 {
166        OsmAdminResponse1 {
167            id: value.id,
168            relation_id: (value.relation_id != 0).then_some(value.relation_id),
169            name: value.name.as_ref(),
170            level: value.level,
171        }
172    }
173}