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
|
use crate::zip::{ZipError, ZipResult};
use chrono::{DateTime, Datelike, NaiveDate, TimeZone, Timelike};
pub trait DosDateTime<Tz>: Sized {
fn from_dos_date_time(date: u16, time: u16, tz: Tz) -> ZipResult<Self>;
#[allow(dead_code)]
fn to_dos_date(&self) -> u16;
fn to_dos_time(&self) -> u16;
}
impl<Tz: TimeZone> DosDateTime<Tz> for DateTime<Tz> {
#[inline]
fn from_dos_date_time(date: u16, time: u16, tz: Tz) -> ZipResult<Self> {
Ok(NaiveDate::from_ymd_opt(
(date as i32 >> 9 & 0x7F) + 1980,
date as u32 >> 5 & 0xF,
date as u32 & 0x1F,
)
.ok_or(ZipError::InvalidField("date"))?
.and_hms_opt(
(time as u32 >> 11) & 0x1F,
(time as u32 >> 5) & 0x3F,
(time as u32 & 0x1F) * 2,
)
.ok_or(ZipError::InvalidField("time"))?
.and_local_timezone(tz)
.unwrap())
}
#[inline]
fn to_dos_date(&self) -> u16 {
(self.year() as u16 - 1980 & 0x7F) << 9
| (self.month() as u16 & 0xF) << 5
| self.day() as u16 & 0x1F
}
#[inline]
fn to_dos_time(&self) -> u16 {
(self.hour() as u16 & 0x1F) << 11
| (self.minute() as u16 & 0x3F) << 5
| self.second() as u16 / 2 & 0x1F
}
}
|