8 个版本

0.1.6 2023年10月17日
0.1.5 2023年10月16日

#120日期和时间

Download history 26/week @ 2024-03-29 8/week @ 2024-04-05

每月 52 次下载

AGPL-3.0

230KB
3K SLoC

cftime-rs

cftime-rs 是 cf 时间规范的 rust 实现。该项目提供了 Python 绑定,并使用优秀的 maturin 库。Python 绑定受到由 Unidata 开发的 cftime Python 包的极大启发。

CI Status Crates.io version badge Pypi version badge CI/CD Status License: AGPL v3 Documentation Status Issue Badge Pull requests Badge

文档 : Rust | Python
: Rust | Python
仓库 : Github

Rust

安装

cargo install cftime-rs

示例

解码

解码需要单位、日历,可以与 i32i64f32f64 以及它们对应的向量类型 Vec<i32>Vec<i64>Vec<f32>Vec<f64> 一起工作。从这些类型中,它返回一个 CFDatetime 对象或一个 Vec<CFDatetime>

use cftime_rs::calendars::Calendar;
use cftime_rs::decoder::*;
use std::str::FromStr;
fn main() {
    let to_decode = vec![0, 1, 2, 3, 4, 5];
    let units = "days since 2000-01-01 00:00:00";
    let calendar = Calendar::from_str("standard").unwrap();
    let datetimes = to_decode.decode_cf(units, calendar).unwrap();
    for datetime in datetimes {
        println!("{}", datetime);
    }
}

将打印

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.000

编码

编码需要单位和日历,可以将一个 CFDatetime 对象转换为 i32i64f32f64,或者将 Vec<CFDatetime> 转换为 Vec<i32>Vec<i64>Vec<f32>Vec<f64>

use cftime_rs::calendars::Calendar;
use cftime_rs::datetime::CFDatetime;
use cftime_rs::encoder::*;
use cftime_rs::errors::Error;
use std::str::FromStr;
fn main() {
    let calendar = Calendar::from_str("standard").unwrap();
    // Create vector of datetimes and convert Vec<Result<CFDatetime, Error>>
    // into Result<Vec<CFDatetime>, Error>
    let to_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 units
    let units = "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>
    let results: Vec<i64> = to_encode.unwrap().encode_cf(units, calendar).unwrap();
    for result in results {
        println!("{}", result);
    }
}

将打印

0
1
2
3
4
5

Python

安装

pip install cftime-rs

示例

解码为 PyCfDatetimes

import cftime_rs

to_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)
for datetime in datetimes:
    print(datetime)

将打印

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.000

编码 PyCfDatetimes

calendar = 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")
for number in numbers:
    print(number)

将打印

0
1
2
3
4
5

解码为 Python 日期时间

to_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)
for datetime in datetimes:
    print(datetime)

将打印

2000-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:00

解码 Python 日期时间

to_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")
for number in numbers:
    print(number)

将打印

0
1
2
3
4
5

已知问题

尽管这个日期计算库可以处理从大约公元前 291,672,107,014 年到公元 291,672,107,014 年的广泛日期,但仍有一些性能考虑因素您应该了解。随着您远离参考日期 1970-01-01 00:00:00,计算时间会增加。这是因为库需要考虑各种历法中的闰年。

以下是在发布模式下使用个人计算机上的 "自 2000-01-01 00:00:00 以来秒数" 单位计算 1_000_000_000_000_000 秒的示例

日历 计算时间
标准日历 44.470405ms
闰日日历 8.052179ms
360 天日历 12.834µs

与 cftime 的比较

以下是在我计算机上对三种方法的基准测试。这并不十分严格,但这是为了提供一个概念。

我们比较了 cftime 与 cftime_rs。第一种方法涉及使用标准日历解码一系列数字,调用 .str() 方法,然后将它们重新编码到相同的单位和日历。第二种方法是不调用 .str(),使用标准日历解码一系列数字并将它们重新编码到相同的单位和日历。第三种方法是将标准日历解码的一系列数字解码为 python 日期时间,然后不调用 .str() 将它们重新编码到相同的单位和日历。

第一种和第二种方法旨在在两个库之间保持公平,因为 cftime_rs 仅使用时间戳 (i64) 作为其内部表示,并且从不重新计算年、月、日、小时、分钟和秒,除非您明确请求此表示。

First method Second method
First method

依赖关系

~4–10MB
~95K SLoC