Verified Commit eb6ddac1 authored by jD91mZM2's avatar jD91mZM2
Browse files

Unify gmtime and localtime code

Apparently gmtime was already implemented when I made localtime, so we had two different things written from scratch. We decided in the relibc channel of the Redox OS Mattermost chat to use my code, as it is more extensively tested and perhaps is clearer in how it works.
parent 9cb594dc
Pipeline #1258 passed with stages
in 26 minutes and 24 seconds
use platform::types::*;
use super::constants::*;
// compute year, month, day & day of year
// for description of this algorithm see
// http://howardhinnant.github.io/date_algorithms.html#civil_from_days
#[inline(always)]
pub(crate) fn civil_from_days(days: c_long) -> (c_int, c_int, c_int, c_int) {
let (era, year): (c_int, c_int);
let (erayear, mut yearday, mut month, day): (c_int, c_int, c_int, c_int);
let eraday: c_ulong;
era = (if days >= 0 {
days
} else {
days - (DAYS_PER_ERA - 1)
} / DAYS_PER_ERA) as c_int;
eraday = (days - era as c_long * DAYS_PER_ERA) as c_ulong;
let a = eraday / (DAYS_PER_4_YEARS - 1);
let b = eraday / DAYS_PER_CENTURY;
let c = eraday / (DAYS_PER_ERA as c_ulong - 1);
erayear = ((eraday - a + b - c) / 365) as c_int;
let d = DAYS_PER_YEAR * erayear + erayear / 4 - erayear / 100;
yearday = (eraday - d as c_ulong) as c_int;
month = (5 * yearday + 2) / 153;
day = yearday - (153 * month + 2) / 5 + 1;
month += if month < 10 { 2 } else { -10 };
year = ADJUSTED_EPOCH_YEAR + erayear + era * YEARS_PER_ERA + (month <= 1) as c_int;
yearday += if yearday >= DAYS_PER_YEAR - DAYS_IN_JANUARY - DAYS_IN_FEBRUARY {
-(DAYS_PER_YEAR - DAYS_IN_JANUARY - DAYS_IN_FEBRUARY)
} else {
DAYS_IN_JANUARY + DAYS_IN_FEBRUARY + is_leap(erayear)
};
return (year, month, day, yearday);
}
#[inline(always)]
fn is_leap(y: c_int) -> c_int {
((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) as c_int
}
......@@ -8,10 +8,8 @@ use platform::types::*;
use platform::{Pal, Sys};
use self::constants::*;
use self::helpers::*;
pub mod constants;
mod helpers;
mod strftime;
#[repr(C)]
......@@ -158,54 +156,10 @@ pub extern "C" fn getdate(string: *const c_char) -> tm {
}
#[no_mangle]
pub extern "C" fn gmtime(timer: *const time_t) -> *mut tm {
pub unsafe extern "C" fn gmtime(timer: *const time_t) -> *mut tm {
unsafe { gmtime_r(timer, &mut TM) }
}
#[no_mangle]
pub extern "C" fn gmtime_r(clock: *const time_t, result: *mut tm) -> *mut tm {
let (mut days, mut rem): (c_long, c_long);
let mut weekday: c_int;
let lcltime = unsafe { *clock };
days = lcltime / SECSPERDAY + EPOCH_ADJUSTMENT_DAYS;
rem = lcltime % SECSPERDAY;
if rem < 0 {
rem += SECSPERDAY;
days -= 1;
}
unsafe {
(*result).tm_hour = (rem / SECSPERHOUR) as c_int;
rem %= SECSPERHOUR;
(*result).tm_min = (rem / SECSPERMIN) as c_int;
(*result).tm_sec = (rem % SECSPERMIN) as c_int;
}
weekday = ((ADJUSTED_EPOCH_WDAY + days) % DAYSPERWEEK as c_long) as c_int;
if weekday < 0 {
weekday += DAYSPERWEEK;
}
unsafe { (*result).tm_wday = weekday };
let (year, month, day, yearday) = civil_from_days(days);
unsafe {
(*result).tm_yday = yearday;
(*result).tm_year = year - YEAR_BASE;
(*result).tm_mon = month;
(*result).tm_mday = day;
(*result).tm_isdst = 0;
(*result).tm_gmtoff = 0;
(*result).tm_zone = UTC;
}
result
}
#[no_mangle]
pub unsafe extern "C" fn localtime(clock: *const time_t) -> *mut tm {
localtime_r(clock, &mut TM)
}
const MONTH_DAYS: [[c_int; 12]; 2] = [
// Non-leap years:
[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
......@@ -213,12 +167,13 @@ const MONTH_DAYS: [[c_int; 12]; 2] = [
[31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
];
#[inline(always)]
fn leap_year(year: c_int) -> bool {
year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
}
#[no_mangle]
pub unsafe extern "C" fn localtime_r(clock: *const time_t, t: *mut tm) -> *mut tm {
pub unsafe extern "C" fn gmtime_r(clock: *const time_t, t: *mut tm) -> *mut tm {
let clock = *clock;
let mut day = (clock / (60 * 60 * 24)) as c_int;
......@@ -288,11 +243,25 @@ pub unsafe extern "C" fn localtime_r(clock: *const time_t, t: *mut tm) -> *mut t
(*t).tm_mon += 1;
}
(*t).tm_mday = 1 + day as c_int;
(*t).tm_isdst = 0;
(*t).tm_gmtoff = 0;
(*t).tm_zone = UTC;
t
}
#[no_mangle]
pub unsafe extern "C" fn localtime(clock: *const time_t) -> *mut tm {
localtime_r(clock, &mut TM)
}
#[no_mangle]
pub unsafe extern "C" fn localtime_r(clock: *const time_t, t: *mut tm) -> *mut tm {
// TODO: Change tm_isdst, tm_gmtoff, tm_zone
gmtime_r(clock, t)
}
#[no_mangle]
pub unsafe extern "C" fn mktime(t: *mut tm) -> time_t {
let mut year = (*t).tm_year + 1900;
......
Year 69, Day of year: 333, Month 10, Day of month: 29, Day of week: 6, 0:0:0
Year 69, Day of year: 365, Month 11, Day of month: 31, Day of week: 3, 0:0:0
Year 69, Day of year: 365, Month 11, Day of month: 31, Day of week: 3, 23:59:59
Year 69, Day of year: 365, Month 11, Day of month: 31, Day of week: 3, 23:51:40
Year 70, Day of year: 0, Month 0, Day of month: 1, Day of week: 4, 0:0:0
Year 70, Day of year: 0, Month 0, Day of month: 1, Day of week: 4, 0:0:1
Year 118, Day of year: 193, Month 6, Day of month: 13, Day of week: 5, 4:9:10
Fri Jul 13 06:03:43 2018
......@@ -3,8 +3,8 @@
int main() {
int day = 60 * 60 * 24;
time_t inputs[] = { -(day * 33), -day, -500, 0, 1531454950 };
for (int i = 0; i < 5; i += 1) {
time_t inputs[] = { -(day * 33), -day, -1, -500, 0, 1, 1531454950 };
for (int i = 0; i < (sizeof(inputs) / sizeof(time_t)); i += 1) {
struct tm* t = localtime(&inputs[i]);
printf(
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment