Coverage Report

Created: 2023-04-25 07:07

/rust/registry/src/index.crates.io-6f17d22bba15001f/humantime-2.1.0/src/date.rs
Line
Count
Source (jump to first uncovered line)
1
use std::error::Error as StdError;
2
use std::fmt;
3
use std::str;
4
use std::time::{SystemTime, Duration, UNIX_EPOCH};
5
6
#[cfg(target_os="cloudabi")]
7
mod max {
8
    pub const SECONDS: u64 = ::std::u64::MAX / 1_000_000_000;
9
    #[allow(unused)]
10
    pub const TIMESTAMP: &'static str = "2554-07-21T23:34:33Z";
11
}
12
#[cfg(all(
13
    target_pointer_width="32",
14
    not(target_os="cloudabi"),
15
    not(target_os="windows"),
16
    not(all(target_arch="wasm32", not(target_os="emscripten")))
17
))]
18
mod max {
19
    pub const SECONDS: u64 = ::std::i32::MAX as u64;
20
    #[allow(unused)]
21
    pub const TIMESTAMP: &'static str = "2038-01-19T03:14:07Z";
22
}
23
24
#[cfg(any(
25
    target_pointer_width="64",
26
    target_os="windows",
27
    all(target_arch="wasm32", not(target_os="emscripten")),
28
))]
29
mod max {
30
    pub const SECONDS: u64 = 253_402_300_800-1;  // last second of year 9999
31
    #[allow(unused)]
32
    pub const TIMESTAMP: &str = "9999-12-31T23:59:59Z";
33
}
34
35
/// Error parsing datetime (timestamp)
36
0
#[derive(Debug, PartialEq, Clone, Copy)]
37
pub enum Error {
38
    /// Numeric component is out of range
39
    OutOfRange,
40
    /// Bad character where digit is expected
41
    InvalidDigit,
42
    /// Other formatting errors
43
    InvalidFormat,
44
}
45
46
impl StdError for Error {}
47
48
impl fmt::Display for Error {
49
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50
0
        match self {
51
0
            Error::OutOfRange => write!(f, "numeric component is out of range"),
52
0
            Error::InvalidDigit => write!(f, "bad character where digit is expected"),
53
0
            Error::InvalidFormat => write!(f, "timestamp format is invalid"),
54
        }
55
0
    }
56
}
57
58
0
#[derive(Debug, Clone, PartialEq, Eq)]
59
enum Precision {
60
    Smart,
61
    Seconds,
62
    Millis,
63
    Micros,
64
    Nanos,
65
}
66
67
/// A wrapper type that allows you to Display a SystemTime
68
0
#[derive(Debug, Clone)]
69
pub struct Rfc3339Timestamp(SystemTime, Precision);
70
71
#[inline]
72
0
fn two_digits(b1: u8, b2: u8) -> Result<u64, Error> {
73
0
    if b1 < b'0' || b2 < b'0' || b1 > b'9' || b2 > b'9' {
74
0
        return Err(Error::InvalidDigit);
75
0
    }
76
0
    Ok(((b1 - b'0')*10 + (b2 - b'0')) as u64)
77
0
}
78
79
/// Parse RFC3339 timestamp `2018-02-14T00:28:07Z`
80
///
81
/// Supported feature: any precision of fractional
82
/// digits `2018-02-14T00:28:07.133Z`.
83
///
84
/// Unsupported feature: localized timestamps. Only UTC is supported.
85
0
pub fn parse_rfc3339(s: &str) -> Result<SystemTime, Error> {
86
0
    if s.len() < "2018-02-14T00:28:07Z".len() {
87
0
        return Err(Error::InvalidFormat);
88
0
    }
89
0
    let b = s.as_bytes();
90
0
    if b[10] != b'T' || b[b.len()-1] != b'Z' {
91
0
        return Err(Error::InvalidFormat);
92
0
    }
93
0
    parse_rfc3339_weak(s)
94
0
}
95
96
/// Parse RFC3339-like timestamp `2018-02-14 00:28:07`
97
///
98
/// Supported features:
99
///
100
/// 1. Any precision of fractional digits `2018-02-14 00:28:07.133`.
101
/// 2. Supports timestamp with or without either of `T` or `Z`
102
/// 3. Anything valid for `parse_3339` is valid for this function
103
///
104
/// Unsupported feature: localized timestamps. Only UTC is supported, even if
105
/// `Z` is not specified.
106
///
107
/// This function is intended to use for parsing human input. Whereas
108
/// `parse_rfc3339` is for strings generated programmatically.
109
0
pub fn parse_rfc3339_weak(s: &str) -> Result<SystemTime, Error> {
110
0
    if s.len() < "2018-02-14T00:28:07".len() {
111
0
        return Err(Error::InvalidFormat);
112
0
    }
113
0
    let b = s.as_bytes();  // for careless slicing
114
0
    if b[4] != b'-' || b[7] != b'-' || (b[10] != b'T' && b[10] != b' ') ||
115
0
       b[13] != b':' || b[16] != b':'
116
    {
117
0
        return Err(Error::InvalidFormat);
118
0
    }
119
0
    let year = two_digits(b[0], b[1])? * 100 + two_digits(b[2], b[3])?;
120
0
    let month = two_digits(b[5], b[6])?;
121
0
    let day = two_digits(b[8], b[9])?;
122
0
    let hour = two_digits(b[11], b[12])?;
123
0
    let minute = two_digits(b[14], b[15])?;
124
0
    let mut second = two_digits(b[17], b[18])?;
125
126
0
    if year < 1970 || hour > 23 || minute > 59 || second > 60 {
127
0
        return Err(Error::OutOfRange);
128
0
    }
129
0
    // TODO(tailhook) should we check that leaps second is only on midnight ?
130
0
    if second == 60 {
131
0
        second = 59
132
0
    };
133
0
    let leap_years = ((year - 1) - 1968) / 4 - ((year - 1) - 1900) / 100 +
134
0
                     ((year - 1) - 1600) / 400;
135
0
    let leap = is_leap_year(year);
136
0
    let (mut ydays, mdays) = match month {
137
0
        1 => (0, 31),
138
0
        2 if leap => (31, 29),
139
0
        2 => (31, 28),
140
0
        3 => (59, 31),
141
0
        4 => (90, 30),
142
0
        5 => (120, 31),
143
0
        6 => (151, 30),
144
0
        7 => (181, 31),
145
0
        8 => (212, 31),
146
0
        9 => (243, 30),
147
0
        10 => (273, 31),
148
0
        11 => (304, 30),
149
0
        12 => (334, 31),
150
0
        _ => return Err(Error::OutOfRange),
151
    };
152
0
    if day > mdays || day == 0 {
153
0
        return Err(Error::OutOfRange);
154
0
    }
155
0
    ydays += day - 1;
156
0
    if leap && month > 2 {
157
0
        ydays += 1;
158
0
    }
159
0
    let days = (year - 1970) * 365 + leap_years + ydays;
160
0
161
0
    let time = second + minute * 60 + hour * 3600;
162
0
163
0
    let mut nanos = 0;
164
0
    let mut mult = 100_000_000;
165
0
    if b.get(19) == Some(&b'.') {
166
0
        for idx in 20..b.len() {
167
0
            if b[idx] == b'Z' {
168
0
                if idx == b.len()-1 {
169
0
                    break;
170
                } else {
171
0
                    return Err(Error::InvalidDigit);
172
                }
173
0
            }
174
0
            if b[idx] < b'0' || b[idx] > b'9' {
175
0
                return Err(Error::InvalidDigit);
176
0
            }
177
0
            nanos += mult * (b[idx] - b'0') as u32;
178
0
            mult /= 10;
179
        }
180
0
    } else if b.len() != 19 && (b.len() > 20 || b[19] != b'Z') {
181
0
        return Err(Error::InvalidFormat);
182
0
    }
183
184
0
    let total_seconds = time + days * 86400;
185
0
    if total_seconds > max::SECONDS {
186
0
        return Err(Error::OutOfRange);
187
0
    }
188
0
189
0
    Ok(UNIX_EPOCH + Duration::new(total_seconds, nanos))
190
0
}
191
192
0
fn is_leap_year(y: u64) -> bool {
193
0
    y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)
194
0
}
195
196
/// Format an RFC3339 timestamp `2018-02-14T00:28:07Z`
197
///
198
/// This function formats timestamp with smart precision: i.e. if it has no
199
/// fractional seconds, they aren't written at all. And up to nine digits if
200
/// they are.
201
///
202
/// The value is always UTC and ignores system timezone.
203
0
pub fn format_rfc3339(system_time: SystemTime) -> Rfc3339Timestamp {
204
0
    Rfc3339Timestamp(system_time, Precision::Smart)
205
0
}
206
207
/// Format an RFC3339 timestamp `2018-02-14T00:28:07Z`
208
///
209
/// This format always shows timestamp without fractional seconds.
210
///
211
/// The value is always UTC and ignores system timezone.
212
0
pub fn format_rfc3339_seconds(system_time: SystemTime) -> Rfc3339Timestamp {
213
0
    Rfc3339Timestamp(system_time, Precision::Seconds)
214
0
}
215
216
/// Format an RFC3339 timestamp `2018-02-14T00:28:07.000Z`
217
///
218
/// This format always shows milliseconds even if millisecond value is zero.
219
///
220
/// The value is always UTC and ignores system timezone.
221
0
pub fn format_rfc3339_millis(system_time: SystemTime) -> Rfc3339Timestamp {
222
0
    Rfc3339Timestamp(system_time, Precision::Millis)
223
0
}
224
225
/// Format an RFC3339 timestamp `2018-02-14T00:28:07.000000Z`
226
///
227
/// This format always shows microseconds even if microsecond value is zero.
228
///
229
/// The value is always UTC and ignores system timezone.
230
0
pub fn format_rfc3339_micros(system_time: SystemTime) -> Rfc3339Timestamp {
231
0
    Rfc3339Timestamp(system_time, Precision::Micros)
232
0
}
233
234
/// Format an RFC3339 timestamp `2018-02-14T00:28:07.000000000Z`
235
///
236
/// This format always shows nanoseconds even if nanosecond value is zero.
237
///
238
/// The value is always UTC and ignores system timezone.
239
0
pub fn format_rfc3339_nanos(system_time: SystemTime) -> Rfc3339Timestamp {
240
0
    Rfc3339Timestamp(system_time, Precision::Nanos)
241
0
}
242
243
impl Rfc3339Timestamp {
244
    /// Returns a reference to the [`SystemTime`][] that is being formatted.
245
0
    pub fn get_ref(&self) -> &SystemTime {
246
0
        &self.0
247
0
    }
248
}
249
250
impl fmt::Display for Rfc3339Timestamp {
251
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
252
0
        use self::Precision::*;
253
0
254
0
        let dur = self.0.duration_since(UNIX_EPOCH)
255
0
            .expect("all times should be after the epoch");
256
0
        let secs_since_epoch = dur.as_secs();
257
0
        let nanos = dur.subsec_nanos();
258
0
259
0
        if secs_since_epoch >= 253_402_300_800 { // year 9999
260
0
            return Err(fmt::Error);
261
0
        }
262
0
263
0
        /* 2000-03-01 (mod 400 year, immediately after feb29 */
264
0
        const LEAPOCH: i64 = 11017;
265
0
        const DAYS_PER_400Y: i64 = 365*400 + 97;
266
0
        const DAYS_PER_100Y: i64 = 365*100 + 24;
267
0
        const DAYS_PER_4Y: i64 = 365*4 + 1;
268
0
269
0
        let days = (secs_since_epoch / 86400) as i64 - LEAPOCH;
270
0
        let secs_of_day = secs_since_epoch % 86400;
271
0
272
0
        let mut qc_cycles = days / DAYS_PER_400Y;
273
0
        let mut remdays = days % DAYS_PER_400Y;
274
0
275
0
        if remdays < 0 {
276
0
            remdays += DAYS_PER_400Y;
277
0
            qc_cycles -= 1;
278
0
        }
279
280
0
        let mut c_cycles = remdays / DAYS_PER_100Y;
281
0
        if c_cycles == 4 { c_cycles -= 1; }
282
0
        remdays -= c_cycles * DAYS_PER_100Y;
283
0
284
0
        let mut q_cycles = remdays / DAYS_PER_4Y;
285
0
        if q_cycles == 25 { q_cycles -= 1; }
286
0
        remdays -= q_cycles * DAYS_PER_4Y;
287
0
288
0
        let mut remyears = remdays / 365;
289
0
        if remyears == 4 { remyears -= 1; }
290
0
        remdays -= remyears * 365;
291
0
292
0
        let mut year = 2000 +
293
0
            remyears + 4*q_cycles + 100*c_cycles + 400*qc_cycles;
294
0
295
0
        let months = [31,30,31,30,31,31,30,31,30,31,31,29];
296
0
        let mut mon = 0;
297
0
        for mon_len in months.iter() {
298
0
            mon += 1;
299
0
            if remdays < *mon_len {
300
0
                break;
301
0
            }
302
0
            remdays -= *mon_len;
303
        }
304
0
        let mday = remdays+1;
305
0
        let mon = if mon + 2 > 12 {
306
0
            year += 1;
307
0
            mon - 10
308
        } else {
309
0
            mon + 2
310
        };
311
312
0
        let mut buf: [u8; 30] = [
313
0
            // Too long to write as: b"0000-00-00T00:00:00.000000000Z"
314
0
            b'0', b'0', b'0', b'0', b'-', b'0', b'0', b'-', b'0', b'0', b'T',
315
0
            b'0', b'0', b':', b'0', b'0', b':', b'0', b'0',
316
0
            b'.', b'0', b'0', b'0', b'0', b'0', b'0', b'0', b'0', b'0', b'Z',
317
0
        ];
318
0
        buf[0] = b'0' + (year / 1000) as u8;
319
0
        buf[1] = b'0' + (year / 100 % 10) as u8;
320
0
        buf[2] = b'0' + (year / 10 % 10) as u8;
321
0
        buf[3] = b'0' + (year % 10) as u8;
322
0
        buf[5] = b'0' + (mon / 10) as u8;
323
0
        buf[6] = b'0' + (mon % 10) as u8;
324
0
        buf[8] = b'0' + (mday / 10) as u8;
325
0
        buf[9] = b'0' + (mday % 10) as u8;
326
0
        buf[11] = b'0' + (secs_of_day / 3600 / 10) as u8;
327
0
        buf[12] = b'0' + (secs_of_day / 3600 % 10) as u8;
328
0
        buf[14] = b'0' + (secs_of_day / 60 / 10 % 6) as u8;
329
0
        buf[15] = b'0' + (secs_of_day / 60 % 10) as u8;
330
0
        buf[17] = b'0' + (secs_of_day / 10 % 6) as u8;
331
0
        buf[18] = b'0' + (secs_of_day % 10) as u8;
332
333
0
        let offset = if self.1 == Seconds || nanos == 0 && self.1 == Smart {
334
0
            buf[19] = b'Z';
335
0
            19
336
0
        } else if self.1 == Millis {
337
0
            buf[20] = b'0' + (nanos / 100_000_000) as u8;
338
0
            buf[21] = b'0' + (nanos / 10_000_000 % 10) as u8;
339
0
            buf[22] = b'0' + (nanos / 1_000_000 % 10) as u8;
340
0
            buf[23] = b'Z';
341
0
            23
342
0
        } else if self.1 == Micros {
343
0
            buf[20] = b'0' + (nanos / 100_000_000) as u8;
344
0
            buf[21] = b'0' + (nanos / 10_000_000 % 10) as u8;
345
0
            buf[22] = b'0' + (nanos / 1_000_000 % 10) as u8;
346
0
            buf[23] = b'0' + (nanos / 100_000 % 10) as u8;
347
0
            buf[24] = b'0' + (nanos / 10_000 % 10) as u8;
348
0
            buf[25] = b'0' + (nanos / 1_000 % 10) as u8;
349
0
            buf[26] = b'Z';
350
0
            26
351
        } else {
352
0
            buf[20] = b'0' + (nanos / 100_000_000) as u8;
353
0
            buf[21] = b'0' + (nanos / 10_000_000 % 10) as u8;
354
0
            buf[22] = b'0' + (nanos / 1_000_000 % 10) as u8;
355
0
            buf[23] = b'0' + (nanos / 100_000 % 10) as u8;
356
0
            buf[24] = b'0' + (nanos / 10_000 % 10) as u8;
357
0
            buf[25] = b'0' + (nanos / 1_000 % 10) as u8;
358
0
            buf[26] = b'0' + (nanos / 100 % 10) as u8;
359
0
            buf[27] = b'0' + (nanos / 10 % 10) as u8;
360
0
            buf[28] = b'0' + (nanos / 1 % 10) as u8;
361
0
            // 29th is 'Z'
362
0
            29
363
        };
364
365
        // we know our chars are all ascii
366
0
        f.write_str(str::from_utf8(&buf[..=offset]).expect("Conversion to utf8 failed"))
367
0
    }
368
}
369
370
#[cfg(test)]
371
mod test {
372
    use std::str::from_utf8;
373
    use std::time::{UNIX_EPOCH, SystemTime, Duration};
374
375
    use rand::Rng;
376
377
    use super::{parse_rfc3339, parse_rfc3339_weak, format_rfc3339};
378
    use super::{format_rfc3339_millis, format_rfc3339_micros};
379
    use super::{format_rfc3339_nanos};
380
    use super::max;
381
382
    fn from_sec(sec: u64) -> (String, SystemTime) {
383
        let s = time::at_utc(time::Timespec { sec: sec as i64, nsec: 0 })
384
                  .rfc3339().to_string();
385
        let time = UNIX_EPOCH + Duration::new(sec, 0);
386
        (s, time)
387
    }
388
389
    #[test]
390
    #[cfg(all(target_pointer_width="32", target_os="linux"))]
391
    fn year_after_2038_fails_gracefully() {
392
        // next second
393
        assert_eq!(parse_rfc3339("2038-01-19T03:14:08Z").unwrap_err(),
394
                   super::Error::OutOfRange);
395
        assert_eq!(parse_rfc3339("9999-12-31T23:59:59Z").unwrap_err(),
396
                   super::Error::OutOfRange);
397
    }
398
399
    #[test]
400
    fn smoke_tests_parse() {
401
        assert_eq!(parse_rfc3339("1970-01-01T00:00:00Z").unwrap(),
402
                   UNIX_EPOCH + Duration::new(0, 0));
403
        assert_eq!(parse_rfc3339("1970-01-01T00:00:01Z").unwrap(),
404
                   UNIX_EPOCH + Duration::new(1, 0));
405
        assert_eq!(parse_rfc3339("2018-02-13T23:08:32Z").unwrap(),
406
                   UNIX_EPOCH + Duration::new(1_518_563_312, 0));
407
        assert_eq!(parse_rfc3339("2012-01-01T00:00:00Z").unwrap(),
408
                   UNIX_EPOCH + Duration::new(1_325_376_000, 0));
409
    }
410
411
    #[test]
412
    fn smoke_tests_format() {
413
        assert_eq!(
414
            format_rfc3339(UNIX_EPOCH + Duration::new(0, 0)).to_string(),
415
            "1970-01-01T00:00:00Z");
416
        assert_eq!(
417
            format_rfc3339(UNIX_EPOCH + Duration::new(1, 0)).to_string(),
418
            "1970-01-01T00:00:01Z");
419
        assert_eq!(
420
            format_rfc3339(UNIX_EPOCH + Duration::new(1_518_563_312, 0)).to_string(),
421
            "2018-02-13T23:08:32Z");
422
        assert_eq!(
423
            format_rfc3339(UNIX_EPOCH + Duration::new(1_325_376_000, 0)).to_string(),
424
            "2012-01-01T00:00:00Z");
425
    }
426
427
    #[test]
428
    fn smoke_tests_format_millis() {
429
        assert_eq!(
430
            format_rfc3339_millis(UNIX_EPOCH +
431
                Duration::new(0, 0)).to_string(),
432
            "1970-01-01T00:00:00.000Z");
433
        assert_eq!(
434
            format_rfc3339_millis(UNIX_EPOCH +
435
                Duration::new(1_518_563_312, 123_000_000)).to_string(),
436
            "2018-02-13T23:08:32.123Z");
437
    }
438
439
    #[test]
440
    fn smoke_tests_format_micros() {
441
        assert_eq!(
442
            format_rfc3339_micros(UNIX_EPOCH +
443
                Duration::new(0, 0)).to_string(),
444
            "1970-01-01T00:00:00.000000Z");
445
        assert_eq!(
446
            format_rfc3339_micros(UNIX_EPOCH +
447
                Duration::new(1_518_563_312, 123_000_000)).to_string(),
448
            "2018-02-13T23:08:32.123000Z");
449
        assert_eq!(
450
            format_rfc3339_micros(UNIX_EPOCH +
451
                Duration::new(1_518_563_312, 456_123_000)).to_string(),
452
            "2018-02-13T23:08:32.456123Z");
453
    }
454
455
    #[test]
456
    fn smoke_tests_format_nanos() {
457
        assert_eq!(
458
            format_rfc3339_nanos(UNIX_EPOCH +
459
                Duration::new(0, 0)).to_string(),
460
            "1970-01-01T00:00:00.000000000Z");
461
        assert_eq!(
462
            format_rfc3339_nanos(UNIX_EPOCH +
463
                Duration::new(1_518_563_312, 123_000_000)).to_string(),
464
            "2018-02-13T23:08:32.123000000Z");
465
        assert_eq!(
466
            format_rfc3339_nanos(UNIX_EPOCH +
467
                Duration::new(1_518_563_312, 789_456_123)).to_string(),
468
            "2018-02-13T23:08:32.789456123Z");
469
    }
470
471
    #[test]
472
    fn upper_bound() {
473
        let max = UNIX_EPOCH + Duration::new(max::SECONDS, 0);
474
        assert_eq!(parse_rfc3339(&max::TIMESTAMP).unwrap(), max);
475
        assert_eq!(format_rfc3339(max).to_string(), max::TIMESTAMP);
476
    }
477
478
    #[test]
479
    fn leap_second() {
480
        assert_eq!(parse_rfc3339("2016-12-31T23:59:60Z").unwrap(),
481
                   UNIX_EPOCH + Duration::new(1_483_228_799, 0));
482
    }
483
484
    #[test]
485
    fn first_731_days() {
486
        let year_start = 0;  // 1970
487
        for day in 0..= 365 * 2 {  // scan leap year and non-leap year
488
            let (s, time) = from_sec(year_start + day * 86400);
489
            assert_eq!(parse_rfc3339(&s).unwrap(), time);
490
            assert_eq!(format_rfc3339(time).to_string(), s);
491
        }
492
    }
493
494
    #[test]
495
    fn the_731_consecutive_days() {
496
        let year_start = 1_325_376_000;  // 2012
497
        for day in 0..= 365 * 2 {  // scan leap year and non-leap year
498
            let (s, time) = from_sec(year_start + day * 86400);
499
            assert_eq!(parse_rfc3339(&s).unwrap(), time);
500
            assert_eq!(format_rfc3339(time).to_string(), s);
501
        }
502
    }
503
504
    #[test]
505
    fn all_86400_seconds() {
506
        let day_start = 1_325_376_000;
507
        for second in 0..86400 {  // scan leap year and non-leap year
508
            let (s, time) = from_sec(day_start + second);
509
            assert_eq!(parse_rfc3339(&s).unwrap(), time);
510
            assert_eq!(format_rfc3339(time).to_string(), s);
511
        }
512
    }
513
514
    #[test]
515
    fn random_past() {
516
        let upper = SystemTime::now().duration_since(UNIX_EPOCH).unwrap()
517
            .as_secs();
518
        for _ in 0..10000 {
519
            let sec = rand::thread_rng().gen_range(0, upper);
520
            let (s, time) = from_sec(sec);
521
            assert_eq!(parse_rfc3339(&s).unwrap(), time);
522
            assert_eq!(format_rfc3339(time).to_string(), s);
523
        }
524
    }
525
526
    #[test]
527
    fn random_wide_range() {
528
        for _ in 0..100_000 {
529
            let sec = rand::thread_rng().gen_range(0, max::SECONDS);
530
            let (s, time) = from_sec(sec);
531
            assert_eq!(parse_rfc3339(&s).unwrap(), time);
532
            assert_eq!(format_rfc3339(time).to_string(), s);
533
        }
534
    }
535
536
    #[test]
537
    fn milliseconds() {
538
        assert_eq!(parse_rfc3339("1970-01-01T00:00:00.123Z").unwrap(),
539
                   UNIX_EPOCH + Duration::new(0, 123_000_000));
540
        assert_eq!(format_rfc3339(UNIX_EPOCH + Duration::new(0, 123_000_000))
541
            .to_string(), "1970-01-01T00:00:00.123000000Z");
542
    }
543
544
    #[test]
545
    #[should_panic(expected="OutOfRange")]
546
    fn zero_month() {
547
        parse_rfc3339("1970-00-01T00:00:00Z").unwrap();
548
    }
549
550
    #[test]
551
    #[should_panic(expected="OutOfRange")]
552
    fn big_month() {
553
        parse_rfc3339("1970-32-01T00:00:00Z").unwrap();
554
    }
555
556
    #[test]
557
    #[should_panic(expected="OutOfRange")]
558
    fn zero_day() {
559
        parse_rfc3339("1970-01-00T00:00:00Z").unwrap();
560
    }
561
562
    #[test]
563
    #[should_panic(expected="OutOfRange")]
564
    fn big_day() {
565
        parse_rfc3339("1970-12-35T00:00:00Z").unwrap();
566
    }
567
568
    #[test]
569
    #[should_panic(expected="OutOfRange")]
570
    fn big_day2() {
571
        parse_rfc3339("1970-02-30T00:00:00Z").unwrap();
572
    }
573
574
    #[test]
575
    #[should_panic(expected="OutOfRange")]
576
    fn big_second() {
577
        parse_rfc3339("1970-12-30T00:00:78Z").unwrap();
578
    }
579
580
    #[test]
581
    #[should_panic(expected="OutOfRange")]
582
    fn big_minute() {
583
        parse_rfc3339("1970-12-30T00:78:00Z").unwrap();
584
    }
585
586
    #[test]
587
    #[should_panic(expected="OutOfRange")]
588
    fn big_hour() {
589
        parse_rfc3339("1970-12-30T24:00:00Z").unwrap();
590
    }
591
592
    #[test]
593
    fn break_data() {
594
        for pos in 0.."2016-12-31T23:59:60Z".len() {
595
            let mut s = b"2016-12-31T23:59:60Z".to_vec();
596
            s[pos] = b'x';
597
            parse_rfc3339(from_utf8(&s).unwrap()).unwrap_err();
598
        }
599
    }
600
601
    #[test]
602
    fn weak_smoke_tests() {
603
        assert_eq!(parse_rfc3339_weak("1970-01-01 00:00:00").unwrap(),
604
                   UNIX_EPOCH + Duration::new(0, 0));
605
        parse_rfc3339("1970-01-01 00:00:00").unwrap_err();
606
607
        assert_eq!(parse_rfc3339_weak("1970-01-01 00:00:00.000123").unwrap(),
608
                   UNIX_EPOCH + Duration::new(0, 123_000));
609
        parse_rfc3339("1970-01-01 00:00:00.000123").unwrap_err();
610
611
        assert_eq!(parse_rfc3339_weak("1970-01-01T00:00:00.000123").unwrap(),
612
                   UNIX_EPOCH + Duration::new(0, 123_000));
613
        parse_rfc3339("1970-01-01T00:00:00.000123").unwrap_err();
614
615
        assert_eq!(parse_rfc3339_weak("1970-01-01 00:00:00.000123Z").unwrap(),
616
                   UNIX_EPOCH + Duration::new(0, 123_000));
617
        parse_rfc3339("1970-01-01 00:00:00.000123Z").unwrap_err();
618
619
        assert_eq!(parse_rfc3339_weak("1970-01-01 00:00:00Z").unwrap(),
620
                   UNIX_EPOCH + Duration::new(0, 0));
621
        parse_rfc3339("1970-01-01 00:00:00Z").unwrap_err();
622
    }
623
}