1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
use std::collections::HashMap;
use std::env;

use chrono::{DateTime, LocalResult, NaiveDateTime, TimeZone};
use chrono_tz::Tz;

use crate::error::CliResult;
use crate::error::Error::Custom;

#[derive(Clone)]
pub struct ChopperTz {
    timezone: Option<Tz>,
}

impl ChopperTz {
    pub fn new_from_cli_arg(
        cli_timezone_arg: Option<&str>,
        timezone_map: Option<HashMap<&str, Tz>>,
    ) -> ChopperTz {
        let timezone = Self::resolve_timezone(cli_timezone_arg, timezone_map);
        ChopperTz { timezone }
    }

    pub fn new_always_fails() -> ChopperTz {
        ChopperTz { timezone: None }
    }

    fn resolve_timezone(
        cli_timezone_arg: Option<&str>,
        timezone_map: Option<HashMap<&str, Tz>>,
    ) -> Option<Tz> {
        let timezone_arg = match cli_timezone_arg {
            None => match env::var("CHOPPER_TZ") {
                Ok(s) => Some(s),
                Err(_) => None,
            },
            Some(s) => Some(s.to_owned()),
        }?;

        let timezone: Tz = match timezone_map {
            None => timezone_arg.parse().unwrap(),
            Some(map) => match map.get(timezone_arg.as_str()) {
                None => timezone_arg.parse().unwrap(),
                Some(s) => *s,
            },
        };
        Some(timezone)
    }

    pub fn from_local_datetime(&self, local: &NaiveDateTime) -> CliResult<DateTime<Tz>> {
        match self.timezone {
            None => Err(Custom(format!(
                "Timezone is needed to parse a date/time value of '{}'. None was provided. \
                Either provide it by setting -z command line arg or by setting CHOPPER_TZ env var.",
                local
            ))),
            Some(timezone) => match timezone.from_local_datetime(local) {
                LocalResult::None | LocalResult::Ambiguous(_, _) => Err(Custom(format!(
                    "Converting '{}' in timezone '{}' to timestamp failed.",
                    local, timezone
                ))),
                LocalResult::Single(t) => Ok(t),
            },
        }
    }
}

impl From<Tz> for ChopperTz {
    fn from(original: Tz) -> Self {
        ChopperTz {
            timezone: Some(original),
        }
    }
}