"parse-zoneinfo",
]
+[[package]]
+name = "cloudabi"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467"
+dependencies = [
+ "bitflags",
+]
+
[[package]]
name = "console_error_panic_hook"
version = "0.1.6"
"libc",
]
+[[package]]
+name = "instant"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63312a18f7ea8760cdd0a7c5aac1a619752a246b833545e3e36d1f81f7cd9e66"
+dependencies = [
+ "cfg-if",
+]
+
[[package]]
name = "inventory"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743"
+[[package]]
+name = "lock_api"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28247cc5a5be2f05fbcd76dd0cf2c7d3b5400cb978a28042abcd4fa0b3f8261c"
+dependencies = [
+ "scopeguard",
+]
+
[[package]]
name = "log"
version = "0.3.9"
"num-traits",
"ordered-float",
"otter-zcoord",
+ "parking_lot",
"percent-encoding 2.1.0",
"pwd",
"rand",
"thiserror",
]
+[[package]]
+name = "parking_lot"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4893845fa2ca272e647da5d0e46660a314ead9c2fdd9a883aabc32e481a8733"
+dependencies = [
+ "instant",
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b"
+dependencies = [
+ "cfg-if",
+ "cloudabi",
+ "instant",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "winapi 0.3.9",
+]
+
[[package]]
name = "parse-zoneinfo"
version = "0.3.0"
"winapi-util",
]
+[[package]]
+name = "scopeguard"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+
[[package]]
name = "serde"
version = "1.0.116"
}
pub fn render(&self, tz: &Timezone) -> String {
- #[derive(Error,Debug)]
- enum E {
- #[from] SystemTime(SystemTimeError);
- #[from] Other(&'static str);
- };
-
- (||{
- let then = SytemTime::UNIX_EPOCH.checked_add(
- Duration::from_secs(tz.0)
- ).ok_or("SystemTime wrap error!")?;
- let elapsed = then.elapsed()?;
- if elapsed > 86400/2 {
-
- }
- let now = SystemTime::now();
- let elapsed = now.duration_since(then);
-
- None => format!("TS{}(@{:?})", self.0, tz)
+ let s = String::with_capacity(30);
+ tz.format(&mut s).unwrap();
+ s
}
}
--- /dev/null
+// Copyright 2020 Ian Jackson
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// There is NO WARRANTY.
+
+use crate::imports::*;
+
+use parking_lot::{RwLock, const_rwlock};
+
+#[derive(SerializeDisplay)]
+#[derive(DeserializeFromStr)]
+pub struct Timezone (Arc<dyn TimeFormatter>);
+
+pub trait TimeFormatter : Debug {
+ fn format(&self, ts: Timestamp, f: &mut Formatter) -> fmt::Result<()>;
+ fn name(&self) -> &str;
+}
+
+impl Display for Timezone {
+ fn fmt(&self, f: &mut Formatter) -> io::Result<()> {
+ write!(f, "{}", self.0.name())
+ }
+}
+
+#[derive(Clone,Debug,Default,Serialize,Deserialize)]
+struct ChronoTz<TZ: chrono::TimeZone> {
+ name: String,
+ ctz: TZ,
+}
+
+impl TimeFormatter<TZ: chrono::TimeZone> for ChronoTz<TZ> {
+ fn name(&self) -> &str { &self.name() }
+
+ #[throws(fmt::Result)]
+ fn format(&self, ts: Timestamp, f: &mut Formatter) {
+ write!(f, "TS{}(@{:?})", ts, &self);
+
+/* #[derive(Error,Debug)]
+ enum E {
+ #[from] SystemTime(SystemTimeError);
+ #[from] Other(&'static str);
+ };
+
+ (||{
+ let then = SytemTime::UNIX_EPOCH.checked_add(
+ Duration::from_secs(tz.0)
+ ).ok_or("SystemTime wrap error!")?;
+ let elapsed = then.elapsed()?;
+ if elapsed > 86400/2 {
+
+ }
+ let now = SystemTime::now();
+ let elapsed = now.duration_since(then);
+
+ None => format!("TS{}(@{:?})", self.0, tz)
+ }
+*/
+
+ }
+}
+
+static memo: RwLock<Option<HashMap<String, Timezone>>> = const_rwlock(None);
+
+impl FromStr for Timezone {
+ fn from_str(name: &str) -> Self {
+ let get = |memor,s| memor?.get(name).map(Clone::clone);
+ if let Some(got) = get(memo.read(), s) { return got }
+
+ // slow path
+ let memow = memo.write();
+ if let Some(got) = get(memow, s) { return got }
+
+ // really slow path
+ let name = name.to_string();
+ let out = match chrono_tz::Tz::from_str(name) {
+ Ok(ctz) => {
+ Arc::new(ChronoTz { ctz, name })
+ },
+ Err(emsg) => {
+ error!("Error loading timezone {:?}: {}, using UTC", name, emsg);
+ let ctz = chrono::offset::Utc;
+ Arc::new(ChroniTz { ctz, name })
+ },
+ };
+ meow.get_or_insert_with(default)
+ .set(name.to_string(), r.clone());
+ out
+ }
+}