time_c/
sys.rs

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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//!Raw system types and functions
#![allow(non_camel_case_types)]

use crate::Time;

use core::{mem, ptr};
use core::ffi::{c_void, c_int, c_long};

///Alias to time_t.
///
///This crate supports 64bit time only
///
///## Note
///
///Your system uses 32bit for time()? Don't use this crate then
pub type time_t = i64;

#[repr(C)]
#[derive(Copy, Clone, Debug)]
///C definition of decoded time.
pub struct tm {
    ///Seconds after the minute. Range 0-60
    pub tm_sec: c_int,
    ///Minutes after the hour. Range 0-59
    pub tm_min: c_int,
    ///Hours since midnight. Range 0-23
    pub tm_hour: c_int,
    ///Day of the month. Range 1-31
    pub tm_mday: c_int,
    ///Months since January. Range 0-11
    pub tm_mon: c_int,
    ///Years since 1900
    pub tm_year: c_int,
    ///days since Sunday. Range 0-6
    pub tm_wday: c_int,
    ///days since January 1. Range 0-365
    pub tm_yday: c_int,
    /// Daylight Saving Time flag. Non-zero value indicates DST is present.
    pub tm_isdst: c_int,
    //Other fields are non-standard and depend on platform
    //So don't care about these fields
    _reserved: mem::MaybeUninit<[u8; mem::size_of::<c_long>() + mem::size_of::<*const c_void>() + mem::size_of::<c_int>()]>,
}

impl tm {
    ///Normalizes time to a more convenient struct for interpreting time components.
    pub const fn normalize(&self) -> Time {
        let tm {
            tm_sec,
            tm_min,
            tm_hour,
            tm_mday,
            tm_mon,
            tm_year,
            tm_wday,
            tm_yday,
            tm_isdst,
            ..
        } = self;

        Time {
            sec: *tm_sec as _,
            min: *tm_min as _,
            hour: *tm_hour as _,
            month_day: *tm_mday as _,
            month: (*tm_mon as u8).saturating_add(1),
            year: (*tm_year as u16).saturating_add(1900),
            week_day: *tm_wday as _,
            day: *tm_yday as _,
            is_dst: *tm_isdst > 0,
        }
    }
}

extern "C" {
    #[cfg_attr(windows, link_name = "_time64")]
    ///Raw C API function to access time
    pub fn time(time: *mut time_t) -> time_t;
}

///Gets current UTC time, if available.
pub fn get_time() -> Option<time_t> {
    let result = unsafe {
        time(ptr::null_mut())
    };

    match result {
        -1 => None,
        time => Some(time)
    }
}


#[cfg(windows)]
///Parses UTC time into tm struct, if possible
pub fn utc_time(timer: &time_t) -> Option<tm> {
    extern "C" {
        #[link_name = "_gmtime64_s"]
        pub fn gmtime_s(buf: *mut tm, timer: *const time_t) -> c_int;
    }

    let mut tm = mem::MaybeUninit::uninit();
    let res = unsafe {
        gmtime_s(tm.as_mut_ptr(), timer)
    };
    match res {
        0 => unsafe {
            Some(tm.assume_init())
        },
        _ => None,
    }
}

#[cfg(not(windows))]
///Parses UTC time into tm struct, if possible
pub fn utc_time(timer: &time_t) -> Option<tm> {
    extern "C" {
        pub fn gmtime_r(timer: *const time_t, buf: *mut tm) -> *mut tm;
    }

    let mut tm = mem::MaybeUninit::uninit();
    let res = unsafe {
        gmtime_r(timer, tm.as_mut_ptr())
    };
    if res.is_null() {
        None
    } else {
        unsafe {
            Some(tm.assume_init())
        }
    }
}