Skip to main content

exiftool/parse_fn/
date.rs

1use chrono::NaiveDate;
2use serde::{self, Deserialize, Deserializer};
3use serde_json::Value;
4
5/// Deserializes a string in "%Y:%m:%d" format into a `NaiveDate`, gracefully skipping null or number values.
6///
7/// # Errors
8///
9/// Returns an error if the input is a string that does not match the required format or is an unsupported JSON type.
10pub fn date<'de, D>(deserializer: D) -> Result<Option<NaiveDate>, D::Error>
11where
12    D: Deserializer<'de>,
13{
14    // Deserialize into a generic JSON value
15    let value: Option<Value> = Option::deserialize(deserializer)?;
16
17    value.map_or_else(
18        || Ok(None),
19        |value| match value {
20            Value::String(s) => {
21                // Try parsing the string as a NaiveDate
22                NaiveDate::parse_from_str(&s, "%Y:%m:%d")
23                    .map(Some)
24                    .map_err(|_| serde::de::Error::custom(format!("invalid date format: {s}")))
25            }
26            Value::Number(_) | Value::Null => Ok(None), // Gracefully skip numbers
27            other => Err(serde::de::Error::custom(format!(
28                "unexpected type for date: {other:?}"
29            ))),
30        },
31    )
32}