forensic_rs/utils/
time.rs

1use std::{ops::{Add, AddAssign, Sub}, time::{Duration, SystemTime, UNIX_EPOCH}};
2
3/// Simplifies handling Windows filetime dates. Use only with UTC dates as it does not take time zones into account. Eliminates the need to use the chrono library.
4/// ```rust
5/// use forensic_rs::prelude::*;
6/// assert_eq!("01-01-1601 00:00:00", format!("{:?}", WinFiletime(0)));
7/// assert_eq!("01-01-1605 00:00:00", format!("{:?}", WinFiletime(1262304000000000)));
8/// assert_eq!("14-11-1999 18:27:59", format!("{:?}", WinFiletime(125870776790000000)));
9/// assert_eq!("14-11-2000 18:27:59.001", format!("{:?}", WinFiletime(126187000790010000)));
10/// ```
11#[derive(Clone, Default, Copy)]
12pub struct WinFiletime(pub u64);
13
14
15/// Simplifies handling unix timestamp dates. Use only with UTC dates as it does not take time zones into account. Eliminates the need to use the chrono library.
16/// 
17/// ```rust
18/// use forensic_rs::prelude::*;
19/// assert_eq!("01-01-1970 00:00:00", format!("{:?}", UnixTimestamp(0)));
20/// assert_eq!("01-01-1972 00:00:00", format!("{:?}", UnixTimestamp(63072000000)));
21/// ```
22#[derive(Clone, Default, Copy)]
23pub struct UnixTimestamp(pub u64);
24
25/// Simplifies handling Windows filetime dates. Use only with UTC dates as it does not take time zones into account. Eliminates the need to use the chrono library.
26/// Its more complex than WinFiletime and uses more space, but its much faster when getting date parameters like hour,minute,day... as it parses the date when created. 
27/// ```rust
28/// use forensic_rs::prelude::*;
29/// assert_eq!("01-01-1601 00:00:00", format!("{:?}", Filetime::new(0)));
30/// assert_eq!("01-01-1605 00:00:00", format!("{:?}", Filetime::new(1262304000000000)));
31/// assert_eq!("14-11-1999 18:27:59", format!("{:?}", Filetime::new(125870776790000000)));
32/// assert_eq!("14-11-2000 18:27:59.001", format!("{:?}", Filetime::new(126187000790010000)));
33/// assert_eq!(2000, Filetime::new(126187000790010000).year());
34/// assert_eq!(100, Filetime::new(126187000790000001).nanoseconds());
35/// ```
36#[derive(Clone, Default, Copy)]
37pub struct Filetime {
38    original : u64,
39    year : u16,
40    month : u8,
41    day : u8,
42    hour : u8,
43    minute : u8,
44    second : u8,
45    nanos : u32
46}
47
48impl Filetime {
49    /// Makes a new Filetime from windows u64 filetime
50    pub fn new(timestap : u64) -> Self {
51        let nanoseconds_since_beginning = (timestap as u128) * 100;
52        let days_since_beginning = nanoseconds_since_beginning.div_euclid(60 * 60 * 24 * 1_000_000_000);
53        let nanoseconds_in_day = nanoseconds_since_beginning - days_since_beginning *60 * 60 * 24 * 1_000_000_000;
54        let (year, restant_days) = to_years(days_since_beginning);
55        let (month, acumulated_day_month) = if is_leap_year(year) {
56            [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335]
57                .iter()
58                .position(|&v| v > restant_days)
59                .map(|pos| {
60                    (
61                        pos,
62                        [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335][pos - 1],
63                    )
64                })
65        } else {
66            [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
67                .iter()
68                .position(|&v| v > restant_days)
69                .map(|pos| {
70                    (
71                        pos,
72                        [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334][pos - 1],
73                    )
74                })
75        }
76        .unwrap_or((12, 335));
77        let day = restant_days.saturating_sub(acumulated_day_month) + 1;
78        let hour = nanoseconds_in_day.div_euclid(60 * 60 * 1_000_000_000);
79        let rest_nanos = nanoseconds_in_day - hour * 60*60*1_000_000_000;
80        let minute = rest_nanos.div_euclid(60 * 1_000_000_000);
81        let rest_nanos = rest_nanos - minute * 60 * 1_000_000_000;
82        let second = rest_nanos.div_euclid(1_000_000_000);
83        let nanos = rest_nanos - second*1_000_000_000;
84        Self {
85            original : timestap,
86            year : year as u16,
87            month: month as u8,
88            day: day as u8,
89            hour: hour as u8,
90            minute: minute as u8,
91            second: second as u8,
92            nanos: nanos as u32,
93        }
94    }
95    /// Make a new Filetime from year, month, day, time components assuming UTC.
96    pub fn with_ymd_and_hms(year : u16, month : u8, day : u8, hour : u8, minute : u8, second : u8, nanos : u32 ) -> Self {
97        let days_since_begining = days_from_year(year) as u64;
98        let days_since_start_year = acumulated_day_month(month, year) as u64;
99        let days = days_since_begining + days_since_start_year + day as u64 - 1;
100        let original = (nanos as u64 / 100) + ((second as u64 + (60u64 * (minute as u64 + (60u64 * (hour as u64 + 24 * days))))) * 10_000_000u64);
101        
102        Self {
103            year,
104            month,
105            day,
106            hour,
107            minute,
108            second,
109            nanos,
110            original 
111        }
112    }
113
114    /// Returns the year number 
115    /// 
116    /// ```rust
117    /// use forensic_rs::prelude::*;
118    /// let time = Filetime::new(125963224790010000); // 29-02-2000 18:27:59.001
119    /// assert_eq!(2000, time.year());
120    /// ```
121    pub fn year(&self) -> u16 {
122        self.year
123    }
124    /// Returns the month number 
125    /// 
126    /// ```rust
127    /// use forensic_rs::prelude::*;
128    /// let time = Filetime::new(125963224790010000); // 29-02-2000 18:27:59.001
129    /// assert_eq!(2, time.month());
130    /// ```
131    pub fn month(&self) -> u8 {
132        self.month
133    }
134    /// Returns the day number 
135    /// 
136    /// ```rust
137    /// use forensic_rs::prelude::*;
138    /// let time = Filetime::new(125963224790010000); // 29-02-2000 18:27:59.001
139    /// assert_eq!(29, time.day());
140    /// ```
141    pub fn day(&self) -> u8 {
142        self.day
143    }
144    /// Returns the hour number 
145    /// 
146    /// ```rust
147    /// use forensic_rs::prelude::*;
148    /// let time = Filetime::new(125963224790010000); // 29-02-2000 18:27:59.001
149    /// assert_eq!(18, time.hour());
150    /// ```
151    pub fn hour(&self) -> u8 {
152        self.hour
153    }
154    /// Returns the minute number 
155    /// 
156    /// ```rust
157    /// use forensic_rs::prelude::*;
158    /// let time = Filetime::new(125963224790010000); // 29-02-2000 18:27:59.001
159    /// assert_eq!(27, time.minute());
160    /// ```
161    pub fn minute(&self) -> u8 {
162        self.minute
163    }
164    /// Returns the second number 
165    /// 
166    /// ```rust
167    /// use forensic_rs::prelude::*;
168    /// let time = Filetime::new(125963224790010000); // 29-02-2000 18:27:59.001
169    /// assert_eq!(59, time.second());
170    /// ```
171    pub fn second(&self) -> u8 {
172        self.second
173    }
174    /// Returns the second number 
175    /// 
176    /// ```rust
177    /// use forensic_rs::prelude::*;
178    /// let time = Filetime::new(125963224790010000); // 29-02-2000 18:27:59.001
179    /// assert_eq!(1, time.millis());
180    /// ```
181    pub fn millis(&self) -> u32 {
182        self.nanos / 1_000_000
183    }
184    /// Returns the nanoseconds number 
185    /// 
186    /// ```rust
187    /// use forensic_rs::prelude::*;
188    /// let time = Filetime::new(125963224790010000); // 29-02-2000 18:27:59.001
189    /// assert_eq!(1000000, time.nanoseconds());
190    /// ```
191    pub fn nanoseconds(&self) -> u32 {
192        self.nanos
193    }
194    /// Returns the original filetime since 1601
195    /// ```rust
196    /// use forensic_rs::prelude::*;
197    /// let time = Filetime::new(125963224790010000); // 29-02-2000 18:27:59.001
198    /// assert_eq!(125963224790010000, time.filetime());
199    /// ```
200    pub fn filetime(&self) -> u64 {
201        self.original
202    }
203
204    /// Returns the amount of time elapsed from an earlier point in time.
205    /// 
206    /// This function may fail because measurements taken earlier are not guaranteed to always be before later measurements (due to anomalies such as the system clock being adjusted either forwards or backwards). Instant can be used to measure elapsed time without this risk of failure.
207    /// 
208    /// If successful, Ok(Duration) is returned where the duration represents the amount of time elapsed from the specified measurement to this one.
209    /// 
210    /// Returns an Err if earlier is later than self, and the error contains how far from self the time is.
211    pub fn duration_since(&self, earlier : SystemTime) -> Result<Duration, Duration> {
212        let nano_epoch = earlier.duration_since(UNIX_EPOCH).map_err(|e| e.duration())?;
213        let nanos = nano_epoch.as_nanos();
214        let self_nanos = self.original as u128 * 100;
215
216        if nanos > self_nanos {
217            return Err(Duration::from_nanos((nanos - self_nanos) as u64))
218        }
219        Ok(Duration::from_nanos((self_nanos - nanos) as u64))
220    }
221}
222
223impl std::fmt::Debug for Filetime {
224    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
225        if self.nanos == 0 {
226            f.write_fmt(format_args!(
227                "{:02}-{:02}-{:04} {:02}:{:02}:{:02}", self.day, self.month, self.year, self.hour, self.minute, self.second
228            ))
229        }else {
230            f.write_fmt(format_args!(
231                "{:02}-{:02}-{:04} {:02}:{:02}:{:02}.{:03}", self.day, self.month, self.year, self.hour, self.minute, self.second, self.nanos / 1_000_000
232            ))
233        }
234    }
235}
236
237impl std::fmt::Display for Filetime {
238    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
239        write!(f, "{:?}", self)
240    }
241}
242
243impl Add<Duration> for Filetime {
244    type Output = Filetime;
245
246    fn add(self, rhs: Duration) -> Self::Output {
247        let nanos = rhs.as_nanos();
248        Self::new(((self.original as u128) * 100 + nanos).div_euclid(100) as u64)
249    }
250}
251
252impl AddAssign<Duration> for Filetime {
253    fn add_assign(&mut self, rhs: Duration) {
254        let nanos = rhs.as_nanos();
255        let nw = Self::new(((self.original as u128) * 100 + nanos).div_euclid(100) as u64);
256        self.hour = nw.hour;
257        self.day = nw.day;
258        self.minute = nw.minute;
259        self.nanos = nw.nanos;
260        self.second = nw.second;
261        self.year = nw.year;
262        self.original = nw.original;
263    }
264}
265
266impl Sub<Duration> for Filetime {
267    type Output = Filetime;
268
269    fn sub(self, rhs: Duration) -> Self::Output {
270        let nanos = rhs.as_nanos();
271        Self::new(((self.original as u128) * 100 - nanos).div_euclid(100) as u64)
272    }
273}
274
275
276/// Converts a Windows filetime to unix timestamp in milliseconds
277///
278/// ```rust
279/// use forensic_rs::utils::time::filetime_to_unix_timestamp;
280/// //Sat 3 February 2024 14:10:23 UTC
281/// assert_eq!(1706969423596, filetime_to_unix_timestamp(133514430235959706u64));
282/// ```
283pub fn filetime_to_unix_timestamp(filetime: u64) -> u64 {
284    (filetime as u128)
285        .div_ceil(10_000u128)
286        .saturating_sub(11644473600000u128) as u64
287}
288
289/// Converts a Windows filetime to unix timestamp with millisecond precision
290///
291/// ```rust
292/// use forensic_rs::utils::time::filetime_to_system_time;
293/// //Sat 3 February 2024 14:10:23 UTC
294/// let time = filetime_to_system_time(133514430235959706u64);
295/// assert_eq!(1706969423596, time.duration_since(std::time::UNIX_EPOCH).unwrap().as_millis());
296/// ```
297pub fn filetime_to_system_time(filetime: u64) -> std::time::SystemTime {
298    UNIX_EPOCH + std::time::Duration::from_millis(filetime_to_unix_timestamp(filetime))
299}
300
301impl From<u64> for WinFiletime {
302    fn from(value: u64) -> Self {
303        WinFiletime(value)
304    }
305}
306impl From<u64> for UnixTimestamp {
307    fn from(value: u64) -> Self {
308        UnixTimestamp(value)
309    }
310}
311
312
313impl std::fmt::Debug for WinFiletime {
314    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
315        let milliseconds_since_beginning = (self.0 as u128).div_euclid(10_000u128);
316        let days_since_beginning = milliseconds_since_beginning.div_euclid(60 * 60 * 24 * 1000);
317        let milliseconds_in_day = milliseconds_since_beginning - days_since_beginning *60 * 60 * 24 * 1000;
318        let (year, restant_days) = to_years(days_since_beginning);
319        let (month, acumulated_day_month) = if is_leap_year(year) {
320            [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335]
321                .iter()
322                .position(|&v| v > restant_days)
323                .map(|pos| {
324                    (
325                        pos,
326                        [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335][pos - 1],
327                    )
328                })
329        } else {
330            [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
331                .iter()
332                .position(|&v| v > restant_days)
333                .map(|pos| {
334                    (
335                        pos,
336                        [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334][pos - 1],
337                    )
338                })
339        }
340        .unwrap_or((12, 335));
341        let day = restant_days.saturating_sub(acumulated_day_month) + 1;
342        let hours = milliseconds_in_day.div_euclid(60 * 60 * 1000);
343        let rest_millis = milliseconds_in_day - hours * 60*60*1000;
344        let minute = rest_millis.div_euclid(60 * 1000);
345        let rest_millis = rest_millis - minute * 60 * 1000;
346        let seconds = rest_millis.div_euclid(1000);
347        let millis = rest_millis - seconds*1000;
348        if millis == 0 {
349            f.write_fmt(format_args!(
350                "{:02}-{:02}-{:04} {:02}:{:02}:{:02}", day, month,year, hours, minute, seconds
351            ))
352        }else {
353            f.write_fmt(format_args!(
354                "{:02}-{:02}-{:04} {:02}:{:02}:{:02}.{:03}", day, month,year, hours, minute, seconds, millis
355            ))
356        }
357    }
358}
359
360impl std::fmt::Debug for UnixTimestamp {
361    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
362        let milliseconds_since_beginning = self.0 as u128;
363        let days_since_beginning = milliseconds_since_beginning.div_euclid(60 * 60 * 24 * 1000);
364        let milliseconds_in_day = milliseconds_since_beginning - days_since_beginning *60 * 60 * 24 * 1000;
365        let (year, restant_days) = to_years_unix(days_since_beginning);
366        let (month, acumulated_day_month) = if is_leap_year(year) {
367            [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335]
368                .iter()
369                .position(|&v| v > restant_days)
370                .map(|pos| {
371                    (
372                        pos,
373                        [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335][pos - 1],
374                    )
375                })
376        } else {
377            [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
378                .iter()
379                .position(|&v| v > restant_days)
380                .map(|pos| {
381                    (
382                        pos,
383                        [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334][pos - 1],
384                    )
385                })
386        }
387        .unwrap_or((12, 335));
388        let day = restant_days.saturating_sub(acumulated_day_month) + 1;
389        let hours = milliseconds_in_day.div_euclid(60 * 60 * 1000);
390        let rest_millis = milliseconds_in_day - hours * 60*60*1000;
391        let minute = rest_millis.div_euclid(60 * 1000);
392        let rest_millis = rest_millis - minute * 60 * 1000;
393        let seconds = rest_millis.div_euclid(1000);
394        let millis = rest_millis - seconds*1000;
395        if millis == 0 {
396            f.write_fmt(format_args!(
397                "{:02}-{:02}-{:04} {:02}:{:02}:{:02}", day, month,year, hours, minute, seconds
398            ))
399        }else {
400            f.write_fmt(format_args!(
401                "{:02}-{:02}-{:04} {:02}:{:02}:{:02}.{:03}", day, month,year, hours, minute, seconds, millis
402            ))
403        }
404    }
405}
406
407fn acumulated_day_month(month : u8, year : u16) -> u16 {
408    if is_leap_year(year) {
409        if month >= 12 {
410            return 366u16
411        }
412        [0,0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335][month as usize]
413    } else {
414        if month >= 12 {
415            return 365u16
416        }
417        [0,0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334][month as usize]
418    }
419}
420
421fn is_leap_year(year: u16) -> bool {
422    (year % 4 == 0 && year % 100 != 0) || (year % 100 == 0 && year % 400 == 0)
423}
424fn to_years(mut days : u128) -> (u16, u128) {
425    let mut year = 1601;
426    while days >= 365 {
427        days -= 365;
428        year += 1;
429        if days < 365 {
430            break
431        }
432        if is_leap_year(year) {
433            days -= 1;
434        }
435    }
436    (year, days)
437}
438fn days_from_year(year : u16) -> u128 {
439    let mut days = 0;
440    if year <= 1601 {
441        return 0
442    }
443    for yr in 1601..year {
444        if is_leap_year(yr) {
445            days += 1;
446        }
447        days += 365;
448    }
449    days
450}
451fn to_years_unix(mut days : u128) -> (u16, u128) {
452    let mut year = 1970;
453    while days >= 365 {
454        days -= 365;
455        year += 1;
456        if days < 365 {
457            break
458        }
459        if is_leap_year(year) {
460            days -= 1;
461        }
462    }
463    (year, days)
464}
465
466impl From<WinFiletime> for SystemTime {
467    fn from(val: WinFiletime) -> Self {
468        filetime_to_system_time(val.0)
469    }
470}
471impl From<&WinFiletime> for SystemTime {
472    fn from(val: &WinFiletime) -> Self {
473        filetime_to_system_time(val.0)
474    }
475}
476impl From<Filetime> for SystemTime {
477    fn from(val: Filetime) -> Self {
478        filetime_to_system_time(val.original)
479    }
480}
481impl From<&Filetime> for SystemTime {
482    fn from(val: &Filetime) -> Self {
483        filetime_to_system_time(val.original)
484    }
485}
486
487impl WinFiletime {
488    pub fn new() -> Self {
489        Self(0)
490    }
491
492    /// Returns the year number 
493    /// 
494    /// ```rust
495    /// use forensic_rs::prelude::*;
496    /// let time = WinFiletime(125963224790010000); // 29-02-2000 18:27:59.001
497    /// assert_eq!(2000, time.year());
498    /// ```
499    pub fn year(&self) -> u32 {
500        let milliseconds_since_beginning = (self.0 as u128).div_euclid(10_000u128);
501        let days_since_beginning = milliseconds_since_beginning.div_euclid(60 * 60 * 24 * 1000);
502        let (year, _) = to_years(days_since_beginning);
503        year as u32
504    }
505
506    /// Returns the month number starting from 1
507    /// 
508    /// ```rust
509    /// use forensic_rs::prelude::*;
510    /// let time = WinFiletime(125963224790010000); // 29-02-2000 18:27:59.001
511    /// assert_eq!(2, time.month());
512    /// ```
513    pub fn month(&self) -> u32 {
514        let milliseconds_since_beginning = (self.0 as u128).div_euclid(10_000u128);
515        let days_since_beginning = milliseconds_since_beginning.div_euclid(60 * 60 * 24 * 1000);
516        let (year, restant_days) = to_years(days_since_beginning);
517        let (month, _acumulated_day_month) = if is_leap_year(year) {
518            [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335]
519                .iter()
520                .position(|&v| v > restant_days)
521                .map(|pos| {
522                    (
523                        pos,
524                        [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335][pos - 1],
525                    )
526                })
527        } else {
528            [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
529                .iter()
530                .position(|&v| v > restant_days)
531                .map(|pos| {
532                    (
533                        pos,
534                        [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334][pos - 1],
535                    )
536                })
537        }
538        .unwrap_or((12, 335));
539        month as u32
540    }
541
542    /// Returns the day of month starting from 1
543    /// 
544    /// ```rust
545    /// use forensic_rs::prelude::*;
546    /// let time = WinFiletime(125963224790010000); // 29-02-2000 18:27:59.001
547    /// assert_eq!(29, time.day());
548    /// ```
549    pub fn day(&self) -> u32 {
550        let milliseconds_since_beginning = (self.0 as u128).div_euclid(10_000u128);
551        let days_since_beginning = milliseconds_since_beginning.div_euclid(60 * 60 * 24 * 1000);
552        let (year, restant_days) = to_years(days_since_beginning);
553        let (_month, acumulated_day_month) = if is_leap_year(year) {
554            [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335]
555                .iter()
556                .position(|&v| v > restant_days)
557                .map(|pos| {
558                    (
559                        pos,
560                        [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335][pos - 1],
561                    )
562                })
563        } else {
564            [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
565                .iter()
566                .position(|&v| v > restant_days)
567                .map(|pos| {
568                    (
569                        pos,
570                        [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334][pos - 1],
571                    )
572                })
573        }
574        .unwrap_or((12, 335));
575        let day = restant_days.saturating_sub(acumulated_day_month) + 1;
576        day as u32
577    }
578
579    /// Returns the hour number from 0 to 23.
580    /// 
581    /// ```rust
582    /// use forensic_rs::prelude::*;
583    /// let time = WinFiletime(125963224790010000); // 29-02-2000 18:27:59.001
584    /// assert_eq!(18, time.hour());
585    /// ```
586    pub fn hour(&self) -> u32 {
587        let milliseconds_since_beginning = (self.0 as u128).div_euclid(10_000u128);
588        let days_since_beginning = milliseconds_since_beginning.div_euclid(60 * 60 * 24 * 1000);
589        let milliseconds_in_day = milliseconds_since_beginning - days_since_beginning *60 * 60 * 24 * 1000;
590        let hours = milliseconds_in_day.div_euclid(60 * 60 * 1000);
591        hours as u32
592    }
593
594    /// Returns the minute number from 0 to 59.
595    /// 
596    /// ```rust
597    /// use forensic_rs::prelude::*;
598    /// let time = WinFiletime(125963224790010000); // 29-02-2000 18:27:59.001
599    /// assert_eq!(27, time.minute());
600    /// ```
601    pub fn minute(&self) -> u32 {
602        let milliseconds_since_beginning = (self.0 as u128).div_euclid(10_000u128);
603        let days_since_beginning = milliseconds_since_beginning.div_euclid(60 * 60 * 24 * 1000);
604        let milliseconds_in_day = milliseconds_since_beginning - days_since_beginning *60 * 60 * 24 * 1000;
605        let hours = milliseconds_in_day.div_euclid(60 * 60 * 1000);
606        let rest_millis = milliseconds_in_day - hours * 60*60*1000;
607        let minute = rest_millis.div_euclid(60 * 1000);
608        minute as u32
609    }
610    /// Returns the second number from 0 to 59.
611    /// 
612    /// ```rust
613    /// use forensic_rs::prelude::*;
614    /// let time = WinFiletime(125963224790010000); // 29-02-2000 18:27:59.001
615    /// assert_eq!(59, time.second());
616    /// ```
617    pub fn second(&self) -> u32 {
618        let milliseconds_since_beginning = (self.0 as u128).div_euclid(10_000u128);
619        let days_since_beginning = milliseconds_since_beginning.div_euclid(60 * 60 * 24 * 1000);
620        let milliseconds_in_day = milliseconds_since_beginning - days_since_beginning *60 * 60 * 24 * 1000;
621        let hours = milliseconds_in_day.div_euclid(60 * 60 * 1000);
622        let rest_millis = milliseconds_in_day - hours * 60*60*1000;
623        let minute = rest_millis.div_euclid(60 * 1000);
624        let rest_millis = rest_millis - minute * 60 * 1000;
625        let seconds = rest_millis.div_euclid(1000);
626        seconds as u32
627    }
628    /// Obtain the millisecond part
629    /// 
630    /// ```rust
631    /// use forensic_rs::prelude::*;
632    /// let time = WinFiletime(125963224790010000); // 29-02-2000 18:27:59.001
633    /// assert_eq!(1, time.milliseconds());
634    /// ```
635    pub fn milliseconds(&self) -> u32 {
636        let milliseconds_since_beginning = (self.0 as u128).div_euclid(10_000u128);
637        let days_since_beginning = milliseconds_since_beginning.div_euclid(60 * 60 * 24 * 1000);
638        let milliseconds_in_day = milliseconds_since_beginning - days_since_beginning *60 * 60 * 24 * 1000;
639        let hours = milliseconds_in_day.div_euclid(60 * 60 * 1000);
640        let rest_millis = milliseconds_in_day - hours * 60*60*1000;
641        let minute = rest_millis.div_euclid(60 * 1000);
642        let rest_millis = rest_millis - minute * 60 * 1000;
643        let seconds = rest_millis.div_euclid(1000);
644        let millis = rest_millis - seconds*1000;
645        millis as u32
646    }
647    
648}
649
650impl PartialEq for Filetime {
651    fn eq(&self, other: &Self) -> bool {
652        self.original == other.original
653    }
654}
655impl Eq for Filetime {}
656
657impl PartialOrd for Filetime {
658    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
659        Some(self.original.cmp(&other.original))
660    }
661}
662
663impl Ord for Filetime {
664    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
665        self.original.cmp(&other.original)
666    }
667}
668
669#[test]
670fn should_generate_valid_windows_timestamps() {
671    assert_eq!(
672        1706969423596,
673        filetime_to_unix_timestamp(133514430235959706u64)
674    );
675    let time = filetime_to_system_time(133514430235959706u64); //Sat 3 February 2024 14:10:23 UTC = EPOCH 1706969423
676    assert_eq!(
677        1706969423,
678        time.duration_since(UNIX_EPOCH).unwrap().as_secs()
679    );
680    assert_eq!(
681        1706969423596,
682        time.duration_since(UNIX_EPOCH).unwrap().as_millis()
683    );
684    println!("{:?}", time.duration_since(UNIX_EPOCH).unwrap().as_millis());
685}
686
687#[test]
688fn should_transform_to_calendar() {
689    assert_eq!("01-02-2024 00:00:00", format!("{:?}", WinFiletime(133512192000000000)));
690    assert_eq!("01-01-2024 14:10:23", format!("{:?}", WinFiletime(133485918230000000)));
691    assert_eq!("03-02-2024 14:10:23", format!("{:?}", WinFiletime(133514430230000000)));
692    assert_eq!("03-02-2024 14:10:23", format!("{:?}", WinFiletime(133514430230000000)));
693    assert_eq!("01-01-1601 00:00:00", format!("{:?}", WinFiletime(0)));
694    assert_eq!("01-01-1602 00:00:00", format!("{:?}", WinFiletime(315360000000000)));
695    assert_eq!("01-01-1605 00:00:00", format!("{:?}", WinFiletime(1262304000000000)));
696    assert_eq!("14-11-1999 18:27:59", format!("{:?}", WinFiletime(125870776790000000)));
697    assert_eq!("14-11-2000 18:27:59", format!("{:?}", WinFiletime(126187000790000000)));
698    // 2000 is a leap year
699    assert_eq!("29-02-2000 18:27:59.001", format!("{:?}", WinFiletime(125963224790010000)));
700    // 1900 not a leap year
701    assert_eq!("01-03-1900 18:27:59", format!("{:?}", WinFiletime(94406488790000000)));
702    assert_eq!("28-02-1900 18:27:59", format!("{:?}", WinFiletime(94405624790000000)));
703
704    let time = WinFiletime(125963224790010000);
705    assert_eq!(29, time.day());
706    assert_eq!(2, time.month());
707    assert_eq!(2000, time.year());
708    assert_eq!(18, time.hour());
709    assert_eq!(27, time.minute());
710    assert_eq!(59, time.second());
711    assert_eq!(1, time.milliseconds());
712}
713
714#[test]
715fn should_transform_unix_to_calendar() {
716    assert_eq!("01-02-2024 00:00:00", format!("{:?}", UnixTimestamp(1706745600000)));
717    assert_eq!("01-01-2024 14:10:23", format!("{:?}", UnixTimestamp(1704118223000)));
718    assert_eq!("03-02-2024 14:10:23", format!("{:?}", UnixTimestamp(1706969423000)));
719    assert_eq!("01-01-1970 00:00:00", format!("{:?}", UnixTimestamp(0)));
720    assert_eq!("01-01-1972 00:00:00", format!("{:?}", UnixTimestamp(63072000000)));
721    assert_eq!("14-11-1999 18:27:59", format!("{:?}", UnixTimestamp(942604079000)));
722    assert_eq!("14-11-2000 18:27:59", format!("{:?}", UnixTimestamp(974226479000)));
723    // 2000 is a leap year
724    assert_eq!("29-02-2000 18:27:59.001", format!("{:?}", UnixTimestamp(951848879001)));
725}
726
727#[test]
728fn should_generate_valid_filetime() {
729    let time = Filetime::new(125963224790010000);
730    assert_eq!("29-02-2000 18:27:59.001", &format!("{}", time));
731    assert_eq!(time, Filetime::with_ymd_and_hms(2000, 2, 29, 18, 27, 59, 1000000));
732    let time = Filetime::new(94405624790010000);
733    assert_eq!(time, Filetime::with_ymd_and_hms(1900, 2, 28, 18, 27, 59, 1000000));
734    assert_eq!("28-02-1900 18:27:59.001", format!("{}", time));
735}