Package: cftime-rs
cftime-rscftime-rsis an implementation inrustof thecf timeconvention. Python bindins are available for this project and use the greatmaturin library. The python bindings are highly inspired by thecftimepython package developped byUnidata.Documentation:Rust|PythonPackages:Rust|PythonRepository:GithubRustInstallationcargo install cftime-rsExamplesDecodingDecoding needs units, and calendar and can work withi32,i64,f32,f64and their corresponding vector typeVec<i32>,Vec<i64>,Vec<f32>andVec<f64>. From these type it return either aCFDatetimeobject or aVec<CFDatetime>.usecftime_rs::calendars::Calendar;usecftime_rs::decoder::*;usestd::str::FromStr;fnmain(){letto_decode=vec![0,1,2,3,4,5];letunits="days since 2000-01-01 00:00:00";letcalendar=Calendar::from_str("standard").unwrap();letdatetimes=to_decode.decode_cf(units,calendar).unwrap();fordatetimeindatetimes{println!("{}",datetime);}}will print :2000-01-01 00:00:00.000
2000-01-02 00:00:00.000
2000-01-03 00:00:00.000
2000-01-04 00:00:00.000
2000-01-05 00:00:00.000
2000-01-06 00:00:00.000EncodingEncoding needs units and calendar and can convert aCFDatetimeobject into ani32,i64,f32orf64or aVec<CFDatetime>intoVec<i32>,Vec<i64>,Vec<f32>orVec<f64>.usecftime_rs::calendars::Calendar;usecftime_rs::datetime::CFDatetime;usecftime_rs::encoder::*;usecftime_rs::errors::Error;usestd::str::FromStr;fnmain(){letcalendar=Calendar::from_str("standard").unwrap();// Create vector of datetimes and convert Vec<Result<CFDatetime, Error>>// into Result<Vec<CFDatetime>, Error>letto_encode:Result<Vec<CFDatetime>,Error>=vec![CFDatetime::from_ymd(2000,1,1,calendar),CFDatetime::from_ymd(2000,1,2,calendar),CFDatetime::from_ymd(2000,1,3,calendar),CFDatetime::from_ymd(2000,1,4,calendar),CFDatetime::from_ymd(2000,1,5,calendar),CFDatetime::from_ymd(2000,1,6,calendar),].into_iter().collect();// define the unitsletunits="days since 2000-01-01 00:00:00";// The type annotation for result allow us to cast to type we want// here we use Vec<i64>letresults:Vec<i64>=to_encode.unwrap().encode_cf(units,calendar).unwrap();forresultinresults{println!("{}",result);}}will print :0
1
2
3
4
5PythonInstallationpip install cftime-rsExamplesDecoding to PyCfDatetimesimportcftime_rsto_decode=[0,1,2,3,4,5]units="days since 2000-01-01 00:00:00"calendar="standard"datetimes=cftime_rs.num2date(arr,units,calendar)fordatetimeindatetimes:print(datetime)will print :2000-01-01 00:00:00.000
2000-01-02 00:00:00.000
2000-01-03 00:00:00.000
2000-01-04 00:00:00.000
2000-01-05 00:00:00.000
2000-01-06 00:00:00.000Encoding PyCFDatetimescalendar=cftime_rs.PyCFCalendar.from_str("standard")to_encode=[cftime_rs.PyCFDatetime.from_ymd(2000,1,1,calendar),cftime_rs.PyCFDatetime.from_ymd(2000,1,2,calendar),cftime_rs.PyCFDatetime.from_ymd(2000,1,3,calendar),cftime_rs.PyCFDatetime.from_ymd(2000,1,4,calendar),cftime_rs.PyCFDatetime.from_ymd(2000,1,5,calendar),cftime_rs.PyCFDatetime.from_ymd(2000,1,6,calendar),]units="days since 2000-01-01 00:00:00"calendar="standard"numbers=cftime_rs.date2num(to_encode,units,calendar,dtype="int")fornumberinnumbers:print(number)will print :0
1
2
3
4
5Decoding to Python datetimesto_decode=[0,1,2,3,4,5]units="days since 2000-01-01 00:00:00"calendar="standard"datetimes=cftime_rs.num2pydate(to_decode,units,calendar)fordatetimeindatetimes:print(datetime)will print2000-01-01 00:00:00
2000-01-02 00:00:00
2000-01-03 00:00:00
2000-01-04 00:00:00
2000-01-05 00:00:00
2000-01-06 00:00:00Decoding Python datetimesto_encode=[dt.datetime(2000,1,1),dt.datetime(2000,1,2),dt.datetime(2000,1,3),dt.datetime(2000,1,4),dt.datetime(2000,1,5),dt.datetime(2000,1,6),]units="days since 2000-01-01 00:00:00"calendar="standard"numbers=cftime_rs.pydate2num(to_encode,units,calendar,dtype="int")fornumberinnumbers:print(number)will print0
1
2
3
4
5Known issuesWhile this date calculation library can handle a wide range of dates, from approximately -291,672,107,014 BC to 291,672,107,014 AD, there are some performance considerations you should be aware of.
As you move further away from the reference date of 1970-01-01 00:00:00, the time of calculation increases. This is because the library needs to account for leap years in various calendars.Here is an example of the computation of 1_000_000_000_000_000 seconds using the units "seconds since 2000-01-01 00:00:00" on my personal computer in release mode :CalendarComputation TimeStandard Calendar44.470405msLeap Day Calendar8.052179ms360-Day Calendar12.834µsComparison with cftimeHere is a benchmark on my computer of three methods. This is not really rigorous but this is to give an idea.We are comparing cftime with cftime_rs. The first method involves decoding a series of numbers using the standard calendar, calling the .str() method, and then re-encoding them to the same unit and calendar.
The second method is to decode a series of numbers using the standard calendar and re-encode them to the same unit and calendar without calling .str().
The third method is to decode a series of numbers using the standard calendar into python datetimes and re-encode them to the same unit and calendar without calling .str().First and second methods are designed to be fair between the two libraries because cftime_rs only uses timestamps (i64) as its internal representation and never recalculates the year, month, day, hour, minutes, and seconds, except if you explicitly request this representation.