How to deserialise DateTime from toml configuration

RMAG news

When implementing a new configuration parameter for Texted, I needed something to represent the date the blog started.

When looking into the TOML website, I was fortunate to discover that it has a data type for dates, so I could create the new parameter

blog_start_date = 2016-06-25

However, my fortune was gone as I found that the Toml crate does not support deserialising.

First, I tried to find if any other crate implemented this, but I found nothing that worked and most of them were over complicated for my use case.

Then I thought, I am pretty sure I am not the only one with this need and with some searching, I found in Arnau Siches website a nice solution for what I needed and I am sharing here a slightly modified version of their solution

use std::str::FromStr;

use chrono::{NaiveDate, ParseError};
use serde::Deserialize;

// Code adapted from https://www.seachess.net/notes/toml-dates/
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct TomlDate(pub NaiveDate);

impl<‘de> Deserialize<‘de> for TomlDate {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<‘de>,
{
use serde::de::Error;
let value = toml::value::Datetime::deserialize(deserializer)?;
let date = TomlDate::from_str(&value.to_string()).map_err(Error::custom)?;
Ok(date)
}
}

impl FromStr for TomlDate {
type Err = ParseError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let naive = NaiveDate::from_str(s)?;
Ok(Self(naive))
}
}

Of course, one small unit test to make sure it works.

#[cfg(test)]
mod tests {
use serde::Deserialize;

use super::*;

#[derive(Deserialize)]
pub struct Personal {
pub activity_start_year: i32,
pub blog_start_date: TomlDate,
}

#[derive(Deserialize)]
pub struct Config {
pub personal: Personal,
}

#[test]
fn test_date_time() {
let toml_str = r##”
[personal]
activity_start_year = 2000
blog_start_date = 2024-04-22
“##
;
let cfg: Config = toml::from_str::<Config>(toml_str).unwrap();
assert_eq!(cfg.personal.blog_start_date, TomlDate(NaiveDate::from_ymd_opt(2024, 04, 22).unwrap()));
}
}

To conclude, please note that this code was adapted from a CC BY-NC 4.0 license

Link to author’s blog: thiagocafe/How to deserialise DateTime from toml configuration

Leave a Reply

Your email address will not be published. Required fields are marked *