1 /// Provides a wrapper for a `mg_date`. Uses `std.datetime.date.Date` internally. 2 module memgraph.date; 3 4 import memgraph.mgclient, memgraph.detail, memgraph.value, memgraph.enums; 5 import sd = std.datetime.date; 6 import ct = core.time; 7 8 /// Represents a date. 9 /// Date is defined with number of days since the Unix epoch. 10 /// Uses a `std.datetime.date.Date` internally. 11 struct Date { 12 /// Create a shallow copy of `other` Date. 13 @nogc this(inout ref Date other) { 14 this(other.ptr_); 15 } 16 17 /// Create a date from a Value. 18 @nogc this(inout ref Value value) { 19 assert(value.type == Type.Date); 20 this(mg_value_date(value.ptr)); 21 } 22 23 /// Compares this date with `other`. 24 /// Return: true if same, false otherwise. 25 @nogc auto opEquals(const ref Date other) const { 26 return Detail.areDatesEqual(ptr_, other.ptr_); 27 } 28 29 /// Return the hash code for this date. 30 size_t toHash() const nothrow @safe { 31 return cast(ulong)ptr_; 32 } 33 34 /// Return a printable string representation of this date. 35 string toString() const { return date_.toString; } 36 37 /// Returns days since Unix epoch. 38 @nogc auto days() const { return (date_ - epoch_).total!"days"; } 39 40 package: 41 /// Create a Date using the given `mg_date` pointer. 42 @nogc this(const mg_date *ptr) { 43 assert(ptr != null); 44 ptr_ = ptr; 45 date_ = epoch_ + ct.days(mg_date_days(ptr)); 46 } 47 48 /// Return pointer to internal `mg_date`. 49 @nogc auto ptr() inout { 50 return ptr_; 51 } 52 53 private: 54 const mg_date *ptr_; 55 sd.Date date_; 56 alias date_ this; 57 } // struct Date 58 59 static private sd.Date epoch_ = sd.Date(1970, 1, 1); 60 61 unittest { 62 import testutils : connectContainer; 63 import std.algorithm : count; 64 import std.conv : to; 65 66 auto client = connectContainer(); 67 assert(client); 68 69 auto result = client.execute(`return date('2021-02-12') as a, date('2022-11-12') as b, date('2038-01-20') as c;`); 70 assert(result, client.error); 71 foreach (r; result) { 72 assert(r.length == 3); 73 74 assert(r[0].type() == Type.Date); 75 const d1 = to!Date(r[0]); 76 assert(d1.days == 18_670, to!string(d1.days)); 77 assert(d1.toISOExtString == "2021-02-12"); 78 assert(d1.toISOString == "20210212"); 79 assert(d1.toString == "2021-Feb-12"); 80 const sd.Date D1 = d1; 81 assert(D1.toISOExtString == "2021-02-12"); 82 assert(D1.toISOString == "20210212"); 83 assert(D1.toString == "2021-Feb-12"); 84 85 assert(r[1].type() == Type.Date); 86 const d2 = to!Date(r[1]); 87 assert(d2.days == 19_308, to!string(d2.days)); 88 assert(d2.toISOExtString == "2022-11-12"); 89 assert(d2.toISOString == "20221112"); 90 assert(d2.toString == "2022-Nov-12"); 91 const sd.Date D2 = d2; 92 assert(D2.toISOExtString == "2022-11-12"); 93 assert(D2.toISOString == "20221112"); 94 assert(D2.toString == "2022-Nov-12"); 95 96 assert(r[2].type() == Type.Date); 97 const d3 = to!Date(r[2]); 98 assert(d3.days == 24_856, to!string(d3.days)); 99 assert(d3.toISOExtString == "2038-01-20"); 100 assert(d3.toISOString == "20380120"); 101 assert(d3.toString == "2038-Jan-20"); 102 const sd.Date D3 = d3; 103 assert(D3.toISOExtString == "2038-01-20"); 104 assert(D3.toISOString == "20380120"); 105 assert(D3.toString == "2038-Jan-20"); 106 } 107 } 108 109 unittest { 110 import memgraph.enums : Type; 111 import std.conv : to; 112 113 auto dt = mg_date_make(42); 114 assert(dt != null); 115 116 auto d = Date(dt); 117 assert(d.days == 42); 118 119 const d1 = d; 120 assert(d1 == d); 121 122 assert(to!string(d) == "1970-Feb-12", to!string(d)); 123 124 auto d2 = Date(mg_date_copy(d.ptr)); 125 assert(d2 == d); 126 127 const d3 = Date(d2); 128 assert(d3 == d); 129 130 const d5 = Date(d3); 131 assert(d5 == d3); 132 133 auto v = Value(mg_value_make_date(dt)); 134 assert(to!string(v) == "1970-Feb-12", to!string(v)); 135 136 assert(cast(ulong)d.ptr == d.toHash); 137 }