How to use date functions with Polars series

I am trying to use date functions with a Polars dataframe (or series) and it is not working for me. I am trying to use the num_days_from_ce() function, but I am pretty sure my problems applies to all date function. There is something I am missing. First let's look at an example that does work:

    let df: DataFrame = df!(
        "date" => &[
                    NaiveDate::from_ymd_opt(2022, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap(),
                    NaiveDate::from_ymd_opt(2022, 1, 2).unwrap().and_hms_opt(0, 0, 0).unwrap(),
                    NaiveDate::from_ymd_opt(2022, 1, 3).unwrap().and_hms_opt(0, 0, 0).unwrap(),
                    NaiveDate::from_ymd_opt(2022, 1, 4).unwrap().and_hms_opt(0, 0, 0).unwrap(),
                    NaiveDate::from_ymd_opt(2022, 1, 5).unwrap().and_hms_opt(0, 0, 0).unwrap()
        ],
        "price" => &[4.0, 5.0, 6.0, 7.0, 8.0]
        ).unwrap();
    println!("df: {}", df);

    let out = df.clone()
        .lazy()
        .select([
                (col("price") + lit(2)).alias("test1"),
                (NaiveDate::from_ymd_opt(1, 1, 1).unwrap().num_days_from_ce()).into(),
                ])
        .collect();
    println!("out: {:?}", out);

In that example I was able to use num_days_from_ce() without problem, when when I try to use it on a the real dataframe, I get an error

error[E0599]: no method named `num_days_from_ce` found for struct `Series` in the current scope
  --> src/main.rs:67:34
   |
67 |             .map(|s| { Ok(Some(s.num_days_from_ce())) },
   |                                  ^^^^^^^^^^^^^^^^ method not found in `Series`

Here is the non-working example:

    let new = df.lazy()
        .with_column(
            col("date")
            .map(|s| { Ok(Some(s.num_days_from_ce())) },
            GetOutput::from_type(DataType::Int32)).alias("new_column")
        )
        .collect()
        .unwrap();
    println!("new: {:?}", new);

As an alternative, I tried extracting the column as a series first and using the function on that, but I get pretty much the same error. Here is the example:

   let mut test = &df.column("date");
    let test = test.map(|x| x.num_days_from_ce()).collect();
    println!("test: {:?}", test);

I am probably just missing some import or feature, but I cannot figure out which one and would appreciate any help.

If this is using Chrono you may have to import the Datelike trait to get num_days_from_ce.

Yes, I was already using this: use chrono::{NaiveDate, Datelike, Weekday};

Here's a version that allows you to map a Series of datetime object to a Series of integers where each value is the number of days in the proleptic Gregorian calendar for the given date:

/*
[dependencies]
polars = { version = "0.29.0", features = ["lazy", "dtype-datetime"]}
*/
use polars::export::chrono::{Datelike, NaiveDate};
use polars::prelude::*;

fn main() {
    let df: DataFrame = df!(
        "date" => &[
            NaiveDate::from_ymd_opt(2022, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap(),
            NaiveDate::from_ymd_opt(2022, 1, 2).unwrap().and_hms_opt(0, 0, 0).unwrap(),
            NaiveDate::from_ymd_opt(2022, 1, 3).unwrap().and_hms_opt(0, 0, 0).unwrap(),
            NaiveDate::from_ymd_opt(2022, 1, 4).unwrap().and_hms_opt(0, 0, 0).unwrap(),
            NaiveDate::from_ymd_opt(2022, 1, 5).unwrap().and_hms_opt(0, 0, 0).unwrap()
        ],
        "price" => &[4.0, 5.0, 6.0, 7.0, 8.0]
    )
    .unwrap();

    let new = df
        .lazy()
        .with_column(
            col("date")
                .map(
                    |s| {
                        Ok(Some(
                            s.datetime()
                                .expect("series must contain datetimes")
                                .as_datetime_iter()
                                .map(|d| d.map(|d| d.num_days_from_ce()))
                                .collect(),
                        ))
                    },
                    GetOutput::from_type(DataType::Int32),
                )
                .alias("new_column"),
        )
        .collect()
        .unwrap();

    println!("new: {:?}", new);
}

Rustexplorer.

1 Like

Thank you so much. I see now that I have to use as.datetime_iter() with a double map. I wasn't aware of that. Also, thanks for pointing out rustexplorer. That will come in very handy as the rust playground does not seem to support polars. Thanks again.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.