chrono
chrono copied to clipboard
SystemTimeToTzSpecificLocalTime failed with: The parameter is incorrect. (os error 87)
We're getting a panic from chrono here when run on a Windows 2012 server:
thread '<unnamed>' panicked at 'SystemTimeToTzSpecificLocalTime failed with: The parameter is incorrect. (os error 87)',
/cargo/registry/src/github.com-1ecc6299db9ec823/chrono-0.4.19/src/sys/windows.rs:97:9
stack backtrace:
0: rust_begin_unwind
at /rustc/db9d1b20bba1968c1ec1fc49616d4742c1725b4b\/library\std\src/panicking.rs:498:5
1: core::panicking::panic_fmt
at /rustc/db9d1b20bba1968c1ec1fc49616d4742c1725b4b\/library\core\src/panicking.rs:107:14
2: chrono::sys::inner::time_to_local_tm
3: <chrono::offset::local::Local as chrono::offset::TimeZone>::from_utc_datetime
4: <chrono::datetime::DateTime<chrono::offset::local::Local> as core::convert::From<std::time::SystemTime>>::from
...
We debugged the SystemTime we were getting and it was:
SystemTime {
intervals: 147221225472,
}
A normal intervals value (e.g. 132790361186042732) is much larger.
I'm assuming there's something about this unusually short SystemTime that's causing chrono to panic.
use std::{io, mem};
use winapi::{shared::minwindef::*, um::timezoneapi::*};
fn main() {
// works - 132790361186042732
// fails - 147221225472
let t = 147221225472 as u64;
let ft = FILETIME {
dwLowDateTime: t as DWORD,
dwHighDateTime: (t >> 32) as DWORD,
};
unsafe {
let mut utc = mem::zeroed();
let mut local = mem::zeroed();
FileTimeToSystemTime(&ft, &mut utc);
dbg!(&utc.wYear); // 1601
dbg!(&utc.wMonth); // 1
dbg!(&utc.wDayOfWeek); // 1 (Monday)
dbg!(&utc.wDay); // 1
dbg!(&utc.wHour);
dbg!(&utc.wMinute);
dbg!(&utc.wSecond);
dbg!(&utc.wMilliseconds);
SystemTimeToTzSpecificLocalTime(0 as *const _, &mut utc, &mut local); // returns 0 (failure)
dbg!(io::Error::last_os_error()); // InvalidInput
}
}
Those debug statements tell you that the SystemTime is January 1, 1601. And while that seems totally ridiculous, it should be a valid date according to Microsoft documentation. Despite this, passing that value to SystemTimeToTzSpecificLocalTime triggers an InvalidInput error:
[src\main.rs:31] io::Error::last_os_error() = Os {
code: 87,
kind: InvalidInput,
message: "The parameter is incorrect.",
}
This seems to be an issue with something lower level having to do with Windows, so I'm going to close this.
We opened an issue in the official windows crate repo.
Actually, I'm reopening this since based on the feedback from that issue it looks like the problem might be more in chrono's domain.
I'm unable to test on Windows myself. I'd be happy to review any code changes that are supported with documentation and/or explanation why they improve the current situation, but I probably won't be able to work on this proactively.
Let me know if you need any guidance on how to fix chrono to support this scenario better.
@annmarie-switzer should have the fix for this. Unfortunately, I don't have the code and also am unable to test on Windows.
Just adding some additional info:
We (Nushell) recently got a bug report where this panic was occurring when the user ran ls ~/Downloads (which uses chrono for file modified times).
The culprit ended up being a file named NUL (which should not exist, cannot be created manually, and was probably created by some buggy third-party software; NUL is a reserved name). To fix the issue the user just deleted the file.
While https://github.com/chronotope/chrono/issues/1150 is a duplicate of this issue, it becomes a bit more specific on what to fix. Closing this issue as a duplicate.