From 990e611a56f37f64fbce74fbc487c7dcc4aa4e28 Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Sun, 4 Jun 2017 20:32:25 -0700 Subject: [PATCH] Use chrono for struct timestamp fields Chrono is easier to use than timestamped strings, so they should be automatically deserialized and available for the user, instead of having the user deserialize the strings themselves. These fields have been changed to use a type of `DateTime`: - `ChannelPinsUpdateEvent.last_pin_timestamp` - `Group.last_pin_timestamp` - `Guild.joined_at` - `GuildChannel.last_pin_timestamp` - `Invite.created_at` - `Member.joined_at` - `Message.edited_timestamp - `Message.timestamp` - `MessageUpdateEvent.edited_timestamp` - `MessageUpdateEvent.timestamp` - `PrivateChannel.last_pin_timestamp` `Member.joined_at` is now also an `Option`. Previously, if a Guild Member Update was received for a member not in the cache, a new Member would be instantiated with a default String value. This is incorrect behaviour, and has now been replaced with being set to `None` in that case. Id methods' `created_at()` method now return a `chrono::NaiveDateTime` instead of a `time::Timespec`, and `User::created_at` has been updated to reflect that. Additionally, drop `time` as a direct dependency and use chrono for internals. --- Cargo.toml | 5 +- src/builder/create_embed.rs | 88 +++++++++++++++++++++++----- src/cache/mod.rs | 2 +- src/framework/buckets.rs | 4 +- src/framework/mod.rs | 6 +- src/gateway/prep.rs | 6 +- src/gateway/shard.rs | 4 +- src/http/ratelimiting.rs | 4 +- src/internal/timer.rs | 25 +++++--- src/lib.rs | 2 +- src/model/channel/group.rs | 3 +- src/model/channel/guild_channel.rs | 3 +- src/model/channel/message.rs | 25 ++++---- src/model/channel/private_channel.rs | 3 +- src/model/event.rs | 7 ++- src/model/guild/member.rs | 5 +- src/model/guild/mod.rs | 5 +- src/model/invite.rs | 5 +- src/model/mod.rs | 6 +- src/model/user.rs | 6 +- tests/test_decode_role.rs | 14 ++--- tests/test_formatters.rs | 2 +- 22 files changed, 151 insertions(+), 79 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ee001394b3d..359a45f0d4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,12 +18,15 @@ log = "~0.3" serde = "^1.0" serde_derive = "^1.0" serde_json = "^1.0" -time = "~0.1" [dependencies.byteorder] optional = true version = "1.0" +[dependencies.chrono] +features = ["serde"] +version = "~0.3" + [dependencies.cookie] default-features = false version = "0.2" diff --git a/src/builder/create_embed.rs b/src/builder/create_embed.rs index 00999361fe8..7b676bee0aa 100644 --- a/src/builder/create_embed.rs +++ b/src/builder/create_embed.rs @@ -15,9 +15,10 @@ //! [`ExecuteWebhook::embeds`]: struct.ExecuteWebhook.html#method.embeds //! [here]: https://discordapp.com/developers/docs/resources/channel#embed-object +use chrono::{DateTime, TimeZone}; use serde_json::Value; use std::default::Default; -use time::Tm; +use std::fmt::Display; use ::internal::prelude::*; use ::model::Embed; @@ -177,26 +178,75 @@ impl CreateEmbed { /// Set the timestamp. /// - /// **Note**: This timestamp must be in ISO-8601 format. It must also be - /// in UTC format. - /// - /// # Examples - /// /// You may pass a direct string: /// /// - `2017-01-03T23:00:00` /// - `2004-06-08T16:04:23` /// - `2004-06-08T16:04:23` /// - /// Or a `time::Tm`: + /// This timestamp must be in ISO-8601 format. It must also be in UTC format. /// - /// ```rust,ignore - /// extern crate time; + /// You can also pass anything that implements `chrono::TimeZone`. /// - /// let now = time::now(); + /// # Examples + /// + /// Passing a string timestamp: /// - /// embed = embed.timestamp(now); - /// // ... + /// ```rust,no_run + /// # use serenity::Client; + /// # + /// # let mut client = Client::login(""); + /// # + /// client.on_message(|_, msg| { + /// if msg.content == "~embed" { + /// let _ = msg.channel_id.send_message(|m| m + /// .embed(|e| e + /// .title("hello") + /// .timestamp("2004-06-08T16:04:23"))); + /// } + /// }); + /// ``` + /// + /// Creating a join-log: + /// + /// Note: this example isn't efficient and is for demonstrative purposes. + /// + /// ```rust,no_run + /// # use serenity::Client; + /// # + /// # let mut client = Client::login(""); + /// # + /// use serenity::CACHE; + /// + /// client.on_guild_member_add(|_, guild_id, member| { + /// let cache = CACHE.read().unwrap(); + /// + /// if let Some(guild) = cache.guild(guild_id) { + /// let guild = guild.read().unwrap(); + /// + /// let channel_search = guild + /// .channels + /// .values() + /// .find(|c| c.read().unwrap().name == "join-log"); + /// + /// if let Some(channel) = channel_search { + /// let user = member.user.read().unwrap(); + /// + /// let _ = channel.read().unwrap().send_message(|m| m + /// .embed(|e| { + /// let mut e = e + /// .author(|a| a.icon_url(&user.face()).name(&user.name)) + /// .title("Member Join"); + /// + /// if let Some(ref joined_at) = member.joined_at { + /// e = e.timestamp(joined_at); + /// } + /// + /// e + /// })); + /// } + /// } + /// }); /// ``` pub fn timestamp>(mut self, timestamp: T) -> Self { self.0.insert("timestamp".to_owned(), Value::String(timestamp.into().ts)); @@ -406,10 +456,18 @@ impl From for Timestamp { } } -impl From for Timestamp { - fn from(tm: Tm) -> Self { +impl<'a> From<&'a str> for Timestamp { + fn from(ts: &'a str) -> Self { + Timestamp { + ts: ts.to_owned(), + } + } +} + +impl<'a, Tz: TimeZone> From<&'a DateTime> for Timestamp where Tz::Offset: Display { + fn from(dt: &'a DateTime) -> Self { Timestamp { - ts: tm.to_utc().rfc3339().to_string(), + ts: dt.to_rfc3339(), } } } diff --git a/src/cache/mod.rs b/src/cache/mod.rs index 246ca02b9f2..98c6648c77f 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -960,7 +960,7 @@ impl Cache { guild.members.insert(event.user.id, Member { deaf: false, guild_id: Some(event.guild_id), - joined_at: String::default(), + joined_at: None, mute: false, nick: event.nick.clone(), roles: event.roles.clone(), diff --git a/src/framework/buckets.rs b/src/framework/buckets.rs index eea12533a9a..4f24893b484 100644 --- a/src/framework/buckets.rs +++ b/src/framework/buckets.rs @@ -1,6 +1,6 @@ +use chrono::UTC; use std::collections::HashMap; use std::default::Default; -use time; #[doc(hidden)] pub struct Ratelimit { @@ -33,7 +33,7 @@ pub struct Bucket { impl Bucket { pub fn take(&mut self, user_id: u64) -> i64 { - let time = time::get_time().sec; + let time = UTC::now().timestamp(); let user = self.users.entry(user_id) .or_insert_with(MemberRatelimit::default); diff --git a/src/framework/mod.rs b/src/framework/mod.rs index ba0aa365415..38615c8e92f 100644 --- a/src/framework/mod.rs +++ b/src/framework/mod.rs @@ -591,7 +591,7 @@ impl Framework { /// ```rust /// # #[macro_use] extern crate serenity; /// command!(ping(_ctx, msg) { - /// msg.channel_id.say("pong!"); + /// msg.channel_id.say("pong!"); /// }); /// # /// # fn main() { @@ -700,7 +700,7 @@ impl Framework { /// # use serenity::Client; /// # let mut client = Client::login("token"); /// use serenity::framework::DispatchError::{NotEnoughArguments, TooManyArguments}; - /// + /// /// client.with_framework(|f| f /// .on_dispatch_error(|ctx, msg, error| { /// match error { @@ -711,7 +711,7 @@ impl Framework { /// msg.channel_id.say(&format!("Max arguments allowed is {}, but got {}.", max, given)); /// } /// _ => println!("Unhandled dispatch error.") - /// } + /// } /// })); /// ``` pub fn on_dispatch_error(mut self, f: F) -> Self diff --git a/src/gateway/prep.rs b/src/gateway/prep.rs index 6a415f8ab09..8e04df430cf 100644 --- a/src/gateway/prep.rs +++ b/src/gateway/prep.rs @@ -1,3 +1,4 @@ +use chrono::{Duration, UTC}; use serde_json::Value; use std::sync::mpsc::{ Receiver as MpscReceiver, @@ -8,7 +9,6 @@ use std::sync::{Arc, Mutex}; use std::time::{Duration as StdDuration, Instant}; use std::{env, thread}; use super::{GatewayError, GatewayStatus}; -use time::{self, Duration}; use websocket::client::request::Url as RequestUrl; use websocket::client::{Receiver, Sender}; use websocket::result::WebSocketError as WsError; @@ -81,7 +81,7 @@ pub fn keepalive(interval: u64, mut sender: Sender, channel: &MpscReceiver) { let mut base_interval = Duration::milliseconds(interval as i64); - let mut next_tick = time::get_time() + base_interval; + let mut next_tick = UTC::now() + base_interval; let mut last_sequence = 0; let mut last_successful = false; @@ -110,7 +110,7 @@ pub fn keepalive(interval: u64, } } - if time::get_time() >= next_tick { + if UTC::now() >= next_tick { // If the last heartbeat didn't receive an acknowledgement, then // shutdown and auto-reconnect. if !*last_ack.lock().unwrap() { diff --git a/src/gateway/shard.rs b/src/gateway/shard.rs index 7790cc6cbd8..343aa0601e2 100644 --- a/src/gateway/shard.rs +++ b/src/gateway/shard.rs @@ -1,3 +1,4 @@ +use chrono::UTC; use std::io::Write; use std::net::Shutdown; use std::sync::mpsc::{self, Sender as MpscSender}; @@ -6,7 +7,6 @@ use std::thread::{self, Builder as ThreadBuilder}; use std::time::{Duration as StdDuration, Instant}; use std::mem; use super::{GatewayError, GatewayStatus, prep}; -use time; use websocket::client::{Client as WsClient, Sender, Receiver}; use websocket::message::Message as WsMessage; use websocket::result::WebSocketError; @@ -788,7 +788,7 @@ impl Shard { fn update_presence(&self) { let (ref game, status, afk) = self.current_presence; - let now = time::get_time().sec as u64; + let now = UTC::now().timestamp() as u64; let msg = json!({ "op": OpCode::StatusUpdate.num(), diff --git a/src/http/ratelimiting.rs b/src/http/ratelimiting.rs index 95318aeec2e..d290dd01f5e 100644 --- a/src/http/ratelimiting.rs +++ b/src/http/ratelimiting.rs @@ -40,6 +40,7 @@ //! [Taken from]: https://discordapp.com/developers/docs/topics/rate-limits#rate-limits #![allow(zero_ptr)] +use chrono::UTC; use hyper::client::{RequestBuilder, Response}; use hyper::header::Headers; use hyper::status::StatusCode; @@ -48,7 +49,6 @@ use std::sync::{Arc, Mutex}; use std::time::Duration; use std::{i64, str, thread}; use super::{HttpError, LightMethod}; -use time; use ::internal::prelude::*; lazy_static! { @@ -441,7 +441,7 @@ impl RateLimit { return; } - let current_time = time::get_time().sec; + let current_time = UTC::now().timestamp(); // The reset was in the past, so we're probably good. if current_time > self.reset { diff --git a/src/internal/timer.rs b/src/internal/timer.rs index cc846b3b0d0..677ece1a9c2 100644 --- a/src/internal/timer.rs +++ b/src/internal/timer.rs @@ -1,9 +1,9 @@ +use chrono::{DateTime, Duration, UTC}; use std::thread; use std::time::Duration as StdDuration; -use time::{self, Duration, Timespec}; pub struct Timer { - due: Timespec, + due: DateTime, duration: Duration, } @@ -12,25 +12,32 @@ impl Timer { let duration = Duration::milliseconds(duration_in_ms as i64); Timer { - due: time::get_time() + duration, + due: UTC::now() + duration, duration: duration, } } pub fn await(&mut self) { - let diff = self.due - time::get_time(); + let due_time = (self.due.timestamp() * 1000) + self.due.timestamp_subsec_millis() as i64; + let now_time = { + let now = UTC::now(); - if diff > time::Duration::zero() { - let amount = diff.num_milliseconds() as u64; + (now.timestamp() * 1000) + now.timestamp_subsec_millis() as i64 + }; - thread::sleep(StdDuration::from_millis(amount)); + if due_time > now_time { + let sleep_time = due_time - now_time; + + if sleep_time > 0 { + thread::sleep(StdDuration::from_millis(sleep_time as u64)); + } } self.due = self.due + self.duration; } pub fn check(&mut self) -> bool { - if time::get_time() >= self.due { + if UTC::now() >= self.due { self.due = self.due + self.duration; true @@ -40,6 +47,6 @@ impl Timer { } pub fn reset(&mut self) { - self.due = time::get_time() + self.duration; + self.due = UTC::now() + self.duration; } } diff --git a/src/lib.rs b/src/lib.rs index f5f695c6c2d..8a2e6803a79 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -103,9 +103,9 @@ extern crate serde_json; extern crate lazy_static; extern crate base64; +extern crate chrono; extern crate flate2; extern crate serde; -extern crate time; #[cfg(feature="voice")] extern crate byteorder; diff --git a/src/model/channel/group.rs b/src/model/channel/group.rs index 25c4690419e..63efb90e594 100644 --- a/src/model/channel/group.rs +++ b/src/model/channel/group.rs @@ -1,3 +1,4 @@ +use chrono::{DateTime, FixedOffset}; use ::model::*; #[cfg(feature="model")] @@ -26,7 +27,7 @@ pub struct Group { /// The Id of the last message sent. pub last_message_id: Option, /// Timestamp of the latest pinned message. - pub last_pin_timestamp: Option, + pub last_pin_timestamp: Option>, /// The name of the group channel. pub name: Option, /// The Id of the group owner. diff --git a/src/model/channel/guild_channel.rs b/src/model/channel/guild_channel.rs index 8b55d045e52..5ce70316d13 100644 --- a/src/model/channel/guild_channel.rs +++ b/src/model/channel/guild_channel.rs @@ -1,3 +1,4 @@ +use chrono::{DateTime, FixedOffset}; use ::model::*; #[cfg(feature="model")] @@ -46,7 +47,7 @@ pub struct GuildChannel { /// The timestamp of the time a pin was most recently made. /// /// **Note**: This is only available for text channels. - pub last_pin_timestamp: Option, + pub last_pin_timestamp: Option>, /// The name of the channel. pub name: String, /// Permission overwrites for [`Member`]s and for [`Role`]s. diff --git a/src/model/channel/message.rs b/src/model/channel/message.rs index 8b9f0af1d90..612113dc8a2 100644 --- a/src/model/channel/message.rs +++ b/src/model/channel/message.rs @@ -1,3 +1,4 @@ +use chrono::{DateTime, FixedOffset}; use ::model::*; #[cfg(feature="cache")] @@ -5,8 +6,6 @@ use std::fmt::Write; #[cfg(feature="model")] use std::mem; #[cfg(feature="model")] -use time; -#[cfg(feature="model")] use ::builder::{CreateEmbed, CreateMessage}; #[cfg(feature="model")] use ::constants; @@ -33,7 +32,7 @@ pub struct Message { /// The content of the message. pub content: String, /// The timestamp of the last time the message was updated, if it was. - pub edited_timestamp: Option, + pub edited_timestamp: Option>, /// Array of embeds sent with the message. pub embeds: Vec, /// Indicator of the type of message this is, i.e. whether it is a regular @@ -56,7 +55,7 @@ pub struct Message { #[serde(default)] pub reactions: Vec, /// Initial message creation timestamp, calculated from its Id. - pub timestamp: String, + pub timestamp: DateTime, /// Indicator of whether the command is to be played back via /// text-to-speech. /// @@ -240,16 +239,14 @@ impl Message { self.content = format!("{} pinned a message to this channel. See all the pins.", self.author); }, MessageType::MemberJoin => { - if let Ok(tm) = time::strptime(&self.timestamp, "%Y-%m-%dT%H:%M:%S") { - let sec = tm.to_timespec().sec as usize; - let chosen = constants::JOIN_MESSAGES[sec % constants::JOIN_MESSAGES.len()]; - - self.content = if chosen.contains("$user") { - chosen.replace("$user", &self.author.mention()) - } else { - chosen.to_owned() - }; - } + let sec = self.timestamp.timestamp() as usize; + let chosen = constants::JOIN_MESSAGES[sec % constants::JOIN_MESSAGES.len()]; + + self.content = if chosen.contains("$user") { + chosen.replace("$user", &self.author.mention()) + } else { + chosen.to_owned() + }; }, _ => {}, } diff --git a/src/model/channel/private_channel.rs b/src/model/channel/private_channel.rs index 7a0ed540d31..797ba9442a4 100644 --- a/src/model/channel/private_channel.rs +++ b/src/model/channel/private_channel.rs @@ -1,3 +1,4 @@ +use chrono::{DateTime, FixedOffset}; use std::fmt::{Display, Formatter, Result as FmtResult}; use super::deserialize_single_recipient; use ::model::*; @@ -21,7 +22,7 @@ pub struct PrivateChannel { /// Timestamp of the last time a [`Message`] was pinned. /// /// [`Message`]: struct.Message.html - pub last_pin_timestamp: Option, + pub last_pin_timestamp: Option>, /// Indicator of the type of channel this is. /// /// This should always be [`ChannelType::Private`]. diff --git a/src/model/event.rs b/src/model/event.rs index 6458b772c48..bbb60c7c4f2 100644 --- a/src/model/event.rs +++ b/src/model/event.rs @@ -1,5 +1,6 @@ //! All the events this library handles. +use chrono::{DateTime, FixedOffset}; use serde::de::Error as DeError; use serde_json::{self, Error as JsonError}; use std::collections::HashMap; @@ -55,7 +56,7 @@ impl<'de> Deserialize<'de> for ChannelDeleteEvent { #[derive(Clone, Debug, Deserialize)] pub struct ChannelPinsUpdateEvent { pub channel_id: ChannelId, - pub last_pin_timestamp: Option, + pub last_pin_timestamp: Option>, } #[derive(Clone, Debug, Deserialize)] @@ -278,8 +279,8 @@ pub struct MessageUpdateEvent { pub nonce: Option, pub tts: Option, pub pinned: Option, - pub timestamp: Option, - pub edited_timestamp: Option, + pub timestamp: Option>, + pub edited_timestamp: Option>, pub author: Option, pub mention_everyone: Option, pub mentions: Option>, diff --git a/src/model/guild/member.rs b/src/model/guild/member.rs index 99bf67bc9e3..008264313ca 100644 --- a/src/model/guild/member.rs +++ b/src/model/guild/member.rs @@ -1,3 +1,4 @@ +use chrono::{DateTime, FixedOffset}; use std::fmt::{Display, Formatter, Result as FmtResult}; use super::deserialize_sync_user; use ::model::*; @@ -23,7 +24,7 @@ pub struct Member { /// The unique Id of the guild that the member is a part of. pub guild_id: Option, /// Timestamp representing the date when the member joined. - pub joined_at: String, + pub joined_at: Option>, /// Indicator of whether the member can speak in voice channels. pub mute: bool, /// The member's nickname, if present. @@ -326,7 +327,7 @@ impl Member { .unwrap() .members .values() - .any(|m| m.user.read().unwrap().id == self.user.read().unwrap().id && m.joined_at == *self.joined_at)) + .any(|m| m.user.read().unwrap().id == self.user.read().unwrap().id && m.joined_at == self.joined_at)) .map(|guild| guild .read() .unwrap() diff --git a/src/model/guild/mod.rs b/src/model/guild/mod.rs index 24e1881ebbc..a744b2c61c9 100644 --- a/src/model/guild/mod.rs +++ b/src/model/guild/mod.rs @@ -14,6 +14,7 @@ pub use self::member::*; pub use self::partial_guild::*; pub use self::role::*; +use chrono::{DateTime, FixedOffset}; use serde::de::Error as DeError; use serde_json; use super::utils::*; @@ -73,7 +74,7 @@ pub struct Guild { /// that of the default channel (typically `#general`). pub id: GuildId, /// The date that the current user joined the guild. - pub joined_at: String, + pub joined_at: DateTime, /// Indicator of whether the guild is considered "large" by Discord. pub large: bool, /// The number of members in the guild. @@ -1149,7 +1150,7 @@ impl<'de> Deserialize<'de> for Guild { .map_err(DeError::custom)?; let joined_at = map.remove("joined_at") .ok_or_else(|| DeError::custom("expected guild joined_at")) - .and_then(String::deserialize) + .and_then(DateTime::deserialize) .map_err(DeError::custom)?; let large = map.remove("large") .ok_or_else(|| DeError::custom("expected guild large")) diff --git a/src/model/invite.rs b/src/model/invite.rs index 7b67296f8b8..7ff3fd1e123 100644 --- a/src/model/invite.rs +++ b/src/model/invite.rs @@ -1,3 +1,4 @@ +use chrono::{DateTime, FixedOffset}; use super::*; #[cfg(feature="cache")] @@ -228,7 +229,7 @@ pub struct RichInvite { /// The unique code for the invite. pub code: String, /// When the invite was created. - pub created_at: String, + pub created_at: DateTime, /// A representation of the minimal amount of information needed about the /// guild being invited to. pub guild: InviteGuild, @@ -302,7 +303,7 @@ impl RichInvite { /// # name: "foo".to_owned(), /// # kind: ChannelType::Text, /// # }, - /// # created_at: "bar".to_owned(), + /// # created_at: "2017-01-29T15:35:17.136000+00:00".parse().unwrap(), /// # guild: InviteGuild { /// # id: GuildId(2), /// # icon: None, diff --git a/src/model/mod.rs b/src/model/mod.rs index 26c6f42a421..bc414c7bccf 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -40,12 +40,12 @@ pub use self::user::*; pub use self::voice::*; pub use self::webhook::*; +use chrono::NaiveDateTime; use self::utils::*; use serde::de::Visitor; use std::collections::HashMap; use std::fmt::{Formatter, Result as FmtResult}; use std::sync::{Arc, RwLock}; -use time::Timespec; use ::internal::prelude::*; #[cfg(feature="utils")] @@ -63,10 +63,10 @@ macro_rules! id { impl $name { /// Retrieves the time that the Id was created at. - pub fn created_at(&self) -> Timespec { + pub fn created_at(&self) -> NaiveDateTime { let offset = (self.0 >> 22) / 1000; - Timespec::new(1420070400 + offset as i64, 0) + NaiveDateTime::from_timestamp(1420070400 + offset as i64, 0) } } diff --git a/src/model/user.rs b/src/model/user.rs index e1483d207b0..ef26ca11ba5 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -5,14 +5,14 @@ use super::*; use ::internal::prelude::*; use ::model::misc::Mentionable; +#[cfg(feature="model")] +use chrono::NaiveDateTime; #[cfg(feature="model")] use std::fmt::Write; #[cfg(feature="model")] use std::mem; #[cfg(feature="cache")] use std::sync::{Arc, RwLock}; -#[cfg(feature="model")] -use time::Timespec; #[cfg(feature="cache")] use ::CACHE; #[cfg(feature="model")] @@ -377,7 +377,7 @@ impl User { /// Retrieves the time that this user was created at. #[inline] - pub fn created_at(&self) -> Timespec { + pub fn created_at(&self) -> NaiveDateTime { self.id.created_at() } diff --git a/tests/test_decode_role.rs b/tests/test_decode_role.rs index 0470fd399e1..eea238faa6c 100644 --- a/tests/test_decode_role.rs +++ b/tests/test_decode_role.rs @@ -142,7 +142,7 @@ fn decode_guild_with_n1_role_position() { ], "nick": "asdasdadas", "mute": false, - "joined_at": "fake", + "joined_at": "2017-01-29T15:35:17.136000+00:00", "deaf": false }, { @@ -156,7 +156,7 @@ fn decode_guild_with_n1_role_position() { "2342432423432" ], "mute": false, - "joined_at": "fake", + "joined_at": "2017-01-29T15:35:17.136000+00:00", "deaf": false }, { @@ -171,7 +171,7 @@ fn decode_guild_with_n1_role_position() { "34534543543" ], "mute": false, - "joined_at": "fake", + "joined_at": "2017-01-29T15:35:17.136000+00:00", "deaf": false }, { @@ -185,7 +185,7 @@ fn decode_guild_with_n1_role_position() { "56465464" ], "mute": false, - "joined_at": "fake", + "joined_at": "2017-01-29T15:35:17.136000+00:00", "deaf": false }, { @@ -201,7 +201,7 @@ fn decode_guild_with_n1_role_position() { ], "nick": null, "mute": false, - "joined_at": "fake", + "joined_at": "2017-01-29T15:35:17.136000+00:00", "deaf": false }, { @@ -217,13 +217,13 @@ fn decode_guild_with_n1_role_position() { ], "nick": null, "mute": false, - "joined_at": "fake", + "joined_at": "2017-01-29T15:35:17.136000+00:00", "deaf": false } ], "member_count": 6, "large": false, - "joined_at": "fake", + "joined_at": "2017-01-29T15:35:17.136000+00:00", "id": "12321321312321", "icon": "fake icon", "features": [], diff --git a/tests/test_formatters.rs b/tests/test_formatters.rs index fa3683235c0..35e81fde311 100644 --- a/tests/test_formatters.rs +++ b/tests/test_formatters.rs @@ -55,7 +55,7 @@ fn test_mention() { let member = Member { deaf: false, guild_id: Some(GuildId(2)), - joined_at: "fake".to_owned(), + joined_at: None, mute: false, nick: None, roles: vec![],