1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
extern crate redis;
extern crate postgres;
extern crate chrono;
extern crate rustc_serialize;
extern crate bincode;

use chrono::*;
use std::io::prelude::*;
use rustc_serialize::*;
use postgres::types::{Type, FromSql, ToSql, IsNull, SessionInfo};
use redis::{RedisResult, ToRedisArgs, FromRedisValue, RedisError, Value};
use std::io::{Error, ErrorKind};
use bincode::SizeLimit;
use bincode::rustc_serialize::{encode, decode};
use std::ops::Deref;

const FORMAT: &'static str = "%Y-%m-%d %H:%M:%S";
#[derive(Debug,Copy,Clone, PartialEq,Eq)]
pub struct Time {
    value: DateTime<Local>,
}

// to explore all the chrono functions
impl Deref for Time {
    type Target = DateTime<Local>;
    fn deref(&self) -> &DateTime<Local> {
        &self.value
    }
}

impl Encodable for Time {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        self.value.format(FORMAT).to_string().encode(s)
    }
}

impl Decodable for Time {
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
        match String::decode(d) {
            Ok(value) => {
                match Local.datetime_from_str(&value, FORMAT) {
                    Ok(value) => Ok(Time { value: value }),
                    Err(_) => panic!("error decode datetime"),
                }
            }
            Err(_) => panic!("error decode datetime"),
        }
    }
}

impl Time {
    pub fn new() -> Self {
        Time { value: Local::now() }
    }
}

impl FromSql for Time {
    fn from_sql<R: Read>(ty: &Type, raw: &mut R, ctx: &SessionInfo) -> postgres::Result<Time> {
        DateTime::from_sql(ty, raw, ctx).map(|value| Time { value: value })
    }
    fn accepts(_: &Type) -> bool {
        true
    }
}

impl ToSql for Time {
    fn to_sql<W: Write + ?Sized>(&self,
                                 ty: &Type,
                                 mut w: &mut W,
                                 ctx: &SessionInfo)
                                 -> postgres::Result<IsNull> {
        self.value.to_sql(ty, w, ctx)
    }
    fn accepts(_: &Type) -> bool {
        true
    }
    fn to_sql_checked(&self,
                      ty: &Type,
                      out: &mut Write,
                      ctx: &SessionInfo)
                      -> postgres::Result<IsNull> {
        self.value.to_sql_checked(ty, out, ctx)
    }
}
impl ToRedisArgs for Time {
    fn to_redis_args(&self) -> Vec<Vec<u8>> {
        vec![encode(&self.value, SizeLimit::Infinite).unwrap()]
    }
}

impl FromRedisValue for Time {
    fn from_redis_value(v: &Value) -> RedisResult<Self> {
        if let Value::Data(ref items) = *v {
            let decoded: DateTime<Local> = decode(&items[..]).unwrap();
            return Ok(Time { value: decoded });
        }
        Err(RedisError::from(Error::new(ErrorKind::Other, "oh no!")))
    }
}