1
1
//! The python `time` module.
2
-
2
+ /// See also:
3
+ /// https://docs.python.org/3/library/time.html
4
+ use std:: fmt;
3
5
use std:: thread;
4
6
use std:: time:: { Duration , SystemTime , UNIX_EPOCH } ;
5
7
6
- use crate :: function:: PyFuncArgs ;
7
- use crate :: obj:: objfloat;
8
- use crate :: pyobject:: { PyObjectRef , PyResult } ;
8
+ use crate :: function:: { OptionalArg , PyFuncArgs } ;
9
+ use crate :: obj:: objtype:: PyClassRef ;
10
+ use crate :: obj:: { objfloat, objint, objtype} ;
11
+ use crate :: pyobject:: { PyClassImpl , PyObjectRef , PyResult , PyValue } ;
9
12
use crate :: vm:: VirtualMachine ;
10
13
14
+ use num_traits:: cast:: ToPrimitive ;
15
+
16
+ use chrono:: naive:: NaiveDateTime ;
17
+ use chrono:: { Datelike , Timelike } ;
18
+
11
19
fn time_sleep ( vm : & VirtualMachine , args : PyFuncArgs ) -> PyResult {
12
20
arg_check ! ( vm, args, required = [ ( seconds, Some ( vm. ctx. float_type( ) ) ) ] ) ;
13
21
let seconds = objfloat:: get_value ( seconds) ;
@@ -32,11 +40,143 @@ fn time_time(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
32
40
Ok ( value)
33
41
}
34
42
43
+ fn time_monotonic ( vm : & VirtualMachine , args : PyFuncArgs ) -> PyResult {
44
+ arg_check ! ( vm, args) ;
45
+ // TODO: implement proper monotonic time!
46
+ let x = match SystemTime :: now ( ) . duration_since ( UNIX_EPOCH ) {
47
+ Ok ( v) => duration_to_f64 ( v) ,
48
+ Err ( err) => panic ! ( "Error: {:?}" , err) ,
49
+ } ;
50
+ let value = vm. ctx . new_float ( x) ;
51
+ Ok ( value)
52
+ }
53
+
54
+ fn pyfloat_to_secs_and_nanos ( seconds : & PyObjectRef ) -> ( i64 , u32 ) {
55
+ let seconds = objfloat:: get_value ( seconds) ;
56
+ let secs: i64 = seconds. trunc ( ) as i64 ;
57
+ let nanos: u32 = ( seconds. fract ( ) * 1e9 ) as u32 ;
58
+ ( secs, nanos)
59
+ }
60
+
61
+ fn pyobj_to_naive_date_time (
62
+ value : & PyObjectRef ,
63
+ vm : & VirtualMachine ,
64
+ ) -> PyResult < Option < NaiveDateTime > > {
65
+ if objtype:: isinstance ( value, & vm. ctx . float_type ( ) ) {
66
+ let ( seconds, nanos) = pyfloat_to_secs_and_nanos ( & value) ;
67
+ let dt = NaiveDateTime :: from_timestamp ( seconds, nanos) ;
68
+ Ok ( Some ( dt) )
69
+ } else if objtype:: isinstance ( & value, & vm. ctx . int_type ( ) ) {
70
+ let seconds = objint:: get_value ( & value) . to_i64 ( ) . unwrap ( ) ;
71
+ let dt = NaiveDateTime :: from_timestamp ( seconds, 0 ) ;
72
+ Ok ( Some ( dt) )
73
+ } else {
74
+ Err ( vm. new_type_error ( "Expected float, int or None" . to_string ( ) ) )
75
+ }
76
+ }
77
+
78
+ /// https://docs.python.org/3/library/time.html?highlight=gmtime#time.gmtime
79
+ fn time_gmtime ( secs : OptionalArg < PyObjectRef > , vm : & VirtualMachine ) -> PyResult < PyStructTime > {
80
+ let default = chrono:: offset:: Utc :: now ( ) . naive_utc ( ) ;
81
+ let instant = match secs {
82
+ OptionalArg :: Present ( secs) => pyobj_to_naive_date_time ( & secs, vm) ?. unwrap_or ( default) ,
83
+ OptionalArg :: Missing => default,
84
+ } ;
85
+ let value = PyStructTime :: new ( instant) ;
86
+ Ok ( value)
87
+ }
88
+
89
+ fn time_localtime ( secs : OptionalArg < PyObjectRef > , vm : & VirtualMachine ) -> PyResult < PyStructTime > {
90
+ let default = chrono:: offset:: Local :: now ( ) . naive_local ( ) ;
91
+ let instant = match secs {
92
+ OptionalArg :: Present ( secs) => pyobj_to_naive_date_time ( & secs, vm) ?. unwrap_or ( default) ,
93
+ OptionalArg :: Missing => default,
94
+ } ;
95
+ let value = PyStructTime :: new ( instant) ;
96
+ Ok ( value)
97
+ }
98
+
99
+ #[ pyclass( name = "struct_time" ) ]
100
+ struct PyStructTime {
101
+ tm : NaiveDateTime ,
102
+ }
103
+
104
+ impl fmt:: Debug for PyStructTime {
105
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
106
+ write ! ( f, "struct_time()" )
107
+ }
108
+ }
109
+
110
+ impl PyValue for PyStructTime {
111
+ fn class ( vm : & VirtualMachine ) -> PyClassRef {
112
+ vm. class ( "time" , "struct_time" )
113
+ }
114
+ }
115
+
116
+ #[ pyimpl]
117
+ impl PyStructTime {
118
+ fn new ( tm : NaiveDateTime ) -> Self {
119
+ PyStructTime { tm }
120
+ }
121
+
122
+ #[ pymethod( name = "__repr__" ) ]
123
+ fn repr ( & self , _vm : & VirtualMachine ) -> String {
124
+ // TODO: extract year day and isdst somehow..
125
+ format ! (
126
+ "time.struct_time(tm_year={}, tm_mon={}, tm_mday={}, tm_hour={}, tm_min={}, tm_sec={}, tm_wday={})" ,
127
+ self . tm. date( ) . year( ) , self . tm. date( ) . month( ) , self . tm. date( ) . day( ) ,
128
+ self . tm. time( ) . hour( ) , self . tm. time( ) . minute( ) , self . tm. time( ) . second( ) ,
129
+ self . tm. date( ) . weekday( ) . num_days_from_monday( )
130
+ )
131
+ }
132
+
133
+ #[ pyproperty( name = "tm_year" ) ]
134
+ fn tm_year ( & self , _vm : & VirtualMachine ) -> i32 {
135
+ self . tm . date ( ) . year ( )
136
+ }
137
+
138
+ #[ pyproperty( name = "tm_mon" ) ]
139
+ fn tm_mon ( & self , _vm : & VirtualMachine ) -> u32 {
140
+ self . tm . date ( ) . month ( )
141
+ }
142
+
143
+ #[ pyproperty( name = "tm_mday" ) ]
144
+ fn tm_mday ( & self , _vm : & VirtualMachine ) -> u32 {
145
+ self . tm . date ( ) . day ( )
146
+ }
147
+
148
+ #[ pyproperty( name = "tm_hour" ) ]
149
+ fn tm_hour ( & self , _vm : & VirtualMachine ) -> u32 {
150
+ self . tm . time ( ) . hour ( )
151
+ }
152
+
153
+ #[ pyproperty( name = "tm_min" ) ]
154
+ fn tm_min ( & self , _vm : & VirtualMachine ) -> u32 {
155
+ self . tm . time ( ) . minute ( )
156
+ }
157
+
158
+ #[ pyproperty( name = "tm_sec" ) ]
159
+ fn tm_sec ( & self , _vm : & VirtualMachine ) -> u32 {
160
+ self . tm . time ( ) . second ( )
161
+ }
162
+
163
+ #[ pyproperty( name = "tm_wday" ) ]
164
+ fn tm_wday ( & self , _vm : & VirtualMachine ) -> u32 {
165
+ self . tm . date ( ) . weekday ( ) . num_days_from_monday ( )
166
+ }
167
+ }
168
+
35
169
pub fn make_module ( vm : & VirtualMachine ) -> PyObjectRef {
36
170
let ctx = & vm. ctx ;
37
171
172
+ let struct_time_type = PyStructTime :: make_class ( ctx) ;
173
+
38
174
py_module ! ( vm, "time" , {
175
+ "gmtime" => ctx. new_rustfunc( time_gmtime) ,
176
+ "localtime" => ctx. new_rustfunc( time_localtime) ,
177
+ "monotonic" => ctx. new_rustfunc( time_monotonic) ,
39
178
"sleep" => ctx. new_rustfunc( time_sleep) ,
179
+ "struct_time" => struct_time_type,
40
180
"time" => ctx. new_rustfunc( time_time)
41
181
} )
42
182
}
0 commit comments