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 }