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 static assert ( 26 isSupportedType!T, 27 "'%s' is not supported by SysTimeSerialiser".format(T.stringof)); 28 29 alias RT = Nullable!(ubyte[]); 30 31 if (isAnyNull(val)) 32 return RT.init; 33 34 // stdTime is in hnsecs, psql wants microsecs 35 long diff = val.stdTime - SysTime(POSTGRES_EPOCH).stdTime; 36 return RT(nativeToBigEndian(diff / 10).dup); 37 } 38 39 static T deserialise(T)(const (ubyte)[] bytes) 40 { 41 static assert ( 42 isSupportedType!T, 43 "'%s' is not supported by SysTimeSerialiser".format(T.stringof)); 44 45 return SysTime(fromBytes!long(bytes, long.sizeof) * 10 + SysTime(POSTGRES_EPOCH).stdTime); 46 } 47 48 static Oid oidForType(T)() 49 { 50 return Type.TIMESTAMP; 51 } 52 53 static string nameForType(T)() 54 { 55 return "TIMESTAMP"; 56 } 57 58 static void ensureExistence(T)(Connection c) 59 { 60 return; 61 } 62 } 63 64 unittest 65 { 66 import std.stdio; 67 import std.datetime; 68 69 writeln(" * SysTimeSerialiser"); 70 71 // In reality, we should probably only check up to msec accuracy, 72 // and I'm not sure how much SysTimes == checks. 73 SysTime time = Clock.currTime; 74 auto serialised = SysTimeSerialiser.serialise(time); 75 76 assert(SysTimeSerialiser.deserialise!SysTime(serialised).toUnixTime == time.toUnixTime); 77 }