• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

baoyachi / shadow-rs / 12340312732

15 Dec 2024 04:05PM UTC coverage: 26.52% (+2.2%) from 24.368%
12340312732

push

github

web-flow
Merge pull request #195 from baoyachi/builder

Add ShadowBuilder build shadow

49 of 97 new or added lines in 2 files covered. (50.52%)

722 existing lines in 3 files now uncovered.

641 of 2417 relevant lines covered (26.52%)

0.39 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.67
/src/date_time.rs
1
use crate::{Format, SdResult, ShadowError};
2
use std::error::Error;
3
use time::format_description::well_known::{Rfc2822, Rfc3339};
4
#[cfg(feature = "tzdb")]
5
use time::UtcOffset;
6
use time::{format_description, OffsetDateTime};
7

8
pub enum DateTime {
9
    Local(OffsetDateTime),
10
    Utc(OffsetDateTime),
11
}
12

13
pub fn now_date_time() -> DateTime {
1✔
14
    // Enable reproducibility for uses of `now_date_time` by respecting the
15
    // `SOURCE_DATE_EPOCH` env variable.
16
    //
17
    // https://reproducible-builds.org/docs/source-date-epoch/
18
    match std::env::var_os("SOURCE_DATE_EPOCH") {
1✔
UNCOV
19
        None => DateTime::now(),
×
20
        Some(timestamp) => {
1✔
21
            let epoch = timestamp
2✔
22
                .into_string()
23
                .expect("Input SOURCE_DATE_EPOCH could not be parsed")
24
                .parse::<i64>()
25
                .expect("Input SOURCE_DATE_EPOCH could not be cast to a number");
26
            DateTime::Utc(OffsetDateTime::from_unix_timestamp(epoch).unwrap())
2✔
27
        }
28
    }
29
}
30

31
impl Default for DateTime {
32
    fn default() -> Self {
×
33
        Self::now()
×
34
    }
35
}
36

37
impl DateTime {
38
    pub fn now() -> Self {
1✔
39
        Self::local_now().unwrap_or_else(|_| DateTime::Utc(OffsetDateTime::now_utc()))
1✔
40
    }
41

42
    pub fn offset_datetime() -> OffsetDateTime {
×
43
        let date_time = Self::now();
×
44
        match date_time {
×
45
            DateTime::Local(time) | DateTime::Utc(time) => time,
×
46
        }
47
    }
48

49
    #[cfg(not(feature = "tzdb"))]
50
    pub fn local_now() -> Result<Self, Box<dyn Error>> {
×
51
        // Warning: This attempts to create a new OffsetDateTime with the current date and time in the local offset, which may fail.
52
        // Currently, it always fails on MacOS.
53
        // This issue does not exist with the "tzdb" feature (see below), which should be used instead.
54
        OffsetDateTime::now_local()
×
55
            .map(DateTime::Local)
×
56
            .map_err(|e| e.into())
×
57
    }
58

59
    #[cfg(feature = "tzdb")]
60
    pub fn local_now() -> Result<Self, Box<dyn Error>> {
1✔
61
        let local_time = tzdb::now::local()?;
1✔
62
        let time_zone_offset =
2✔
63
            UtcOffset::from_whole_seconds(local_time.local_time_type().ut_offset())?;
×
64
        let local_date_time = OffsetDateTime::from_unix_timestamp(local_time.unix_time())?
2✔
65
            .to_offset(time_zone_offset);
×
66
        Ok(DateTime::Local(local_date_time))
1✔
67
    }
68

69
    pub fn timestamp_2_utc(time_stamp: i64) -> SdResult<Self> {
1✔
70
        let time = OffsetDateTime::from_unix_timestamp(time_stamp).map_err(ShadowError::new)?;
1✔
71
        Ok(DateTime::Utc(time))
1✔
72
    }
73

74
    pub fn to_rfc2822(&self) -> String {
1✔
75
        match self {
2✔
76
            DateTime::Local(dt) | DateTime::Utc(dt) => dt.format(&Rfc2822).unwrap_or_default(),
2✔
77
        }
78
    }
79

80
    pub fn to_rfc3339(&self) -> String {
1✔
81
        match self {
1✔
82
            DateTime::Local(dt) | DateTime::Utc(dt) => dt.format(&Rfc3339).unwrap_or_default(),
1✔
83
        }
84
    }
85
}
86

87
impl Format for DateTime {
88
    fn human_format(&self) -> String {
1✔
89
        match self {
2✔
90
            DateTime::Local(dt) | DateTime::Utc(dt) => dt.human_format(),
2✔
91
        }
92
    }
93
}
94

95
impl Format for OffsetDateTime {
96
    fn human_format(&self) -> String {
1✔
97
        let fmt = format_description::parse(
98
            "[year]-[month]-[day] [hour]:[minute]:[second] [offset_hour \
99
         sign:mandatory]:[offset_minute]",
100
        )
101
        .unwrap();
102
        self.format(&fmt).unwrap()
1✔
103
    }
104
}
105

106
#[cfg(test)]
107
mod tests {
108
    use super::*;
109
    use human_format_validate::parse_human_format;
110

111
    mod human_format_validate {
112
        use std::num::{NonZeroU32, NonZeroU8};
113
        use winnow::ascii::{digit1, space1};
114
        use winnow::error::{ContextError, ParseError};
115
        use winnow::token::{literal, take};
116
        use winnow::{PResult, Parser};
117

118
        fn u8_len2(input: &mut &str) -> PResult<u8> {
1✔
119
            take(2_usize).try_map(str::parse).parse_next(input)
120
        }
121

122
        fn non_zero_u8_len2<const LIMIT: u8>(input: &mut &str) -> PResult<NonZeroU8> {
2✔
123
            take(2_usize)
124
                .try_map(str::parse)
125
                .verify(|x| *x <= unsafe { NonZeroU8::new_unchecked(LIMIT) })
4✔
126
                .parse_next(input)
127
        }
128

129
        //
130
        fn non_zero_u32(input: &mut &str) -> PResult<NonZeroU32> {
1✔
131
            digit1.try_map(str::parse).parse_next(input)
1✔
132
        }
133

134
        // 2022-07-14 00:40:05 +08:00
135
        pub(crate) fn parse_human_format(
1✔
136
            input: &str,
137
        ) -> Result<(), ParseError<&str, ContextError>> {
138
            (
139
                non_zero_u32,
140
                literal('-'),
141
                non_zero_u8_len2::<12>,
142
                literal('-'),
143
                non_zero_u8_len2::<31>,
144
                space1,
145
                u8_len2,
146
                literal(':'),
147
                u8_len2,
148
                literal(':'),
149
                u8_len2,
150
                space1,
151
                literal('+'),
152
                u8_len2,
153
                literal(':'),
154
                u8_len2,
155
            )
156
                .parse(input)?;
1✔
157
            Ok(())
1✔
158
        }
159

160
        #[test]
161
        fn test_parse() {
3✔
162
            assert!(parse_human_format("2022-07-14 00:40:05 +08:00").is_ok());
1✔
163
            assert!(parse_human_format("2022-12-14 00:40:05 +08:00").is_ok());
1✔
164
            assert!(parse_human_format("2022-13-14 00:40:05 +08:00").is_err());
1✔
165
            assert!(parse_human_format("2022-12-31 00:40:05 +08:00").is_ok());
1✔
166
            assert!(parse_human_format("2022-12-32 00:40:05 +08:00").is_err());
1✔
167
            assert!(parse_human_format("2022-07-14 00:40:05 +08:0").is_err());
1✔
168
            assert!(parse_human_format("2022-07-14 00:40:05 -08:0").is_err());
1✔
169
            assert!(parse_human_format("2022-07-00 00:40:05 +08:00").is_err());
1✔
170
            assert!(parse_human_format("2022-00-01 00:40:05 +08:00").is_err());
1✔
171
            assert!(parse_human_format("2022-00-01 00:40:05 08:00").is_err());
1✔
172
            assert!(parse_human_format("2022-00-01 00:40:05+08:00").is_err());
1✔
173
            assert!(parse_human_format("20221-00-01 00:40:05+08:00").is_err());
1✔
174
            assert!(parse_human_format("20221-01-01 00:40:05 +08:00").is_ok());
1✔
175
        }
176
    }
177

178
    #[test]
179
    fn test_source_date_epoch() {
3✔
180
        std::env::set_var("SOURCE_DATE_EPOCH", "1628080443");
181
        let time = now_date_time();
1✔
182
        assert_eq!(time.human_format(), "2021-08-04 12:34:03 +00:00");
1✔
183
    }
184

185
    #[test]
186
    fn test_local_now_human_format() {
3✔
187
        let time = DateTime::local_now().unwrap().human_format();
2✔
188
        #[cfg(unix)]
189
        assert!(!std::fs::read("/etc/localtime").unwrap().is_empty());
2✔
190

191
        assert!(parse_human_format(&time).is_ok());
1✔
192

193
        println!("local now:{time}"); // 2022-07-14 00:40:05 +08:00
1✔
194
        assert_eq!(time.len(), 26);
1✔
195
    }
196

197
    #[test]
198
    fn test_timestamp_2_utc() {
3✔
199
        let time = DateTime::timestamp_2_utc(1628080443).unwrap();
1✔
200
        assert_eq!(time.to_rfc2822(), "Wed, 04 Aug 2021 12:34:03 +0000");
1✔
201
        assert_eq!(time.to_rfc3339(), "2021-08-04T12:34:03Z");
1✔
202
        assert_eq!(time.human_format(), "2021-08-04 12:34:03 +00:00");
1✔
203
    }
204
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc