strftime: ISO-8601 leap weeks
This commit is contained in:
@@ -208,6 +208,9 @@ pub unsafe fn strftime<W: WriteByte>(w: &mut W, format: *const c_char, t: *const
|
||||
// Sunday-based week of year: %U
|
||||
b'U' => w!("{}", ((*t).tm_yday + 7 - (*t).tm_wday) / 7),
|
||||
|
||||
// ISO-8601 week of year
|
||||
b'V' => w!("{}", week_of_year(unsafe { &*t })),
|
||||
|
||||
// Weekday (0-6, Sunday=0): %w
|
||||
b'w' => w!("{}", (*t).tm_wday),
|
||||
|
||||
@@ -246,3 +249,35 @@ pub unsafe fn strftime<W: WriteByte>(w: &mut W, format: *const c_char, t: *const
|
||||
}
|
||||
cw.written
|
||||
}
|
||||
|
||||
/// Calculate number of weeks in a year as defined by ISO 8601
|
||||
///
|
||||
/// ## Source
|
||||
/// 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
|
||||
} else {
|
||||
52
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate the week of the year accounting for leap weeks (ISO 8601)
|
||||
///
|
||||
/// ## Source
|
||||
/// https://en.wikipedia.org/wiki/ISO_week_date
|
||||
fn week_of_year(time: &tm) -> c_int {
|
||||
let week = (10 + time.tm_yday - time.tm_wday) / 7;
|
||||
|
||||
if week <= 1 {
|
||||
weeks_per_year(time.tm_year - 1)
|
||||
} else if week > weeks_per_year(time.tm_year) {
|
||||
1
|
||||
} else {
|
||||
week
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,3 +7,8 @@
|
||||
6: 197 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
|
||||
52
|
||||
52
|
||||
1
|
||||
53
|
||||
|
||||
@@ -7,3 +7,8 @@
|
||||
6: 197 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
|
||||
52
|
||||
52
|
||||
1
|
||||
53
|
||||
|
||||
+50
-3
@@ -4,11 +4,53 @@
|
||||
|
||||
#include "test_helpers.h"
|
||||
|
||||
#define PRINT_BUFSZ 50
|
||||
#define V_BUFSZ 3
|
||||
|
||||
void print(time_t timestamp, char* fmt) {
|
||||
char* out = malloc(50);
|
||||
size_t n = strftime(out, 50, fmt, localtime(×tamp));
|
||||
char out[PRINT_BUFSZ] = {0};
|
||||
size_t n = strftime(out, PRINT_BUFSZ, fmt, localtime(×tamp));
|
||||
printf("%zu: %s\n", n, out);
|
||||
free(out);
|
||||
}
|
||||
|
||||
void test_v(void) {
|
||||
char buf[V_BUFSZ] = {0};
|
||||
struct tm time = {0};
|
||||
|
||||
// Example dates copied from Wikipedia
|
||||
// Saturday 2005-01-01
|
||||
time.tm_yday = 0;
|
||||
time.tm_wday = 6;
|
||||
time.tm_year = 2005;
|
||||
strftime(buf, V_BUFSZ, "%V", &time);
|
||||
puts(buf);
|
||||
|
||||
// Saturday 2005-12-31
|
||||
time.tm_yday = 365;
|
||||
time.tm_wday = 6;
|
||||
strftime(buf, V_BUFSZ, "%V", &time);
|
||||
puts(buf);
|
||||
|
||||
// Sunday 2006-01-01
|
||||
time.tm_yday = 0;
|
||||
time.tm_wday = 0;
|
||||
time.tm_year = 2006;
|
||||
strftime(buf, V_BUFSZ, "%V", &time);
|
||||
puts(buf);
|
||||
|
||||
// Sunday 2008-12-28
|
||||
time.tm_yday = 362;
|
||||
time.tm_wday = 0;
|
||||
time.tm_year = 2008;
|
||||
strftime(buf, V_BUFSZ, "%V", &time);
|
||||
puts(buf);
|
||||
|
||||
// Friday 2010-01-01
|
||||
time.tm_yday = 0;
|
||||
time.tm_wday = 5;
|
||||
time.tm_year = 2010;
|
||||
strftime(buf, V_BUFSZ, "%V", &time);
|
||||
puts(buf);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
@@ -21,4 +63,9 @@ int main(void) {
|
||||
print(1531839600, "%j %U");
|
||||
print(1531839600, "%+");
|
||||
print(1533669431, "%+%+%+%+%+"); // will overflow 50 characters
|
||||
|
||||
// ISO-8601 tests
|
||||
test_v();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user