I am trying to format SystemTime
as a String in Rust without using external crates, but I am facing a bizarre issue regarding the "day" field.
Can anyone explain me why the line preceded by the "FIXME" comment yields slightly wrong month days as the time distance from Thu, 01 Jan 1970 00:00:00 GMT
increases?
fn time_to_http_date_string(time: &SystemTime) -> String {
const MINUTE: u64 = 60;
const HOUR: u64 = 3600;
const DAY: u64 = 86400;
const WEEKDAYS: [&str; 7] = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
const MONTH: u64 = 2629743;
const MONTHS: [&str; 12] = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
const YEAR: u64 = 31556926;
let time = time.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs();
let year = 1970 + (time / YEAR);
let month = MONTHS[(time % YEAR / MONTH) as usize];
let weekday = WEEKDAYS[((time / DAY + 4) % 7) as usize];
// FIXME: Slightly wrong as time distance from the UNIX epoch increases.
let day = (time % MONTH / DAY) + 1;
let hour = time % DAY / HOUR;
let minute = time % HOUR / MINUTE;
let second = time % MINUTE;
format!(
"{weekday}, {day:02} {month} {year} {hour:02}:{minute:02}:{second:02} GMT",
weekday = weekday,
day = day,
month = month,
year = year,
hour = hour,
minute = minute,
second = second,
)
}
Let me give you more details about this issue; here are some tests I ran this function through:
Unix Timestamp | Expected | Mine | OK |
---|---|---|---|
0 | Thu, 01 Jan 1970 00:00:00 GMT | Thu, 01 Jan 1970 00:00:00 GMT | 👍 |
68169600 | Tue, 29 Feb 1972 00:00:00 GMT | Tue, 29 Feb 1972 00:00:00 GMT | 👍 |
874540800 | Thu, 18 Sep 1997 00:00:00 GMT | Thu, 17 Sep 1997 00:00:00 GMT | ❌ |
1052790840 | Tue, 13 May 2003 01:54:00 GMT | Tue, 11 May 2003 01:54:00 GMT | ❌ |
As you may have already noticed from my test cases, the day is the only wrong field in any of the failing cases. Any ideas about the culprit?
PS: I have already tried to use f64 instead of u64 and to round the results... but it didn't fix all of the test cases.
It turns out I was looking for an impossible solution. It is indeed impossible to perform such a computation without taking into account leap years and the simple fact that months do not share the same duration in days. Even though now I feel a bit dumb about posting this question, I'd like to thank the people who first commented this thread. They pushed me in the right direction.