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:: objstr:: PyStringRef ;
10
+ use crate :: obj:: objtype:: PyClassRef ;
11
+ use crate :: obj:: { objfloat, objint, objtype} ;
12
+ use crate :: pyobject:: { PyClassImpl , PyObjectRef , PyRef , PyResult , PyValue } ;
9
13
use crate :: vm:: VirtualMachine ;
10
14
15
+ use num_traits:: cast:: ToPrimitive ;
16
+
17
+ use chrono:: naive:: NaiveDateTime ;
18
+ use chrono:: { Datelike , Timelike } ;
19
+
11
20
fn time_sleep ( vm : & VirtualMachine , args : PyFuncArgs ) -> PyResult {
12
21
arg_check ! ( vm, args, required = [ ( seconds, Some ( vm. ctx. float_type( ) ) ) ] ) ;
13
22
let seconds = objfloat:: get_value ( seconds) ;
@@ -32,11 +41,209 @@ fn time_time(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
32
41
Ok ( value)
33
42
}
34
43
44
+ fn time_monotonic ( vm : & VirtualMachine , args : PyFuncArgs ) -> PyResult {
45
+ arg_check ! ( vm, args) ;
46
+ // TODO: implement proper monotonic time!
47
+ let x = match SystemTime :: now ( ) . duration_since ( UNIX_EPOCH ) {
48
+ Ok ( v) => duration_to_f64 ( v) ,
49
+ Err ( err) => panic ! ( "Error: {:?}" , err) ,
50
+ } ;
51
+ let value = vm. ctx . new_float ( x) ;
52
+ Ok ( value)
53
+ }
54
+
55
+ fn pyfloat_to_secs_and_nanos ( seconds : & PyObjectRef ) -> ( i64 , u32 ) {
56
+ let seconds = objfloat:: get_value ( seconds) ;
57
+ let secs: i64 = seconds. trunc ( ) as i64 ;
58
+ let nanos: u32 = ( seconds. fract ( ) * 1e9 ) as u32 ;
59
+ ( secs, nanos)
60
+ }
61
+
62
+ fn pyobj_to_naive_date_time (
63
+ value : & PyObjectRef ,
64
+ vm : & VirtualMachine ,
65
+ ) -> PyResult < Option < NaiveDateTime > > {
66
+ if objtype:: isinstance ( value, & vm. ctx . float_type ( ) ) {
67
+ let ( seconds, nanos) = pyfloat_to_secs_and_nanos ( & value) ;
68
+ let dt = NaiveDateTime :: from_timestamp ( seconds, nanos) ;
69
+ Ok ( Some ( dt) )
70
+ } else if objtype:: isinstance ( & value, & vm. ctx . int_type ( ) ) {
71
+ let seconds = objint:: get_value ( & value) . to_i64 ( ) . unwrap ( ) ;
72
+ let dt = NaiveDateTime :: from_timestamp ( seconds, 0 ) ;
73
+ Ok ( Some ( dt) )
74
+ } else {
75
+ Err ( vm. new_type_error ( "Expected float, int or None" . to_string ( ) ) )
76
+ }
77
+ }
78
+
79
+ /// https://docs.python.org/3/library/time.html?highlight=gmtime#time.gmtime
80
+ fn time_gmtime ( secs : OptionalArg < PyObjectRef > , vm : & VirtualMachine ) -> PyResult < PyStructTime > {
81
+ let default = chrono:: offset:: Utc :: now ( ) . naive_utc ( ) ;
82
+ let instant = match secs {
83
+ OptionalArg :: Present ( secs) => pyobj_to_naive_date_time ( & secs, vm) ?. unwrap_or ( default) ,
84
+ OptionalArg :: Missing => default,
85
+ } ;
86
+ let value = PyStructTime :: new ( instant) ;
87
+ Ok ( value)
88
+ }
89
+
90
+ fn time_localtime ( secs : OptionalArg < PyObjectRef > , vm : & VirtualMachine ) -> PyResult < PyStructTime > {
91
+ let instant = optional_or_localtime ( secs, vm) ?;
92
+ let value = PyStructTime :: new ( instant) ;
93
+ Ok ( value)
94
+ }
95
+
96
+ /// Construct a localtime from the optional seconds, or get the current local time.
97
+ fn optional_or_localtime (
98
+ secs : OptionalArg < PyObjectRef > ,
99
+ vm : & VirtualMachine ,
100
+ ) -> PyResult < NaiveDateTime > {
101
+ let default = chrono:: offset:: Local :: now ( ) . naive_local ( ) ;
102
+ let instant = match secs {
103
+ OptionalArg :: Present ( secs) => pyobj_to_naive_date_time ( & secs, vm) ?. unwrap_or ( default) ,
104
+ OptionalArg :: Missing => default,
105
+ } ;
106
+ Ok ( instant)
107
+ }
108
+
109
+ const CFMT : & str = "%a %b %e %H:%M:%S %Y" ;
110
+
111
+ fn time_asctime ( t : OptionalArg < PyStructTimeRef > , vm : & VirtualMachine ) -> PyResult {
112
+ let default = chrono:: offset:: Local :: now ( ) . naive_local ( ) ;
113
+ let instant = match t {
114
+ OptionalArg :: Present ( t) => t. get_date_time ( ) ,
115
+ OptionalArg :: Missing => default,
116
+ } ;
117
+ let formatted_time = instant. format ( & CFMT ) . to_string ( ) ;
118
+ Ok ( vm. ctx . new_str ( formatted_time) )
119
+ }
120
+
121
+ fn time_ctime ( secs : OptionalArg < PyObjectRef > , vm : & VirtualMachine ) -> PyResult < String > {
122
+ let instant = optional_or_localtime ( secs, vm) ?;
123
+ let formatted_time = instant. format ( & CFMT ) . to_string ( ) ;
124
+ Ok ( formatted_time)
125
+ }
126
+
127
+ fn time_strftime (
128
+ format : PyStringRef ,
129
+ t : OptionalArg < PyStructTimeRef > ,
130
+ vm : & VirtualMachine ,
131
+ ) -> PyResult {
132
+ let default = chrono:: offset:: Local :: now ( ) . naive_local ( ) ;
133
+ let instant = match t {
134
+ OptionalArg :: Present ( t) => t. get_date_time ( ) ,
135
+ OptionalArg :: Missing => default,
136
+ } ;
137
+ let formatted_time = instant. format ( & format. value ) . to_string ( ) ;
138
+ Ok ( vm. ctx . new_str ( formatted_time) )
139
+ }
140
+
141
+ fn time_strptime (
142
+ string : PyStringRef ,
143
+ format : OptionalArg < PyStringRef > ,
144
+ vm : & VirtualMachine ,
145
+ ) -> PyResult < PyStructTime > {
146
+ let format: String = match format {
147
+ OptionalArg :: Present ( format) => format. value . clone ( ) ,
148
+ OptionalArg :: Missing => "%a %b %H:%M:%S %Y" . to_string ( ) ,
149
+ } ;
150
+ let instant = NaiveDateTime :: parse_from_str ( & string. value , & format)
151
+ . map_err ( |e| vm. new_value_error ( format ! ( "Parse error: {:?}" , e) ) ) ?;
152
+ let struct_time = PyStructTime :: new ( instant) ;
153
+ Ok ( struct_time)
154
+ }
155
+
156
+ #[ pyclass( name = "struct_time" ) ]
157
+ struct PyStructTime {
158
+ tm : NaiveDateTime ,
159
+ }
160
+
161
+ type PyStructTimeRef = PyRef < PyStructTime > ;
162
+
163
+ impl fmt:: Debug for PyStructTime {
164
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
165
+ write ! ( f, "struct_time()" )
166
+ }
167
+ }
168
+
169
+ impl PyValue for PyStructTime {
170
+ fn class ( vm : & VirtualMachine ) -> PyClassRef {
171
+ vm. class ( "time" , "struct_time" )
172
+ }
173
+ }
174
+
175
+ #[ pyimpl]
176
+ impl PyStructTime {
177
+ fn new ( tm : NaiveDateTime ) -> Self {
178
+ PyStructTime { tm }
179
+ }
180
+
181
+ #[ pymethod( name = "__repr__" ) ]
182
+ fn repr ( & self , _vm : & VirtualMachine ) -> String {
183
+ // TODO: extract year day and isdst somehow..
184
+ format ! (
185
+ "time.struct_time(tm_year={}, tm_mon={}, tm_mday={}, tm_hour={}, tm_min={}, tm_sec={}, tm_wday={})" ,
186
+ self . tm. date( ) . year( ) , self . tm. date( ) . month( ) , self . tm. date( ) . day( ) ,
187
+ self . tm. time( ) . hour( ) , self . tm. time( ) . minute( ) , self . tm. time( ) . second( ) ,
188
+ self . tm. date( ) . weekday( ) . num_days_from_monday( )
189
+ )
190
+ }
191
+
192
+ fn get_date_time ( & self ) -> NaiveDateTime {
193
+ self . tm
194
+ }
195
+
196
+ #[ pyproperty( name = "tm_year" ) ]
197
+ fn tm_year ( & self , _vm : & VirtualMachine ) -> i32 {
198
+ self . tm . date ( ) . year ( )
199
+ }
200
+
201
+ #[ pyproperty( name = "tm_mon" ) ]
202
+ fn tm_mon ( & self , _vm : & VirtualMachine ) -> u32 {
203
+ self . tm . date ( ) . month ( )
204
+ }
205
+
206
+ #[ pyproperty( name = "tm_mday" ) ]
207
+ fn tm_mday ( & self , _vm : & VirtualMachine ) -> u32 {
208
+ self . tm . date ( ) . day ( )
209
+ }
210
+
211
+ #[ pyproperty( name = "tm_hour" ) ]
212
+ fn tm_hour ( & self , _vm : & VirtualMachine ) -> u32 {
213
+ self . tm . time ( ) . hour ( )
214
+ }
215
+
216
+ #[ pyproperty( name = "tm_min" ) ]
217
+ fn tm_min ( & self , _vm : & VirtualMachine ) -> u32 {
218
+ self . tm . time ( ) . minute ( )
219
+ }
220
+
221
+ #[ pyproperty( name = "tm_sec" ) ]
222
+ fn tm_sec ( & self , _vm : & VirtualMachine ) -> u32 {
223
+ self . tm . time ( ) . second ( )
224
+ }
225
+
226
+ #[ pyproperty( name = "tm_wday" ) ]
227
+ fn tm_wday ( & self , _vm : & VirtualMachine ) -> u32 {
228
+ self . tm . date ( ) . weekday ( ) . num_days_from_monday ( )
229
+ }
230
+ }
231
+
35
232
pub fn make_module ( vm : & VirtualMachine ) -> PyObjectRef {
36
233
let ctx = & vm. ctx ;
37
234
235
+ let struct_time_type = PyStructTime :: make_class ( ctx) ;
236
+
38
237
py_module ! ( vm, "time" , {
238
+ "asctime" => ctx. new_rustfunc( time_asctime) ,
239
+ "ctime" => ctx. new_rustfunc( time_ctime) ,
240
+ "gmtime" => ctx. new_rustfunc( time_gmtime) ,
241
+ "localtime" => ctx. new_rustfunc( time_localtime) ,
242
+ "monotonic" => ctx. new_rustfunc( time_monotonic) ,
243
+ "strftime" => ctx. new_rustfunc( time_strftime) ,
244
+ "strptime" => ctx. new_rustfunc( time_strptime) ,
39
245
"sleep" => ctx. new_rustfunc( time_sleep) ,
246
+ "struct_time" => struct_time_type,
40
247
"time" => ctx. new_rustfunc( time_time)
41
248
} )
42
249
}
0 commit comments