11//! The python `time` module.
2-
2+ /// See also:
3+ /// https://docs.python.org/3/library/time.html
4+ use std:: fmt;
35use std:: thread;
46use std:: time:: { Duration , SystemTime , UNIX_EPOCH } ;
57
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 } ;
913use crate :: vm:: VirtualMachine ;
1014
15+ use num_traits:: cast:: ToPrimitive ;
16+
17+ use chrono:: naive:: NaiveDateTime ;
18+ use chrono:: { Datelike , Timelike } ;
19+
1120fn time_sleep ( vm : & VirtualMachine , args : PyFuncArgs ) -> PyResult {
1221 arg_check ! ( vm, args, required = [ ( seconds, Some ( vm. ctx. float_type( ) ) ) ] ) ;
1322 let seconds = objfloat:: get_value ( seconds) ;
@@ -32,11 +41,209 @@ fn time_time(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
3241 Ok ( value)
3342}
3443
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+
35232pub fn make_module ( vm : & VirtualMachine ) -> PyObjectRef {
36233 let ctx = & vm. ctx ;
37234
235+ let struct_time_type = PyStructTime :: make_class ( ctx) ;
236+
38237 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) ,
39245 "sleep" => ctx. new_rustfunc( time_sleep) ,
246+ "struct_time" => struct_time_type,
40247 "time" => ctx. new_rustfunc( time_time)
41248 } )
42249}
0 commit comments