represent post dates as a NaiveDateTime, still allowing for date-only

posts can be specified with a date only, or date and time as desired.
it is up to the site's specific template to render posts with an
appropriate date/time format string based on what the author's
preferences
This commit is contained in:
Gered 2023-06-28 15:16:24 -04:00
parent 3f18b2a58a
commit 83d75d4885
7 changed files with 37 additions and 15 deletions

View file

@ -3,7 +3,7 @@
{ {
"file_path": "2023-01-01-hello-world.md", "file_path": "2023-01-01-hello-world.md",
"title": "Hello, world!", "title": "Hello, world!",
"date": "2023-01-01", "date": "2023-01-01 12:30:42",
"slug": "hello-world", "slug": "hello-world",
"tags": ["aaa", "hello", "testing"] "tags": ["aaa", "hello", "testing"]
}, },
@ -17,7 +17,7 @@
{ {
"file_path": "2023-03-20-lorem-ipsum.md", "file_path": "2023-03-20-lorem-ipsum.md",
"title": "Lorem Ipsum", "title": "Lorem Ipsum",
"date": "2023-03-20", "date": "2023-03-20 18:01",
"slug": "lorem-ipsum" "slug": "lorem-ipsum"
}, },
{ {

View file

@ -8,7 +8,7 @@
<table> <table>
{% for post in posts %} {% for post in posts %}
<tr> <tr>
<td><time>{{ post.date }}</time></td> <td><time>{{ post.date | date(format="%Y-%b-%d") }}</time></td>
<td> <td>
<a href="{{ post.url }}">{{ post.title }}</a> <a href="{{ post.url }}">{{ post.title }}</a>
<span class="tags"> <span class="tags">

View file

@ -2,7 +2,7 @@
<header> <header>
<h1>{{ post.title }}</h1> <h1>{{ post.title }}</h1>
<div class="meta"> <div class="meta">
{{ post.date }} &mdash; {{ post.date | date(format="%B %e, %Y") }} &mdash;
<span class="tags"> <span class="tags">
{%- for tag in post.tags -%} {%- for tag in post.tags -%}
<span><a href="/tag/{{ tag }}/">{{ tag }}</a></span> <span><a href="/tag/{{ tag }}/">{{ tag }}</a></span>

View file

@ -8,7 +8,7 @@
<table> <table>
{% for post in posts %} {% for post in posts %}
<tr> <tr>
<td><time>{{ post.date }}</time></td> <td><time>{{ post.date | date }}</time></td>
<td><a href="{{ post.url }}">{{ post.title }}</a></td> <td><a href="{{ post.url }}">{{ post.title }}</a></td>
</tr> </tr>
{% endfor %} {% endfor %}

View file

@ -37,8 +37,8 @@ pub struct Pages {
pub struct Post { pub struct Post {
pub file_path: PathBuf, pub file_path: PathBuf,
pub title: String, pub title: String,
#[serde(deserialize_with = "crate::util::deserialize_naivedate")] #[serde(deserialize_with = "crate::util::deserialize_string_to_naivedatetime")]
pub date: chrono::NaiveDate, pub date: chrono::NaiveDateTime,
pub slug: String, pub slug: String,
pub old_urls: Option<Vec<String>>, pub old_urls: Option<Vec<String>>,
pub tags: Option<Vec<String>>, pub tags: Option<Vec<String>>,

View file

@ -106,8 +106,8 @@ pub struct Post {
pub url: UriPath, pub url: UriPath,
pub title: String, pub title: String,
pub content_html: String, pub content_html: String,
#[serde(serialize_with = "crate::util::serialize_naivedate")] #[serde(serialize_with = "crate::util::serialize_naivedatetime_to_i64")]
pub date: chrono::NaiveDate, pub date: chrono::NaiveDateTime,
pub tags: Vec<Tag>, pub tags: Vec<Tag>,
} }
@ -327,7 +327,7 @@ impl SiteService {
.title(post.title.clone()) .title(post.title.clone())
.content(post.content_html.clone()) .content(post.content_html.clone())
.link(base_url.clone().join(&post.url).unwrap().to_string()) .link(base_url.clone().join(&post.url).unwrap().to_string())
.pub_date(chrono::Local.from_local_date(&post.date).unwrap().to_string()) .pub_date(chrono::Local.from_local_datetime(&post.date).unwrap().to_string())
.build() .build()
}) })
.collect::<Vec<rss::Item>>(), .collect::<Vec<rss::Item>>(),

View file

@ -1,10 +1,32 @@
pub fn deserialize_naivedate<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<chrono::NaiveDate, D::Error> { fn parse_datetime_from_str(s: &str) -> Result<chrono::NaiveDateTime, chrono::ParseError> {
let s: String = serde::Deserialize::deserialize(deserializer)?; let dt = chrono::NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S");
chrono::NaiveDate::parse_from_str(&s, "%Y-%m-%d").map_err(serde::de::Error::custom) if dt.is_ok() {
return dt;
}
let dt = chrono::NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M");
if dt.is_ok() {
return dt;
}
match chrono::NaiveDate::parse_from_str(s, "%Y-%m-%d") {
Ok(date) => Ok(date.and_time(chrono::NaiveTime::default())),
Err(e) => Err(e),
}
} }
pub fn serialize_naivedate<S: serde::Serializer>(value: &chrono::NaiveDate, serializer: S) -> Result<S::Ok, S::Error> { pub fn deserialize_string_to_naivedatetime<'de, D: serde::Deserializer<'de>>(
serializer.serialize_str(&value.to_string()) deserializer: D,
) -> Result<chrono::NaiveDateTime, D::Error> {
let s: String = serde::Deserialize::deserialize(deserializer)?;
parse_datetime_from_str(&s).map_err(serde::de::Error::custom)
}
pub fn serialize_naivedatetime_to_i64<S: serde::Serializer>(
value: &chrono::NaiveDateTime,
serializer: S,
) -> Result<S::Ok, S::Error> {
serializer.serialize_i64(value.timestamp())
} }
pub fn safe_subslice<T>(slice: &[T], start: usize, count: usize) -> Option<&[T]> { pub fn safe_subslice<T>(slice: &[T], start: usize, count: usize) -> Option<&[T]> {