/* * meli - melib POSIX libc time interface * * Copyright 2020 Manos Pitsidianakis * * This file is part of meli. * * meli is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * meli is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with meli. If not, see . */ use std::convert::TryInto; use std::ffi::{CStr, CString}; pub type UnixTimestamp = u64; use libc::{timeval, timezone}; extern "C" { fn strptime( s: *const ::std::os::raw::c_char, format: *const ::std::os::raw::c_char, tm: *mut ::libc::tm, ) -> *const ::std::os::raw::c_char; fn strftime( s: *mut ::std::os::raw::c_char, max: ::libc::size_t, format: *const ::std::os::raw::c_char, tm: *const ::libc::tm, ) -> ::libc::size_t; fn mktime(tm: *const ::libc::tm) -> ::libc::time_t; fn localtime_r(timep: *const ::libc::time_t, tm: *mut ::libc::tm) -> *mut ::libc::tm; fn gettimeofday(tv: *mut timeval, tz: *mut timezone) -> i32; } pub fn timestamp_to_string(timestamp: UnixTimestamp, fmt: Option<&str>) -> String { let mut new_tm: ::libc::tm = unsafe { std::mem::zeroed() }; unsafe { let i: i64 = timestamp.try_into().unwrap_or(0); localtime_r(&i as *const i64, &mut new_tm as *mut ::libc::tm); } let fmt = fmt.map(|slice| CString::new(slice).unwrap()); let format: &CStr = if let Some(ref s) = fmt { &s } else { unsafe { CStr::from_bytes_with_nul_unchecked(b"%a, %d %b %Y %T %z\0") } }; let s: CString; unsafe { let mut vec: [u8; 256] = [0; 256]; let ret = strftime( vec.as_mut_ptr() as *mut _, 256, format.as_ptr(), &new_tm as *const _, ); s = CString::new(&vec[0..ret]).unwrap(); } s.to_string_lossy().to_string() } pub fn rfc822_to_timestamp(s: T) -> UnixTimestamp where T: Into>, { let mut new_tm: ::libc::tm = unsafe { std::mem::zeroed() }; unsafe { let fmt = CStr::from_bytes_with_nul_unchecked(b"%a, %e %h %Y %H:%M:%S %z\0"); let ret = strptime( CString::new(s).unwrap().as_ptr(), fmt.as_ptr(), &mut new_tm as *mut _, ); if ret.is_null() { return 0; } return mktime(&new_tm as *const _) as u64; } } pub fn timestamp_from_string(s: T, fmt: &str) -> Option where T: Into>, { let mut new_tm: ::libc::tm = unsafe { std::mem::zeroed() }; let fmt = CString::new(fmt).unwrap(); unsafe { let ret = strptime( CString::new(s).unwrap().as_ptr(), fmt.as_ptr(), &mut new_tm as *mut _, ); if ret.is_null() { return None; } return Some(mktime(&new_tm as *const _) as u64); } } pub fn now() -> UnixTimestamp { use std::mem::MaybeUninit; let mut tv = MaybeUninit::<::libc::timeval>::uninit(); let mut tz = MaybeUninit::<::libc::timezone>::uninit(); unsafe { let ret = gettimeofday(tv.as_mut_ptr(), tz.as_mut_ptr()); if ret == -1 { unreachable!("gettimeofday returned -1"); } (tv.assume_init()).tv_sec as UnixTimestamp } } #[test] fn test_timestamp() { timestamp_to_string(0); }