|
Pythonのdatetimeモジュールの日付型は、PyO3 0.27ではpyo3::typesのPyDateTime等で扱う。
日付(年月日)は、PyO3ではpyo3::types::PyDateで扱う。
関数の引数や戻り値の型としては、Bound<PyDate>(やPy<PyDate>)を指定する。
use pyo3::prelude::*;
#[pymodule]
mod example_pyo3 {
use pyo3::{prelude::*, types::*};
〜
#[pyfunction]
fn inc_date<'py>(py: Python<'py>, date: &Bound<PyDate>) -> PyResult<Bound<'py, PyDate>> {
let year = date.get_year();
let month = date.get_month();
let day = date.get_day();
let next_date = PyDate::new(py, year, month, day + 1)?; // Bound<PyDate>
Ok(next_date)
}
}
pyが必要な場合、第1引数に「py: Python」を定義しておく。
関数からBoundで返す場合はライフタイム'pyも明示する。
get_year()やget_month()といったメソッドは、PyDateAccessトレイトで定義されている。 [2026-02-04]
pyo3::types::*で全てをインポートしている場合は自動的にインポートされるが、クラスやトレイトを個別に指定する場合はPyDateとPyDateAccessをインポートする必要がある。
Pythonプロジェクト側で、datetimeモジュールを依存ライブラリーに追加しておく。
cd call-pyo3 uv add datetime
import datetime
import example_pyo3
def main():
print("Hello from call-pyo3!")
print(example_pyo3.inc_date(datetime.date(2025, 12, 13)))
if __name__ == "__main__":
main()
> cd call-pyo3 > uv run main.py Hello from call-pyo3! 2025-12-14
Pythonのdatetime.datetimeやdatetime.timeはタイムゾーン(tzinfo)を持つことが出来る。[2026-01-28]
Bound<PyAny>からタイムゾーンを取得するには、getattrメソッドを使用する。
use pyo3::{prelude::*, types::*};
#[pyfunction]
fn tzinfo_check(value: Bound<PyAny>) -> PyResult<()> {
if value.is_instance_of::<PyDateTime>() || value.is_instance_of::<PyTime>() {
let tzinfo = value.getattr("tzinfo")?; // Bound<PyAny>
println!("tzinfo {}", tzinfo);
}
Ok(())
Python側でtzinfoをセットしていないときは、Rust側ではPyNoneになる。
import datetime
import example_pyo3
def main():
JST = datetime.timezone(datetime.timedelta(hours=9))
example_pyo3.tzinfo_check(datetime.time(12, 34, 56))
example_pyo3.tzinfo_check(datetime.time(12, 34, 56, tzinfo=JST))
example_pyo3.tzinfo_check(datetime.datetime(2026, 1, 28))
example_pyo3.tzinfo_check(datetime.datetime(2026, 1, 28, tzinfo=JST))
if __name__ == "__main__":
main()Bound<PyDateTime>やBound<PyTime>からは、get_tzinfoメソッドでPyTzInfoを取得できる。[2026-02-13]
use pyo3::{prelude::*, types::*}; // types::PyDateTime, types::PyTzInfoAccess
#[pyfunction]
fn tzinfo_check(value: Bound<PyDateTime>) {
let tzinfo = value.get_tzinfo(); // Option<Bound<PyTzInfo>>
println!("tzinfo={:?}", tzinfo);
}
タイムゾーン情報(Pythonのdatetime.tzinfo)は、PyO3ではPyTzInfoで扱う。[2026-02-04]
これを生成するには、PyDeltaを使用する。
use pyo3::{prelude::*, types::*};
#[pyfunction]
fn get_datetime<'py>(py: Python<'py>) -> PyResult<Bound<'py, PyDateTime>> {
let year = 2026;
let month = 2;
let day = 4;
let hour = 12;
let minute = 34;
let second = 56;
let microsecond = 456789;
// +09:00
let offset_hour = 9;
let offset = PyDelta::new(py, 0, offset_hour * 60 * 60, 0, false)?;
let tzinfo = PyTzInfo::fixed_offset(py, offset)?;
let datetime = PyDateTime::new(
py,
year,
month,
day,
hour,
minute,
second,
microsecond,
Some(&tzinfo),
)?;
Ok(datetime)
}
Rustで日付を扱うchronoクレートをPyO3 0.27で使う例。
まず、chronoクレートを依存ライブラリーに追加する。
cd example-pyo3 cargo add chrono
次に、pyo3にchronoフィーチャーを追加する。
〜
[dependencies]
chrono = "0.4.42"
pyo3 = { version = "0.27.2", features = ["chrono"] }
PyDateとchrono::NaiveDateを変換する例。
use pyo3::prelude::*;
#[pymodule]
mod example_pyo3 {
use pyo3::{prelude::*, types::*};
〜
#[pyfunction]
fn inc_date(py: Python, date: &Bound<PyDate>) -> PyResult<Py<PyDate>> {
let date: chrono::NaiveDate = date.extract()?; // PyDateをchronoのNaiveDateに変換
let next_date = date + chrono::Duration::days(1);
let next_date = next_date.into_pyobject(py)?; // chronoのNativeDateをPyDateに変換
Ok(next_date.into())
}
}
pyfunctionの関数の引数や戻り値として直接chronoの日付を指定することも出来る。
use pyo3::prelude::*;
#[pymodule]
mod example_pyo3 {
use pyo3::{prelude::*, types::*};
〜
#[pyfunction]
fn inc_date(date: chrono::NaiveDate) -> PyResult<chrono::NaiveDate> {
let next_date = date + chrono::Duration::days(1);
Ok(next_date)
}
}
numpyのdatetime64を扱う例。[2026-02-07]
datetime64クラスをPyO3で直接扱う方法は無いようなので、astypeメソッドを呼び出して変換する。
#[pyfunction]
fn numpy_datetime64(value: Bound<PyAny>) -> PyResult<()> {
let value = value.call_method1("astype", ("datetime64[ns]",))?;
let value = value.call_method1("astype", ("int64",))?;
let value: i64 = value.extract()?;
println!("epoch: {}", value);
Ok(())
}
datetime64は色々な単位で保持できるようなので、まずナノ秒単位に変換する。
その後エポック(1970-01-01からの経過ナノ秒)の数値に変換する。