Add the status application
This commit is contained in:
parent
3c57becd17
commit
3a82cd229d
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,7 @@
|
||||||
|
[workspace]
|
||||||
|
members = [
|
||||||
|
"cachememory",
|
||||||
|
"geo-types",
|
||||||
|
"fluent-ergonomics",
|
||||||
|
"status",
|
||||||
|
]
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,26 @@
|
||||||
|
[package]
|
||||||
|
name = "reports"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
|
chrono-tz = { version = "0.6" }
|
||||||
|
fluent = { version = "0.16" }
|
||||||
|
fluent-ergonomics = { path = "../fluent-ergonomics/" }
|
||||||
|
futures = { version = "0.3" }
|
||||||
|
geo-types = { path = "../geo-types/" }
|
||||||
|
lazy_static = { version = "1.4" }
|
||||||
|
unic-langid = { version = "0.9" }
|
||||||
|
http = { version = "*" }
|
||||||
|
international-fixed-calendar = { path = "../ifc" }
|
||||||
|
cachememory = { path = "../cachememory" }
|
||||||
|
reqwest = { version = "0.11", features = ["json"] }
|
||||||
|
serde_derive = { version = "1" }
|
||||||
|
serde_json = { version = "1" }
|
||||||
|
serde = { version = "1" }
|
||||||
|
svg = { version = "0.10" }
|
||||||
|
tokio = { version = "1", features = ["full"] }
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
dev:
|
||||||
|
cargo watch -x build
|
||||||
|
|
||||||
|
test:
|
||||||
|
cargo watch -x test
|
||||||
|
|
||||||
|
test-once:
|
||||||
|
cargo test
|
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
|
@ -0,0 +1,84 @@
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
|
|
||||||
|
mod moon;
|
||||||
|
|
||||||
|
mod solar_client;
|
||||||
|
use solar_client::{SunMoon, SunMoonClient};
|
||||||
|
|
||||||
|
mod solstices;
|
||||||
|
use solstices::{Event, Solstices};
|
||||||
|
|
||||||
|
const EO_TEXT: &'static str = "
|
||||||
|
day = {$day ->
|
||||||
|
*[Sunday] Dimanĉo
|
||||||
|
[Monday] Lundo
|
||||||
|
[Tuesday] Mardo
|
||||||
|
[Wednesday] Merkredo
|
||||||
|
[Thursday] Ĵaŭdo
|
||||||
|
[Friday] Vendredo
|
||||||
|
[Saturday] Sabato
|
||||||
|
[LeapDay] Leap Day
|
||||||
|
[YearDay] Year Day
|
||||||
|
}
|
||||||
|
month = {$month ->
|
||||||
|
*[January] Januaro
|
||||||
|
[February] Februaro
|
||||||
|
[March] Marto
|
||||||
|
[April] Aprilo
|
||||||
|
[May] Mayo
|
||||||
|
[June] Junio
|
||||||
|
[Sol] Solo
|
||||||
|
[July] Julio
|
||||||
|
[August] Aŭgusto
|
||||||
|
[September] Septembro
|
||||||
|
[October] Oktobro
|
||||||
|
[November] Novembro
|
||||||
|
[December] Decembro
|
||||||
|
}
|
||||||
|
spring_equinox = Spring Equinox
|
||||||
|
summer_solstice = Summer Solstice
|
||||||
|
autumn_equinox = Autumn Equinox
|
||||||
|
winter_solstice = Winter Solstice
|
||||||
|
";
|
||||||
|
|
||||||
|
/*
|
||||||
|
#[tokio::main]
|
||||||
|
pub async fn main() {
|
||||||
|
let latitudo = Latitudo::from(41.78);
|
||||||
|
let longitudo = Longitudo::from(-71.41);
|
||||||
|
let eo_id = "eo".parse::<unic_langid::LanguageIdentifier>().unwrap();
|
||||||
|
let mut fluent = fluent_ergonomics::FluentErgo::new(&[eo_id.clone()]);
|
||||||
|
let solar_client = Arc::new(SolunaKliento::kreu());
|
||||||
|
|
||||||
|
fluent.add_from_text(eo_id, EO_TEXT.to_owned()).unwrap();
|
||||||
|
let fluent = Arc::new(fluent);
|
||||||
|
|
||||||
|
let paĝvojo = {
|
||||||
|
warp::path::end().and_then(move || {
|
||||||
|
paĝo(
|
||||||
|
fluent.clone(),
|
||||||
|
solar_client.clone(),
|
||||||
|
latitudo.clone(),
|
||||||
|
longitudo.clone(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
let luna_vojo = { warp::path::path("luna").and_then(move || lunpaĝo()) };
|
||||||
|
|
||||||
|
let server = warp::serve(paĝvojo.or(luna_vojo));
|
||||||
|
server
|
||||||
|
.run(SocketAddr::new(
|
||||||
|
IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
|
||||||
|
8000,
|
||||||
|
))
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
panic!("no main function: moving from the web app to a GTK app");
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
use svg::{
|
||||||
|
node::element::{Circle, Image},
|
||||||
|
Document,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn moon() -> Document {
|
||||||
|
/*
|
||||||
|
svg(width="100%", height="100%", xmlns="http://www.w3.org/2000/svg") {
|
||||||
|
circle(cx="50", cy="50", r="50", stroke="green", fill="none");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
let img = Image::new().set("href", "/moon-small.png");
|
||||||
|
Document::new().add(img)
|
||||||
|
}
|
|
@ -0,0 +1,151 @@
|
||||||
|
// 41.78, -71.41
|
||||||
|
// https://api.solunar.org/solunar/41.78,-71.41,20211029,-4
|
||||||
|
|
||||||
|
use cachememory::Cache;
|
||||||
|
use chrono::{Date, DateTime, Duration, NaiveTime, Offset, Timelike, Utc};
|
||||||
|
use chrono_tz::Tz;
|
||||||
|
use geo_types::{Latitude, Longitude};
|
||||||
|
use reqwest;
|
||||||
|
|
||||||
|
const ENDPOINT: &str = "https://api.solunar.org/solunar";
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct SunMoon {
|
||||||
|
pub sunrise: DateTime<Tz>,
|
||||||
|
pub sunset: DateTime<Tz>,
|
||||||
|
pub moonrise: Option<DateTime<Tz>>,
|
||||||
|
pub moonset: Option<DateTime<Tz>>,
|
||||||
|
pub moonphase: MoonPhase,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SunMoon {
|
||||||
|
fn from_js(day: Date<Tz>, val: SunMoonJs) -> Self {
|
||||||
|
fn kreu_tempo(day: Date<Tz>, val: String) -> Option<DateTime<Tz>> {
|
||||||
|
NaiveTime::parse_from_str(&val, "%H:%M")
|
||||||
|
.map(|tempo| day.and_hms(tempo.hour(), tempo.minute(), 0))
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
let sunrise = kreu_tempo(day.clone(), val.sunrise).unwrap();
|
||||||
|
let sunset = kreu_tempo(day.clone(), val.sunset).unwrap();
|
||||||
|
let moonrise = val.moonrise.and_then(|v| kreu_tempo(day.clone(), v));
|
||||||
|
let moonset = val.moonset.and_then(|v| kreu_tempo(day.clone(), v));
|
||||||
|
|
||||||
|
Self {
|
||||||
|
sunrise,
|
||||||
|
sunset,
|
||||||
|
moonrise,
|
||||||
|
moonset,
|
||||||
|
moonphase: val.moonphase,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
|
pub(crate) struct SunMoonJs {
|
||||||
|
#[serde(alias = "sunRise")]
|
||||||
|
sunrise: String,
|
||||||
|
#[serde(alias = "sunSet")]
|
||||||
|
sunset: String,
|
||||||
|
#[serde(alias = "moonRise")]
|
||||||
|
moonrise: Option<String>,
|
||||||
|
#[serde(alias = "moonSet")]
|
||||||
|
moonset: Option<String>,
|
||||||
|
#[serde(alias = "moonPhase")]
|
||||||
|
moonphase: MoonPhase,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
||||||
|
pub enum MoonPhase {
|
||||||
|
#[serde(alias = "New Moon")]
|
||||||
|
NewMoon,
|
||||||
|
#[serde(alias = "Waxing Crescent")]
|
||||||
|
WaxingCrescent,
|
||||||
|
#[serde(alias = "First Quarter")]
|
||||||
|
FirstQuarter,
|
||||||
|
#[serde(alias = "Waxing Gibbous")]
|
||||||
|
WaxingGibbous,
|
||||||
|
#[serde(alias = "Full Moon")]
|
||||||
|
FullMoon,
|
||||||
|
#[serde(alias = "Waning Gibbous")]
|
||||||
|
WaningGibbous,
|
||||||
|
#[serde(alias = "Last Quarter")]
|
||||||
|
LastQuarter,
|
||||||
|
#[serde(alias = "Waning Crescent")]
|
||||||
|
WaningCrescent,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SunMoonClient {
|
||||||
|
client: reqwest::Client,
|
||||||
|
cache: Cache<SunMoonJs>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SunMoonClient {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
client: reqwest::Client::new(),
|
||||||
|
cache: Cache::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn demandu(
|
||||||
|
&self,
|
||||||
|
latitude: Latitude,
|
||||||
|
longitude: Longitude,
|
||||||
|
day: Date<Tz>,
|
||||||
|
) -> SunMoon {
|
||||||
|
let date = day.format("%Y%m%d");
|
||||||
|
let url = format!(
|
||||||
|
"{}/{},{},{},{}",
|
||||||
|
ENDPOINT,
|
||||||
|
latitude,
|
||||||
|
longitude,
|
||||||
|
date,
|
||||||
|
day.offset().fix().local_minus_utc() / 3600
|
||||||
|
);
|
||||||
|
let js = self
|
||||||
|
.cache
|
||||||
|
.find(&url, async {
|
||||||
|
let response = self.client.get(&url).send().await.unwrap();
|
||||||
|
let tempolimo = response
|
||||||
|
.headers()
|
||||||
|
.get(reqwest::header::EXPIRES)
|
||||||
|
.and_then(|header| header.to_str().ok())
|
||||||
|
.and_then(|tempolimo_str| DateTime::parse_from_rfc2822(tempolimo_str).ok())
|
||||||
|
.map(|dt_local| DateTime::<Utc>::from(dt_local))
|
||||||
|
.unwrap_or(Utc::now() + Duration::seconds(3600));
|
||||||
|
let soluna: SunMoonJs = response.json().await.unwrap();
|
||||||
|
(tempolimo, soluna)
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
SunMoon::from_js(day, js)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use chrono::TimeZone;
|
||||||
|
use chrono_tz::America::New_York;
|
||||||
|
use serde_json;
|
||||||
|
|
||||||
|
const EXAMPLE: &str = "{\"sunRise\":\"7:15\",\"sunTransit\":\"12:30\",\"sunSet\":\"17:45\",\"moonRise\":null,\"moonTransit\":\"7:30\",\"moonUnder\":\"19:54\",\"moonSet\":\"15:02\",\"moonPhase\":\"Waning Crescent\",\"moonIllumination\":0.35889454647387764,\"sunRiseDec\":7.25,\"sunTransitDec\":12.5,\"sunSetDec\":17.75,\"moonRiseDec\":null,\"moonSetDec\":15.033333333333333,\"moonTransitDec\":7.5,\"moonUnderDec\":19.9,\"minor1Start\":null,\"minor1Stop\":null,\"minor2StartDec\":14.533333333333333,\"minor2Start\":\"14:32\",\"minor2StopDec\":15.533333333333333,\"minor2Stop\":\"15:32\",\"major1StartDec\":6.5,\"major1Start\":\"06:30\",\"major1StopDec\":8.5,\"major1Stop\":\"08:30\",\"major2StartDec\":18.9,\"major2Start\":\"18:54\",\"major2StopDec\":20.9,\"major2Stop\":\"20:54\",\"dayRating\":1,\"hourlyRating\":{\"0\":20,\"1\":20,\"2\":0,\"3\":0,\"4\":0,\"5\":0,\"6\":20,\"7\":40,\"8\":40,\"9\":20,\"10\":0,\"11\":0,\"12\":0,\"13\":0,\"14\":0,\"15\":20,\"16\":20,\"17\":20,\"18\":40,\"19\":20,\"20\":20,\"21\":20,\"22\":0,\"23\":0}}";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn it_parses_a_response() {
|
||||||
|
let day = New_York.ymd(2021, 10, 29);
|
||||||
|
let sun_moon_js: SunMoonJs = serde_json::from_str(EXAMPLE).unwrap();
|
||||||
|
let sun_moon = SunMoon::from_js(day.clone(), sun_moon_js);
|
||||||
|
assert_eq!(
|
||||||
|
sun_moon,
|
||||||
|
SunMoon {
|
||||||
|
sunrise: day.and_hms(7, 15, 0),
|
||||||
|
sunset: day.and_hms(17, 45, 0),
|
||||||
|
moonrise: None,
|
||||||
|
moonset: Some(day.and_hms(15, 02, 0)),
|
||||||
|
moonphase: MoonPhase::WaningCrescent,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,179 @@
|
||||||
|
use chrono;
|
||||||
|
use chrono::prelude::*;
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use serde_json;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
// http://astropixels.com/ephemeris/soleq2001.html
|
||||||
|
const SOLSTICE_TABLE: &'static str = "
|
||||||
|
2001 Mar 20 13:31 Jun 21 07:38 Sep 22 23:05 Dec 21 19:22
|
||||||
|
2002 Mar 20 19:16 Jun 21 13:25 Sep 23 04:56 Dec 22 01:15
|
||||||
|
2003 Mar 21 01:00 Jun 21 19:11 Sep 23 10:47 Dec 22 07:04
|
||||||
|
2004 Mar 20 06:49 Jun 21 00:57 Sep 22 16:30 Dec 21 12:42
|
||||||
|
2005 Mar 20 12:34 Jun 21 06:46 Sep 22 22:23 Dec 21 18:35
|
||||||
|
2006 Mar 20 18:25 Jun 21 12:26 Sep 23 04:04 Dec 22 00:22
|
||||||
|
2007 Mar 21 00:07 Jun 21 18:06 Sep 23 09:51 Dec 22 06:08
|
||||||
|
2008 Mar 20 05:49 Jun 21 00:00 Sep 22 15:45 Dec 21 12:04
|
||||||
|
2009 Mar 20 11:44 Jun 21 05:45 Sep 22 21:18 Dec 21 17:47
|
||||||
|
2010 Mar 20 17:32 Jun 21 11:28 Sep 23 03:09 Dec 21 23:38
|
||||||
|
|
||||||
|
2011 Mar 20 23:21 Jun 21 17:16 Sep 23 09:05 Dec 22 05:30
|
||||||
|
2012 Mar 20 05:15 Jun 20 23:08 Sep 22 14:49 Dec 21 11:12
|
||||||
|
2013 Mar 20 11:02 Jun 21 05:04 Sep 22 20:44 Dec 21 17:11
|
||||||
|
2014 Mar 20 16:57 Jun 21 10:52 Sep 23 02:30 Dec 21 23:03
|
||||||
|
2015 Mar 20 22:45 Jun 21 16:38 Sep 23 08:20 Dec 22 04:48
|
||||||
|
2016 Mar 20 04:31 Jun 20 22:35 Sep 22 14:21 Dec 21 10:45
|
||||||
|
2017 Mar 20 10:29 Jun 21 04:25 Sep 22 20:02 Dec 21 16:29
|
||||||
|
2018 Mar 20 16:15 Jun 21 10:07 Sep 23 01:54 Dec 21 22:22
|
||||||
|
2019 Mar 20 21:58 Jun 21 15:54 Sep 23 07:50 Dec 22 04:19
|
||||||
|
2020 Mar 20 03:50 Jun 20 21:43 Sep 22 13:31 Dec 21 10:03
|
||||||
|
|
||||||
|
2021 Mar 20 09:37 Jun 21 03:32 Sep 22 19:21 Dec 21 15:59
|
||||||
|
2022 Mar 20 15:33 Jun 21 09:14 Sep 23 01:04 Dec 21 21:48
|
||||||
|
2023 Mar 20 21:25 Jun 21 14:58 Sep 23 06:50 Dec 22 03:28
|
||||||
|
2024 Mar 20 03:07 Jun 20 20:51 Sep 22 12:44 Dec 21 09:20
|
||||||
|
2025 Mar 20 09:02 Jun 21 02:42 Sep 22 18:20 Dec 21 15:03
|
||||||
|
2026 Mar 20 14:46 Jun 21 08:25 Sep 23 00:06 Dec 21 20:50
|
||||||
|
2027 Mar 20 20:25 Jun 21 14:11 Sep 23 06:02 Dec 22 02:43
|
||||||
|
2028 Mar 20 02:17 Jun 20 20:02 Sep 22 11:45 Dec 21 08:20
|
||||||
|
2029 Mar 20 08:01 Jun 21 01:48 Sep 22 17:37 Dec 21 14:14
|
||||||
|
2030 Mar 20 13:51 Jun 21 07:31 Sep 22 23:27 Dec 21 20:09
|
||||||
|
|
||||||
|
2031 Mar 20 19:41 Jun 21 13:17 Sep 23 05:15 Dec 22 01:56
|
||||||
|
2032 Mar 20 01:23 Jun 20 19:09 Sep 22 11:11 Dec 21 07:57
|
||||||
|
2033 Mar 20 07:23 Jun 21 01:01 Sep 22 16:52 Dec 21 13:45
|
||||||
|
2034 Mar 20 13:18 Jun 21 06:45 Sep 22 22:41 Dec 21 19:35
|
||||||
|
2035 Mar 20 19:03 Jun 21 12:33 Sep 23 04:39 Dec 22 01:31
|
||||||
|
2036 Mar 20 01:02 Jun 20 18:31 Sep 22 10:23 Dec 21 07:12
|
||||||
|
2037 Mar 20 06:50 Jun 21 00:22 Sep 22 16:13 Dec 21 13:08
|
||||||
|
2038 Mar 20 12:40 Jun 21 06:09 Sep 22 22:02 Dec 21 19:01
|
||||||
|
2039 Mar 20 18:32 Jun 21 11:58 Sep 23 03:50 Dec 22 00:41
|
||||||
|
2040 Mar 20 00:11 Jun 20 17:46 Sep 22 09:44 Dec 21 06:33
|
||||||
|
|
||||||
|
2041 Mar 20 06:07 Jun 20 23:37 Sep 22 15:27 Dec 21 12:19
|
||||||
|
2042 Mar 20 11:53 Jun 21 05:16 Sep 22 21:11 Dec 21 18:04
|
||||||
|
2043 Mar 20 17:29 Jun 21 10:59 Sep 23 03:07 Dec 22 00:02
|
||||||
|
2044 Mar 19 23:20 Jun 20 16:50 Sep 22 08:47 Dec 21 05:43
|
||||||
|
2045 Mar 20 05:08 Jun 20 22:34 Sep 22 14:33 Dec 21 11:36
|
||||||
|
2046 Mar 20 10:58 Jun 21 04:15 Sep 22 20:22 Dec 21 17:28
|
||||||
|
2047 Mar 20 16:52 Jun 21 10:02 Sep 23 02:07 Dec 21 23:07
|
||||||
|
2048 Mar 19 22:34 Jun 20 15:54 Sep 22 08:01 Dec 21 05:02
|
||||||
|
2049 Mar 20 04:28 Jun 20 21:47 Sep 22 13:42 Dec 21 10:51
|
||||||
|
2050 Mar 20 10:20 Jun 21 03:33 Sep 22 19:29 Dec 21 16:39
|
||||||
|
";
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct YearlyEvents {
|
||||||
|
pub year: i32,
|
||||||
|
pub spring_equinox: chrono::DateTime<chrono::Utc>,
|
||||||
|
pub summer_solstice: chrono::DateTime<chrono::Utc>,
|
||||||
|
pub autumn_equinox: chrono::DateTime<chrono::Utc>,
|
||||||
|
pub winter_solstice: chrono::DateTime<chrono::Utc>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||||
|
pub enum Event {
|
||||||
|
SpringEquinox(chrono::DateTime<chrono::Utc>),
|
||||||
|
SummerSolstice(chrono::DateTime<chrono::Utc>),
|
||||||
|
AutumnEquinox(chrono::DateTime<chrono::Utc>),
|
||||||
|
WinterSolstice(chrono::DateTime<chrono::Utc>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Event {
|
||||||
|
pub fn date(&self) -> chrono::DateTime<chrono::Utc> {
|
||||||
|
match *self {
|
||||||
|
Event::SpringEquinox(d) => d,
|
||||||
|
Event::SummerSolstice(d) => d,
|
||||||
|
Event::AutumnEquinox(d) => d,
|
||||||
|
Event::WinterSolstice(d) => d,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_text<'a>(
|
||||||
|
year: &str,
|
||||||
|
iter: impl Iterator<Item = &'a str>,
|
||||||
|
) -> chrono::DateTime<chrono::Utc> {
|
||||||
|
let partoj = iter.collect::<Vec<&str>>();
|
||||||
|
let p = format!("{} {} {} {}", year, partoj[0], partoj[1], partoj[2]);
|
||||||
|
chrono::Utc.datetime_from_str(&p, "%Y %b %d %H:%M").unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_line(year: &str, resto: &[&str]) -> YearlyEvents {
|
||||||
|
let spring = parse_text(year, resto.iter().take(3).cloned());
|
||||||
|
let summer = parse_text(year, resto.iter().skip(3).take(3).cloned());
|
||||||
|
let autumn = parse_text(year, resto.iter().skip(6).take(3).cloned());
|
||||||
|
let winter = parse_text(year, resto.iter().skip(9).take(3).cloned());
|
||||||
|
YearlyEvents {
|
||||||
|
year: year.parse::<i32>().unwrap(),
|
||||||
|
spring_equinox: spring,
|
||||||
|
summer_solstice: summer,
|
||||||
|
autumn_equinox: autumn,
|
||||||
|
winter_solstice: winter,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_table() -> Vec<Option<YearlyEvents>> {
|
||||||
|
SOLSTICE_TABLE
|
||||||
|
.lines()
|
||||||
|
.map(|line| {
|
||||||
|
match line
|
||||||
|
.split(" ")
|
||||||
|
.filter(|elem| !elem.is_empty())
|
||||||
|
.collect::<Vec<&str>>()
|
||||||
|
.as_slice()
|
||||||
|
{
|
||||||
|
[year, rest @ ..] => Some(parse_line(year, rest)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Solstices(HashMap<i32, YearlyEvents>);
|
||||||
|
|
||||||
|
impl Solstices {
|
||||||
|
pub fn get_events(&self, year: i32) -> Option<YearlyEvents> {
|
||||||
|
self.0.get(&year).map(|c| c.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next_event(&self, date: chrono::DateTime<chrono::Utc>) -> Option<Event> {
|
||||||
|
let yearly_events = self.0.get(&date.year());
|
||||||
|
match yearly_events {
|
||||||
|
Some(yearly_events) => {
|
||||||
|
if date <= yearly_events.spring_equinox {
|
||||||
|
Some(Event::SpringEquinox(yearly_events.spring_equinox.clone()))
|
||||||
|
} else if date <= yearly_events.summer_solstice {
|
||||||
|
Some(Event::SummerSolstice(yearly_events.summer_solstice.clone()))
|
||||||
|
} else if date <= yearly_events.autumn_equinox {
|
||||||
|
Some(Event::AutumnEquinox(yearly_events.autumn_equinox.clone()))
|
||||||
|
} else if date <= yearly_events.winter_solstice {
|
||||||
|
Some(Event::WinterSolstice(yearly_events.winter_solstice.clone()))
|
||||||
|
} else {
|
||||||
|
self.0
|
||||||
|
.get(&(date.year() + 1))
|
||||||
|
.map(|events| Event::SpringEquinox(events.spring_equinox.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<Option<YearlyEvents>>> for Solstices {
|
||||||
|
fn from(entry: Vec<Option<YearlyEvents>>) -> Self {
|
||||||
|
Solstices(entry.iter().fold(HashMap::new(), |mut m, record| {
|
||||||
|
match record {
|
||||||
|
Some(record) => {
|
||||||
|
m.insert(record.year, record.clone());
|
||||||
|
}
|
||||||
|
None => (),
|
||||||
|
}
|
||||||
|
m
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref EVENTOJ: Solstices = Solstices::from(parse_table());
|
||||||
|
}
|
Loading…
Reference in New Issue