1 /// Provides a wrapper around a `mg_date_time`.
2 module memgraph.date_time;
3 
4 import memgraph.mgclient, memgraph.detail, memgraph.value, memgraph.enums;
5 
6 /// Represents date and time with its time zone.
7 ///
8 /// Date is defined with seconds since the adjusted Unix epoch.
9 /// Time is defined with nanoseconds since midnight.
10 /// Time zone is defined with minutes from UTC.
11 struct DateTime {
12 
13 	/// Create a copy of `other` date time.
14 	this(inout ref DateTime other) {
15 		this(mg_date_time_copy(other.ptr));
16 	}
17 
18 	/// Create a date time from a Value.
19 	this(inout ref Value value) {
20 		assert(value.type == Type.DateTime);
21 		this(mg_date_time_copy(mg_value_date_time(value.ptr)));
22 	}
23 
24 	/// Assigns a date time to another. The target of the assignment gets detached from
25 	/// whatever date time it was attached to, and attaches itself to the new date time.
26 	ref DateTime opAssign(DateTime rhs) @safe return {
27 		import std.algorithm.mutation : swap;
28 		swap(this, rhs);
29 		return this;
30 	}
31 
32 	/// Return a printable string representation of this date time.
33 	const (string) toString() const {
34 		import std.conv : to;
35 		return to!string(seconds) ~ " " ~ to!string(nanoseconds) ~ " " ~ to!string(tz_offset_minutes);
36 	}
37 
38 	/// Compares this date time with `other`.
39 	/// Return: true if same, false otherwise.
40 	bool opEquals(const ref DateTime other) const {
41 		return Detail.areDateTimesEqual(ptr_, other.ptr);
42 	}
43 
44 	/// Returns seconds since Unix epoch.
45 	const (long) seconds() const { return mg_date_time_seconds(ptr_); }
46 
47 	/// Returns nanoseconds since midnight.
48 	const (long) nanoseconds() const { return mg_date_time_nanoseconds(ptr_); }
49 
50 	/// Returns time zone offset in minutes from UTC.
51 	const (long) tz_offset_minutes() const { return mg_date_time_tz_offset_minutes(ptr_); }
52 
53 	/// Create a copy of the internal `mg_date_time`.
54 	this(this) {
55 		if (ptr_)
56 			ptr_ = mg_date_time_copy(ptr_);
57 	}
58 
59 	/// Destroys the internal `mg_date_time`.
60 	@safe @nogc ~this() {
61 		if (ptr_)
62 			mg_date_time_destroy(ptr_);
63 	}
64 
65 package:
66 	/// Create a DateTime using the given `mg_date_time`.
67 	this(mg_date_time *ptr) @trusted {
68 		assert(ptr != null);
69 		ptr_ = ptr;
70 	}
71 
72 	/// Create a DateTime from a copy of the given `mg_date_time`.
73 	this(const mg_date_time *ptr) {
74 		assert(ptr != null);
75 		this(mg_date_time_copy(ptr));
76 	}
77 
78 	/// Returns the internal `mg_date_time` pointer.
79 	const (mg_date_time *) ptr() const { return ptr_; }
80 
81 private:
82 	mg_date_time *ptr_;
83 }
84 
85 unittest {
86 	import std.conv : to;
87 	import memgraph.enums;
88 
89 	auto tm = mg_date_time_alloc(&mg_system_allocator);
90 	assert(tm != null);
91 	tm.seconds = 23;
92 	tm.nanoseconds = 42;
93 	tm.tz_offset_minutes = 60;
94 
95 	auto t = DateTime(tm);
96 	assert(t.seconds == 23);
97 	assert(t.nanoseconds == 42);
98 	assert(t.tz_offset_minutes == 60);
99 
100 	const t1 = t;
101 	assert(t1 == t);
102 
103 	assert(to!string(t) == "23 42 60");
104 
105 	auto t2 = DateTime(mg_date_time_copy(t.ptr));
106 	assert(t2 == t);
107 
108 	const t3 = DateTime(t2);
109 	assert(t3 == t);
110 
111 	const v = Value(t);
112 	const t4 = DateTime(v);
113 	assert(t4 == t);
114 	assert(v == t);
115 	assert(to!string(v) == to!string(t));
116 
117 	t2 = t;
118 	assert(t2 == t);
119 
120 	const v1 = Value(t2);
121 	assert(v1.type == Type.DateTime);
122 	const v2 = Value(t2);
123 	assert(v2.type == Type.DateTime);
124 
125 	assert(v1 == v2);
126 
127 	const t5 = DateTime(t3);
128 	assert(t5 == t3);
129 }