1 ///
2 module dpq.serialisers.systime;
3 
4 import std.datetime : SysTime, DateTime;
5 import std.typecons : Nullable;
6 import std.bitmanip;
7 import core.time;
8 import dpq.meta;
9 import dpq.serialisation;
10 import dpq.connection : Connection;
11 import libpq.libpq : Oid;
12 import dpq.value : Type;
13 
14 enum POSTGRES_EPOCH = DateTime(2000, 1, 1);
15 
16 struct SysTimeSerialiser
17 {
18    static bool isSupportedType(T)()
19    {
20       return is(T == SysTime);
21    }
22 
23    static Nullable!(ubyte[]) serialise(T)(T val)
24    {
25       import std.datetime.timezone : UTC;
26 
27       static assert(isSupportedType!T, "'%s' is not supported by SysTimeSerialiser".format(T.stringof));
28 
29       alias RT = Nullable!(ubyte[]);
30 
31       if (isAnyNull(val))
32       {
33          return RT.init;
34       }
35       // stdTime is in hnsecs, psql wants microsecs
36       long diff = val.stdTime - SysTime(POSTGRES_EPOCH, UTC()).stdTime;
37       return RT(nativeToBigEndian(diff / 10).dup);
38    }
39 
40    static T deserialise(T)(const(ubyte)[] bytes)
41    {
42       static assert(isSupportedType!T, "'%s' is not supported by SysTimeSerialiser".format(T.stringof));
43 
44       import std.datetime.timezone : UTC;
45 
46       return SysTime(fromBytes!long(bytes, long.sizeof) * 10 + SysTime(POSTGRES_EPOCH, UTC()).stdTime);
47    }
48 
49    static Oid oidForType(T)()
50    {
51       return Type.TIMESTAMP;
52    }
53 
54    static string nameForType(T)()
55    {
56       return "TIMESTAMP";
57    }
58 
59    static void ensureExistence(T)(Connection c)
60    {
61       return;
62    }
63 }
64 
65 unittest
66 {
67    import std.stdio;
68    import std.datetime;
69 
70    writeln(" * SysTimeSerialiser");
71 
72    // In reality, we should probably only check up to msec accuracy,
73    // and I'm not sure how much SysTimes == checks.
74    SysTime time = Clock.currTime;
75    auto serialised = SysTimeSerialiser.serialise(time);
76 
77    assert(SysTimeSerialiser.deserialise!SysTime(serialised.get).toUnixTime == time.toUnixTime);
78 }