Skip to content

Commit 5877f41

Browse files
authored
Merge pull request #1925 from youknowone/fix-datetime
Fix datetime.fromtimestamp OverflowError
2 parents 160afda + e98ee15 commit 5877f41

File tree

1 file changed

+30
-18
lines changed

1 file changed

+30
-18
lines changed

vm/src/stdlib/time_module.rs

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -70,32 +70,41 @@ fn time_monotonic(_vm: &VirtualMachine) -> f64 {
7070
}
7171
}
7272

73-
fn pyobj_to_naive_date_time(value: Either<f64, i64>) -> NaiveDateTime {
74-
match value {
73+
fn pyobj_to_naive_date_time(
74+
value: Either<f64, i64>,
75+
vm: &VirtualMachine,
76+
) -> PyResult<NaiveDateTime> {
77+
let timestamp = match value {
7578
Either::A(float) => {
7679
let secs = float.trunc() as i64;
7780
let nsecs = (float.fract() * 1e9) as u32;
78-
NaiveDateTime::from_timestamp(secs, nsecs)
81+
NaiveDateTime::from_timestamp_opt(secs, nsecs)
7982
}
80-
Either::B(int) => NaiveDateTime::from_timestamp(int, 0),
81-
}
83+
Either::B(int) => NaiveDateTime::from_timestamp_opt(int, 0),
84+
};
85+
timestamp.ok_or_else(|| {
86+
vm.new_overflow_error("timestamp out of range for platform time_t".to_owned())
87+
})
8288
}
8389

8490
/// https://docs.python.org/3/library/time.html?highlight=gmtime#time.gmtime
85-
fn time_gmtime(secs: OptionalArg<Either<f64, i64>>, vm: &VirtualMachine) -> PyObjectRef {
91+
fn time_gmtime(secs: OptionalArg<Either<f64, i64>>, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
8692
let default = chrono::offset::Utc::now().naive_utc();
8793
let instant = match secs {
88-
OptionalArg::Present(secs) => pyobj_to_naive_date_time(secs),
94+
OptionalArg::Present(secs) => pyobj_to_naive_date_time(secs, vm)?,
8995
OptionalArg::Missing => default,
9096
};
91-
PyStructTime::new(vm, instant, 0).into_obj(vm)
97+
Ok(PyStructTime::new(vm, instant, 0).into_obj(vm))
9298
}
9399

94-
fn time_localtime(secs: OptionalArg<Either<f64, i64>>, vm: &VirtualMachine) -> PyObjectRef {
95-
let instant = optional_or_localtime(secs);
100+
fn time_localtime(
101+
secs: OptionalArg<Either<f64, i64>>,
102+
vm: &VirtualMachine,
103+
) -> PyResult<PyObjectRef> {
104+
let instant = optional_or_localtime(secs, vm)?;
96105
// TODO: isdst flag must be valid value here
97106
// https://docs.python.org/3/library/time.html#time.localtime
98-
PyStructTime::new(vm, instant, -1).into_obj(vm)
107+
Ok(PyStructTime::new(vm, instant, -1).into_obj(vm))
99108
}
100109

101110
fn time_mktime(t: PyStructTime, vm: &VirtualMachine) -> PyResult {
@@ -105,12 +114,15 @@ fn time_mktime(t: PyStructTime, vm: &VirtualMachine) -> PyResult {
105114
}
106115

107116
/// Construct a localtime from the optional seconds, or get the current local time.
108-
fn optional_or_localtime(secs: OptionalArg<Either<f64, i64>>) -> NaiveDateTime {
117+
fn optional_or_localtime(
118+
secs: OptionalArg<Either<f64, i64>>,
119+
vm: &VirtualMachine,
120+
) -> PyResult<NaiveDateTime> {
109121
let default = chrono::offset::Local::now().naive_local();
110-
match secs {
111-
OptionalArg::Present(secs) => pyobj_to_naive_date_time(secs),
122+
Ok(match secs {
123+
OptionalArg::Present(secs) => pyobj_to_naive_date_time(secs, vm)?,
112124
OptionalArg::Missing => default,
113-
}
125+
})
114126
}
115127

116128
const CFMT: &str = "%a %b %e %H:%M:%S %Y";
@@ -125,9 +137,9 @@ fn time_asctime(t: OptionalArg<PyStructTime>, vm: &VirtualMachine) -> PyResult {
125137
Ok(vm.ctx.new_str(formatted_time))
126138
}
127139

128-
fn time_ctime(secs: OptionalArg<Either<f64, i64>>) -> String {
129-
let instant = optional_or_localtime(secs);
130-
instant.format(&CFMT).to_string()
140+
fn time_ctime(secs: OptionalArg<Either<f64, i64>>, vm: &VirtualMachine) -> PyResult<String> {
141+
let instant = optional_or_localtime(secs, vm)?;
142+
Ok(instant.format(&CFMT).to_string())
131143
}
132144

133145
fn time_strftime(

0 commit comments

Comments
 (0)