Skip to content
Snippets Groups Projects
Unverified Commit 43e6cad3 authored by Jeremy Soller's avatar Jeremy Soller Committed by GitHub
Browse files

Merge pull request #112 from jeizsm/master

add gmtime and difftime
parents 93e2e160 8015878a
No related branches found
No related tags found
No related merge requests found
#[cfg(target_os = "linux")]
#[path = "linux.rs"]
pub mod sys;
#[cfg(target_os = "redox")]
#[path = "redox.rs"]
pub mod sys;
pub use sys::*;
use platform::types::*;
// Move epoch from 01.01.1970 to 01.03.0000 (yes, Year 0) - this is the first
// day of a 400-year long "era", right after additional day of leap year.
// This adjustment is required only for date calculation, so instead of
// modifying time_t value (which would require 64-bit operations to work
// correctly) it's enough to adjust the calculated number of days since epoch.
pub(crate) const EPOCH_ADJUSTMENT_DAYS: c_long = 719468;
// year to which the adjustment was made
pub(crate) const ADJUSTED_EPOCH_YEAR: c_int = 0;
// 1st March of year 0 is Wednesday
pub(crate) const ADJUSTED_EPOCH_WDAY: c_long = 3;
pub(crate) const DAYS_PER_ERA: c_long = (400 - 97) * 365 + 97 * 366;
pub(crate) const DAYS_PER_CENTURY: c_ulong = (100 - 24) * 365 + 24 * 366;
pub(crate) const DAYS_PER_4_YEARS: c_ulong = 3 * 365 + 366;
pub(crate) const DAYS_PER_YEAR: c_int = 365;
pub(crate) const DAYS_IN_JANUARY: c_int = 31;
pub(crate) const DAYS_IN_FEBRUARY: c_int = 28;
pub(crate) const YEARS_PER_ERA: c_int = 400;
pub(crate) const SECSPERMIN: c_long = 60;
pub(crate) const MINSPERHOUR: c_long = 60;
pub(crate) const HOURSPERDAY: c_long = 24;
pub(crate) const SECSPERHOUR: c_long = SECSPERMIN * MINSPERHOUR;
pub(crate) const SECSPERDAY: c_long = SECSPERHOUR * HOURSPERDAY;
pub(crate) const DAYSPERWEEK: c_int = 7;
pub(crate) const YEAR_BASE: c_int = 1900;
pub(crate) const UTC: *const c_char = b"UTC\0" as *const u8 as *const c_char;
use constants::*;
use platform::types::*;
// 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
}
//! time implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/time.h.html //! time implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/time.h.html
#![no_std] #![no_std]
#![feature(const_fn)]
extern crate platform; extern crate platform;
use platform::types::*; pub mod constants;
mod helpers;
#[cfg(target_os = "redox")] use platform::types::*;
pub const CLOCK_REALTIME: c_int = 1; use constants::*;
#[cfg(target_os = "redox")] use helpers::*;
pub const CLOCK_MONOTONIC: c_int = 4;
#[cfg(target_os = "linux")]
pub const CLOCK_REALTIME: c_int = 0;
#[cfg(target_os = "linux")]
pub const CLOCK_MONOTONIC: c_int = 1;
#[cfg(target_os = "linux")]
pub const CLOCK_PROCESS_CPUTIME_ID: c_int = 2;
#[cfg(target_os = "linux")]
pub const CLOCK_THREAD_CPUTIME_ID: c_int = 3;
#[cfg(target_os = "linux")]
pub const CLOCK_MONOTONIC_RAW: c_int = 4;
#[cfg(target_os = "linux")]
pub const CLOCK_REALTIME_COARSE: c_int = 5;
#[cfg(target_os = "linux")]
pub const CLOCK_MONOTONIC_COARSE: c_int = 6;
#[cfg(target_os = "linux")]
pub const CLOCK_BOOTTIME: c_int = 7;
#[cfg(target_os = "linux")]
pub const CLOCK_REALTIME_ALARM: c_int = 8;
#[cfg(target_os = "linux")]
pub const CLOCK_BOOTTIME_ALARM: c_int = 9;
#[cfg(target_os = "linux")]
pub const CLOCK_TAI: c_int = 11;
/* /*
*#[repr(C)] *#[repr(C)]
...@@ -56,6 +35,23 @@ pub struct tm { ...@@ -56,6 +35,23 @@ pub struct tm {
pub tm_zone: *const c_char, pub tm_zone: *const c_char,
} }
unsafe impl Sync for tm {}
// The C Standard says that localtime and gmtime return the same pointer.
static mut TM: tm = tm {
tm_sec: 0,
tm_min: 0,
tm_hour: 0,
tm_mday: 0,
tm_mon: 0,
tm_year: 0,
tm_wday: 0,
tm_yday: 0,
tm_isdst: 0,
tm_gmtoff: 0,
tm_zone: UTC,
};
#[repr(C)] #[repr(C)]
pub struct itimerspec { pub struct itimerspec {
pub it_interval: timespec, pub it_interval: timespec,
...@@ -105,8 +101,8 @@ pub extern "C" fn ctime_r(clock: *const time_t, buf: *mut c_char) -> *mut c_char ...@@ -105,8 +101,8 @@ pub extern "C" fn ctime_r(clock: *const time_t, buf: *mut c_char) -> *mut c_char
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn difftime(time1: time_t, time0: time_t) -> f64 { pub extern "C" fn difftime(time1: time_t, time0: time_t) -> c_double {
unimplemented!(); (time1 - time0) as c_double
} }
#[no_mangle] #[no_mangle]
...@@ -116,12 +112,46 @@ pub extern "C" fn getdate(string: *const c_char) -> tm { ...@@ -116,12 +112,46 @@ pub extern "C" fn getdate(string: *const c_char) -> tm {
#[no_mangle] #[no_mangle]
pub extern "C" fn gmtime(timer: *const time_t) -> *mut tm { pub extern "C" fn gmtime(timer: *const time_t) -> *mut tm {
unimplemented!(); unsafe { gmtime_r(timer, &mut TM) }
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn gmtime_r(clock: *const time_t, result: *mut tm) -> *mut tm { pub extern "C" fn gmtime_r(clock: *const time_t, result: *mut tm) -> *mut tm {
unimplemented!(); 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] #[no_mangle]
......
use platform::types::*;
pub const CLOCK_REALTIME: c_int = 0;
pub const CLOCK_MONOTONIC: c_int = 1;
pub const CLOCK_PROCESS_CPUTIME_ID: c_int = 2;
pub const CLOCK_THREAD_CPUTIME_ID: c_int = 3;
pub const CLOCK_MONOTONIC_RAW: c_int = 4;
pub const CLOCK_REALTIME_COARSE: c_int = 5;
pub const CLOCK_MONOTONIC_COARSE: c_int = 6;
pub const CLOCK_BOOTTIME: c_int = 7;
pub const CLOCK_REALTIME_ALARM: c_int = 8;
pub const CLOCK_BOOTTIME_ALARM: c_int = 9;
pub const CLOCK_TAI: c_int = 11;
use platform::types::*;
pub const CLOCK_REALTIME: c_int = 1;
pub const CLOCK_MONOTONIC: c_int = 4;
...@@ -49,3 +49,4 @@ ...@@ -49,3 +49,4 @@
/waitpid /waitpid
/write /write
/time /time
/gmtime
...@@ -43,7 +43,8 @@ EXPECT_BINS=\ ...@@ -43,7 +43,8 @@ EXPECT_BINS=\
unlink \ unlink \
waitpid \ waitpid \
write \ write \
time time \
gmtime
# Binaries that may generate varied output # Binaries that may generate varied output
BINS=\ BINS=\
......
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char** argv) {
time_t a = 0;
tm expected = { .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = 1, .tm_year = 70,
.tm_wday = 4, .tm_yday = 0, .tm_isdst = 0, .tm_gmtoff = 0, .tm_zone = "UTC" };
tm *info = gmtime(&a);
if (info->tm_sec != expected.tm_sec || info->tm_min != expected.tm_min ||
info->tm_hour != expected.tm_hour || info->tm_mday != expected.tm_mday ||
info->tm_year != expected.tm_year || info->tm_wday != expected.tm_wday ||
info->tm_yday != expected.tm_yday || info->tm_isdst != expected.tm_isdst ||
info->tm_gmtoff != expected.tm_gmtoff || strcmp(info->tm_zone, expected.tm_zone) != 0) {
exit(1);
}
if (info->tm_sec != expected.tm_sec || info->tm_min != expected.tm_min ||
info->tm_hour != expected.tm_hour || info->tm_mday != expected.tm_mday ||
info->tm_year != expected.tm_year || info->tm_wday != expected.tm_wday ||
info->tm_yday != expected.tm_yday || info->tm_isdst != expected.tm_isdst ||
info->tm_gmtoff != expected.tm_gmtoff || strcmp(info->tm_zone, expected.tm_zone) != 0) {
exit(1);
}
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment