Merge branch 'time-improvements' into 'master'
Time improvements See merge request redox-os/relibc!635
This commit is contained in:
+12
-3
@@ -382,9 +382,8 @@ pub unsafe extern "C" fn mktime(timeptr: *mut tm) -> time_t {
|
||||
}
|
||||
};
|
||||
|
||||
let offset = FixedOffset::east((*timeptr).tm_gmtoff as _);
|
||||
let offset = get_offset((*timeptr).tm_gmtoff).unwrap();
|
||||
let tz = time_zone();
|
||||
|
||||
// Create DateTime<FixedOffset>
|
||||
let datetime = match offset.from_local_datetime(&naive_local) {
|
||||
MappedLocalTime::Single(datetime) => datetime,
|
||||
@@ -486,11 +485,12 @@ pub unsafe extern "C" fn timelocal(tm: *mut tm) -> time_t {
|
||||
None => return -1,
|
||||
};
|
||||
|
||||
let tz_name = CString::new(tz.name()).unwrap();
|
||||
(*tm).tm_wday = dt.weekday().num_days_from_sunday() as _;
|
||||
(*tm).tm_yday = dt.ordinal0() as _; // day of year starting at 0
|
||||
(*tm).tm_isdst = dt.offset().dst_offset().num_hours() as _;
|
||||
(*tm).tm_gmtoff = dt.offset().fix().local_minus_utc() as _;
|
||||
(*tm).tm_zone = UTC_STR.as_ptr() as *const c_char;
|
||||
(*tm).tm_zone = tz_name.into_raw().cast();
|
||||
|
||||
dt.timestamp()
|
||||
}
|
||||
@@ -726,6 +726,15 @@ unsafe fn set_timezone(
|
||||
timezone = -c_long::from(ut_offset.fix().local_minus_utc());
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub const fn get_offset(off: c_long) -> Option<FixedOffset> {
|
||||
if off < 0 {
|
||||
FixedOffset::west_opt(off as _)
|
||||
} else {
|
||||
FixedOffset::east_opt(off as _)
|
||||
}
|
||||
}
|
||||
|
||||
const fn blank_tm() -> tm {
|
||||
tm {
|
||||
tm_year: 0,
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
// Following https://pubs.opengroup.org/onlinepubs/7908799/xsh/strftime.html
|
||||
use alloc::string::String;
|
||||
|
||||
use super::tm;
|
||||
use crate::platform::{self, types::*, WriteByte};
|
||||
use super::{get_offset, tm};
|
||||
use crate::{
|
||||
c_str::CStr,
|
||||
platform::{self, types::*, WriteByte},
|
||||
};
|
||||
|
||||
// We use the langinfo constants
|
||||
use crate::header::langinfo::{
|
||||
@@ -157,7 +160,7 @@ pub unsafe fn strftime<W: WriteByte>(w: &mut W, format: *const c_char, t: *const
|
||||
b'I' => w!("{:02}", ((*t).tm_hour + 12 - 1) % 12 + 1),
|
||||
|
||||
// Day of year: %j
|
||||
b'j' => w!("{:03}", (*t).tm_yday),
|
||||
b'j' => w!("{:03}", (*t).tm_yday + 1),
|
||||
|
||||
// etc.
|
||||
b'k' => w!("{:2}", (*t).tm_hour),
|
||||
@@ -223,11 +226,22 @@ pub unsafe fn strftime<W: WriteByte>(w: &mut W, format: *const c_char, t: *const
|
||||
// Full year: %Y
|
||||
b'Y' => w!("{}", (*t).tm_year + 1900),
|
||||
|
||||
// Timezone offset: %z => currently hard-coded "+0000"
|
||||
b'z' => w!("+0000"), // TODO: Add real timezone support
|
||||
// Timezone offset: %z
|
||||
b'z' => {
|
||||
let offset = (*t).tm_gmtoff;
|
||||
let (sign, offset) = if offset < 0 {
|
||||
('-', -offset)
|
||||
} else {
|
||||
('+', offset)
|
||||
};
|
||||
let mins = offset.div_euclid(60);
|
||||
let min = mins.rem_euclid(60);
|
||||
let hour = mins.div_euclid(60);
|
||||
w!("{}{:02}{:02}", sign, hour, min)
|
||||
}
|
||||
|
||||
// Timezone name: %Z => currently "UTC"
|
||||
b'Z' => w!("UTC"), // TODO: Add real timezone name support
|
||||
// Timezone name: %Z
|
||||
b'Z' => w!("{}", CStr::from_ptr((*t).tm_zone).to_str().unwrap()),
|
||||
|
||||
// Date+time+TZ: %+
|
||||
b'+' => w!(recurse "%a %b %d %T %Z %Y"),
|
||||
@@ -256,8 +270,6 @@ pub unsafe fn strftime<W: WriteByte>(w: &mut W, format: *const c_char, t: *const
|
||||
/// https://en.wikipedia.org/wiki/ISO_week_date
|
||||
fn weeks_per_year(year: c_int) -> c_int {
|
||||
let year = year as f64;
|
||||
// TODO: This function can be made const on newer Rust compilers but this line prevents it on
|
||||
// our version in CI
|
||||
let p_y = (year + (year / 4.) - (year / 100.) + (year / 400.)) as c_int % 7;
|
||||
if p_y == 4 {
|
||||
53
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
11: 03:00:00 PM
|
||||
5: 15:00
|
||||
15: 15 1531839600 2
|
||||
6: 197 28
|
||||
6: 198 28
|
||||
28: Tue Jul 17 15:00:00 UTC 2018
|
||||
0: Tue Aug 07 19:17:11 UTC 2018Tue Aug 07 19:17:11 U
|
||||
53
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
11: 03:00:00 PM
|
||||
5: 15:00
|
||||
15: 15 1531839600 2
|
||||
6: 197 28
|
||||
6: 198 28
|
||||
28: Tue Jul 17 15:00:00 UTC 2018
|
||||
0: Tue Aug 07 19:17:11 UTC 2018Tue Aug 07 19:17:11 U
|
||||
53
|
||||
|
||||
+97
-1
@@ -1,16 +1,110 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include "test_helpers.h"
|
||||
|
||||
#define PRINT_BUFSZ 50
|
||||
#define V_BUFSZ 3
|
||||
#define BUFS 30
|
||||
|
||||
void print(time_t timestamp, char* fmt) {
|
||||
char out[PRINT_BUFSZ] = {0};
|
||||
size_t n = strftime(out, PRINT_BUFSZ, fmt, localtime(×tamp));
|
||||
printf("%zu: %s\n", n, out);
|
||||
|
||||
}
|
||||
|
||||
void strftime_mix(void) {
|
||||
setenv("TZ", "Australia/Melbourne", 1);
|
||||
tzset();
|
||||
|
||||
// Initialize a struct tm with a known fixed date and time.
|
||||
// December 31, 2020 23:59:59, which is a Thursday.
|
||||
struct tm t = {0};
|
||||
t.tm_year = 2020 - 1900; // Years since 1900.
|
||||
t.tm_mon = 11; // December (0-based, so 11 means December).
|
||||
t.tm_mday = 31;
|
||||
t.tm_hour = 23;
|
||||
t.tm_min = 59;
|
||||
t.tm_sec = 59;
|
||||
t.tm_wday = 4; // Thursday (0 = Sunday, so Thursday = 4).
|
||||
t.tm_yday = 365;
|
||||
t.tm_gmtoff = 39600; // GMT offset for AEDT (UTC+11).
|
||||
t.tm_isdst = 11; // Daylight saving time is in effect.
|
||||
t.tm_zone = "AEDT"; // Time zone name.
|
||||
char buf[BUFS];
|
||||
|
||||
strftime(buf, BUFS, "%a", &t);
|
||||
assert(strcmp(buf, "Thu") == 0);
|
||||
|
||||
strftime(buf, BUFS, "%A", &t);
|
||||
assert(strcmp(buf, "Thursday") == 0);
|
||||
|
||||
strftime(buf, BUFS, "%b", &t);
|
||||
assert(strcmp(buf, "Dec") == 0);
|
||||
|
||||
strftime(buf, BUFS, "%B", &t);
|
||||
assert(strcmp(buf, "December") == 0);
|
||||
|
||||
strftime(buf, BUFS, "%d", &t);
|
||||
assert(strcmp(buf, "31") == 0);
|
||||
|
||||
strftime(buf, BUFS, "%H", &t);
|
||||
assert(strcmp(buf, "23") == 0);
|
||||
|
||||
strftime(buf, BUFS, "%I", &t);
|
||||
assert(strcmp(buf, "11") == 0);
|
||||
|
||||
// Day of the year as a zero-padded decimal number (001-366).
|
||||
strftime(buf, BUFS, "%j", &t);
|
||||
// Even though t.tm_yday is 365 (zero-based), %j is one-based: "366"
|
||||
assert(strcmp(buf, "366") == 0);
|
||||
|
||||
strftime(buf, BUFS, "%m", &t);
|
||||
assert(strcmp(buf, "12") == 0);
|
||||
|
||||
strftime(buf, BUFS, "%M", &t);
|
||||
assert(strcmp(buf, "59") == 0);
|
||||
|
||||
strftime(buf, BUFS, "%p", &t);
|
||||
assert(strcmp(buf, "PM") == 0);
|
||||
|
||||
strftime(buf, BUFS, "%S", &t);
|
||||
assert(strcmp(buf, "59") == 0);
|
||||
|
||||
strftime(buf, BUFS, "%U", &t);
|
||||
assert(strcmp(buf, "52") == 0);
|
||||
|
||||
strftime(buf, BUFS, "%w", &t);
|
||||
assert(strcmp(buf, "4") == 0);
|
||||
|
||||
strftime(buf, BUFS, "%W", &t);
|
||||
assert(strcmp(buf, "52") == 0);
|
||||
|
||||
strftime(buf, BUFS, "%y", &t);
|
||||
assert(strcmp(buf, "20") == 0);
|
||||
|
||||
strftime(buf, BUFS, "%Y", &t);
|
||||
assert(strcmp(buf, "2020") == 0);
|
||||
|
||||
strftime(buf, BUFS, "%Z", &t);
|
||||
assert(strcmp(buf, "AEDT") == 0);
|
||||
|
||||
strftime(buf, BUFS, "%z", &t);
|
||||
assert(strcmp(buf, "+1100") == 0);
|
||||
|
||||
strftime(buf, BUFS, "%F", &t);
|
||||
assert(strcmp(buf, "2020-12-31") == 0);
|
||||
|
||||
strftime(buf, BUFS, "%R", &t);
|
||||
assert(strcmp(buf, "23:59") == 0);
|
||||
|
||||
strftime(buf, BUFS, "%r", &t);
|
||||
assert(strcmp(buf, "11:59:59 PM") == 0);
|
||||
|
||||
strftime(buf, BUFS, "%T", &t);
|
||||
assert(strcmp(buf, "23:59:59") == 0);
|
||||
}
|
||||
|
||||
void test_v(void) {
|
||||
@@ -67,5 +161,7 @@ int main(void) {
|
||||
// ISO-8601 tests
|
||||
test_v();
|
||||
|
||||
strftime_mix();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user