Skip to content

Commit 99c459b

Browse files
committed
Include timezone in when serializing JSON responses
This adds back the timezone information to JSON responses. Note that the format is slightly different than we provided from the deprecated `time` crate. Previously, responses would end in `Z` and now the timezone is provided as `+00:00`. However, both representations are compliant with RFC3339. Fixes #1123
1 parent 566c7be commit 99c459b

File tree

8 files changed

+61
-12
lines changed

8 files changed

+61
-12
lines changed

src/category.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pub struct EncodableCategory {
3535
pub category: String,
3636
pub slug: String,
3737
pub description: String,
38-
pub created_at: NaiveDateTime,
38+
#[serde(with = "::util::rfc3339")] pub created_at: NaiveDateTime,
3939
pub crates_cnt: i32,
4040
}
4141

@@ -45,7 +45,7 @@ pub struct EncodableCategoryWithSubcategories {
4545
pub category: String,
4646
pub slug: String,
4747
pub description: String,
48-
pub created_at: NaiveDateTime,
48+
#[serde(with = "::util::rfc3339")] pub created_at: NaiveDateTime,
4949
pub crates_cnt: i32,
5050
pub subcategories: Vec<EncodableCategory>,
5151
}

src/crate_owner_invitation.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ pub struct EncodableCrateOwnerInvitation {
6161
pub invited_by_username: String,
6262
pub crate_name: String,
6363
pub crate_id: i32,
64-
pub created_at: NaiveDateTime,
64+
#[serde(with = "::util::rfc3339")] pub created_at: NaiveDateTime,
6565
}
6666

6767
/// Handles the `GET /me/crate_owner_invitations` route.

src/keyword.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub struct CrateKeyword {
3434
pub struct EncodableKeyword {
3535
pub id: String,
3636
pub keyword: String,
37-
pub created_at: NaiveDateTime,
37+
#[serde(with = "::util::rfc3339")] pub created_at: NaiveDateTime,
3838
pub crates_cnt: i32,
3939
}
4040

src/krate/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,12 +96,12 @@ type ByName<'a> = diesel::dsl::Filter<All, WithName<'a>>;
9696
pub struct EncodableCrate {
9797
pub id: String,
9898
pub name: String,
99-
pub updated_at: NaiveDateTime,
99+
#[serde(with = "::util::rfc3339")] pub updated_at: NaiveDateTime,
100100
pub versions: Option<Vec<i32>>,
101101
pub keywords: Option<Vec<String>>,
102102
pub categories: Option<Vec<String>>,
103103
pub badges: Option<Vec<EncodableBadge>>,
104-
pub created_at: NaiveDateTime,
104+
#[serde(with = "::util::rfc3339")] pub created_at: NaiveDateTime,
105105
pub downloads: i32,
106106
pub recent_downloads: Option<i64>,
107107
pub max_version: String,

src/token.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ pub struct ApiToken {
1818
#[serde(skip)] pub user_id: i32,
1919
#[serde(skip)] pub token: String,
2020
pub name: String,
21-
pub created_at: NaiveDateTime,
22-
pub last_used_at: Option<NaiveDateTime>,
21+
#[serde(with = "::util::rfc3339")] pub created_at: NaiveDateTime,
22+
#[serde(with = "::util::rfc3339::option")] pub last_used_at: Option<NaiveDateTime>,
2323
}
2424

2525
/// The serialization format for the `ApiToken` model with its token value.
@@ -30,8 +30,8 @@ pub struct EncodableApiTokenWithToken {
3030
pub id: i32,
3131
pub name: String,
3232
pub token: String,
33-
pub created_at: NaiveDateTime,
34-
pub last_used_at: Option<NaiveDateTime>,
33+
#[serde(with = "::util::rfc3339")] pub created_at: NaiveDateTime,
34+
#[serde(with = "::util::rfc3339::option")] pub last_used_at: Option<NaiveDateTime>,
3535
}
3636

3737
impl ApiToken {

src/util/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub use self::io_util::{read_fill, LimitErrorReader, read_le_u32};
1919
pub use self::request_proxy::RequestProxy;
2020

2121
pub mod errors;
22+
pub mod rfc3339;
2223
mod hasher;
2324
mod head;
2425
mod io_util;

src/util/rfc3339.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//! Convenience functions for serializing and deserializing times in RFC 3339 format.
2+
//! Used for returning time values in JSON API responses.
3+
//! Example: `2012-02-22T14:53:18+00:00`.
4+
5+
use chrono::{DateTime, NaiveDateTime, Utc};
6+
use serde::{self, Deserialize, Deserializer, Serializer};
7+
8+
pub fn serialize<S>(dt: &NaiveDateTime, serializer: S) -> Result<S::Ok, S::Error>
9+
where
10+
S: Serializer,
11+
{
12+
let s = DateTime::<Utc>::from_utc(*dt, Utc).to_rfc3339();
13+
serializer.serialize_str(&s)
14+
}
15+
pub fn deserialize<'de, D>(deserializer: D) -> Result<NaiveDateTime, D::Error>
16+
where
17+
D: Deserializer<'de>,
18+
{
19+
let s = String::deserialize(deserializer)?;
20+
let dt = DateTime::parse_from_rfc3339(&s).map_err(serde::de::Error::custom)?;
21+
Ok(dt.naive_utc())
22+
}
23+
24+
/// Wrapper for dealing with Option<NaiveDateTime>
25+
pub mod option {
26+
use chrono::NaiveDateTime;
27+
use serde::{Deserializer, Serializer};
28+
29+
pub fn serialize<S>(dt: &Option<NaiveDateTime>, serializer: S) -> Result<S::Ok, S::Error>
30+
where
31+
S: Serializer,
32+
{
33+
match *dt {
34+
Some(dt) => super::serialize(&dt, serializer),
35+
None => serializer.serialize_none(),
36+
}
37+
}
38+
39+
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<NaiveDateTime>, D::Error>
40+
where
41+
D: Deserializer<'de>,
42+
{
43+
match super::deserialize(deserializer) {
44+
Ok(dt) => Ok(Some(dt)),
45+
Err(_) => Ok(None),
46+
}
47+
}
48+
}

src/version/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ pub struct EncodableVersion {
5252
pub num: String,
5353
pub dl_path: String,
5454
pub readme_path: String,
55-
pub updated_at: NaiveDateTime,
56-
pub created_at: NaiveDateTime,
55+
#[serde(with = "::util::rfc3339")] pub updated_at: NaiveDateTime,
56+
#[serde(with = "::util::rfc3339")] pub created_at: NaiveDateTime,
5757
pub downloads: i32,
5858
pub features: HashMap<String, Vec<String>>,
5959
pub yanked: bool,

0 commit comments

Comments
 (0)