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 deep 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 	this(this) {
54 		if (ptr_)
55 			ptr_ = mg_date_time_copy(ptr_);
56 	}
57 
58 	@safe @nogc ~this() {
59 		if (ptr_)
60 			mg_date_time_destroy(ptr_);
61 	}
62 
63 package:
64 	/// Create a DateTime using the given `mg_date_time`.
65 	this(mg_date_time *ptr) @trusted {
66 		assert(ptr != null);
67 		ptr_ = ptr;
68 	}
69 
70 	/// Create a DateTime from a copy of the given `mg_date_time`.
71 	this(const mg_date_time *ptr) {
72 		assert(ptr != null);
73 		this(mg_date_time_copy(ptr));
74 	}
75 
76 	const (mg_date_time *) ptr() const { return ptr_; }
77 
78 private:
79 	mg_date_time *ptr_;
80 }
81 
82 unittest {
83 	import std.conv : to;
84 	import memgraph.enums;
85 
86 	auto tm = mg_date_time_alloc(&mg_system_allocator);
87 	assert(tm != null);
88 	tm.seconds = 23;
89 	tm.nanoseconds = 42;
90 	tm.tz_offset_minutes = 60;
91 
92 	auto t = DateTime(tm);
93 	assert(t.seconds == 23);
94 	assert(t.nanoseconds == 42);
95 	assert(t.tz_offset_minutes == 60);
96 
97 	const t1 = t;
98 	assert(t1 == t);
99 
100 	assert(to!string(t) == "23 42 60");
101 
102 	auto t2 = DateTime(mg_date_time_copy(t.ptr));
103 	assert(t2 == t);
104 
105 	const t3 = DateTime(t2);
106 	assert(t3 == t);
107 
108 	const v = Value(t);
109 	const t4 = DateTime(v);
110 	assert(t4 == t);
111 	assert(v == t);
112 	assert(to!string(v) == to!string(t));
113 
114 	t2 = t;
115 	assert(t2 == t);
116 
117 	const v1 = Value(t2);
118 	assert(v1.type == Type.DateTime);
119 	const v2 = Value(t2);
120 	assert(v2.type == Type.DateTime);
121 
122 	assert(v1 == v2);
123 
124 	const t5 = DateTime(t3);
125 	assert(t5 == t3);
126 }