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:: objtype:: PyClassRef ;
10+ use crate :: obj:: { objfloat, objint, objtype} ;
11+ use crate :: pyobject:: { PyClassImpl , PyObjectRef , PyResult , PyValue } ;
912use crate :: vm:: VirtualMachine ;
1013
14+ use num_traits:: cast:: ToPrimitive ;
15+
16+ use chrono:: naive:: NaiveDateTime ;
17+ use chrono:: { Datelike , Timelike } ;
18+
1119fn time_sleep ( vm : & VirtualMachine , args : PyFuncArgs ) -> PyResult {
1220 arg_check ! ( vm, args, required = [ ( seconds, Some ( vm. ctx. float_type( ) ) ) ] ) ;
1321 let seconds = objfloat:: get_value ( seconds) ;
@@ -32,11 +40,143 @@ fn time_time(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
3240 Ok ( value)
3341}
3442
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+
35169pub fn make_module ( vm : & VirtualMachine ) -> PyObjectRef {
36170 let ctx = & vm. ctx ;
37171
172+ let struct_time_type = PyStructTime :: make_class ( ctx) ;
173+
38174 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) ,
39178 "sleep" => ctx. new_rustfunc( time_sleep) ,
179+ "struct_time" => struct_time_type,
40180 "time" => ctx. new_rustfunc( time_time)
41181 } )
42182}
0 commit comments