1 /* This file is part of the Amalthea library.
2  *
3  * Copyright (C) 2021, 2024 Eugene 'Vindex' Stulin
4  *
5  * Distributed under the Boost Software License 1.0 or (at your option)
6  * the GNU Lesser General Public License 3.0 or later.
7  */
8 
9 module amalthea.time;
10 
11 import core.stdc.time;
12 import core.sys.posix.signal : timespec;
13 import core.thread : Thread;
14 
15 public import amalthea.libcore;
16 import amalthea.sys : SysException;
17 
18 import
19     std.datetime,
20     std.datetime.systime,
21     std.string;
22 
23 
24 /*******************************************************************************
25  * The function returns number of seconds since 1970-01-01.
26  * Params:
27  *     timeString = String with the format 'YYYY-MM-DD hh:mm:ss'
28  *                  or 'YYYY-MM-DDThh:mm:ss'.
29  *                  If the string is empty, the function returns current time.
30  *                  By default, empty.
31  */
32 long unixTime(string timeString = "") {
33     if (timeString.empty) {
34         return core.stdc.time.time(null);
35     }
36     timeString = timeString.replace(" ", "T");
37     return SysTime(DateTime.fromISOExtString(timeString)).toUnixTime();
38 }
39 
40 
41 /*******************************************************************************
42  * Gets a time string from the std.datetime.systime.SysTime object.
43  * Returns: String with format "YYYY-MM-DD HH:MM:SS".
44  */
45 string getTimeString(SysTime sysTime) {
46     return sysTime.toISOExtString().replace("T"," ").split('.')[0];
47 }
48 
49 
50 /*******************************************************************************
51  * Gets a time string with the current time.
52  * Returns: String with format "YYYY-MM-DD HH:MM:SS".
53  */
54 string getTimeString() {
55     return getTimeString(Clock.currTime);
56 }
57 
58 
59 /*******************************************************************************
60  * Gets a time string by UNIX time (number of seconds).
61  * Returns: String with format "YYYY-MM-DD HH:MM:SS".
62  */
63 string getTimeString(long secondsByUnixTime) {
64     return getTimeString(SysTime.fromUnixTime(secondsByUnixTime));
65 }
66 
67 
68 /*******************************************************************************
69  * Gets a time string by timestamp (only seconds from timestamp is used).
70  * Returns: String with format "YYYY-MM-DD HH:MM:SS".
71  */
72 string getTimeString(timestamp_t t) {
73     return getTimeString(SysTime.fromUnixTime(t.tv_sec));
74 }
75 
76 
77 /*******************************************************************************
78  * Gets a time string by timestamp content with nanoseconds.
79  * Returns: String with format "YYYY-MM-DD HH:MM:SS.NNNNNNNNN".
80  */
81 string getTimeExtString(timestamp_t t) {
82     string part1 = getTimeString(SysTime.fromUnixTime(t.tv_sec));
83     string nsecs = format!"%09d"(t.tv_nsec);
84     return part1 ~ "." ~ nsecs;
85 }
86 
87 
88 /*******************************************************************************
89  * Gets a string containing the current time with nanoseconds.
90  * Returns: String with format "YYYY-MM-DD HH:MM:SS.NNNNNNNNN".
91  */
92 string getTimeExtString() {
93     return getTimeExtString(getCurrentTimestamp());
94 }
95 
96 
97 /*******************************************************************************
98  * UNIX timestamp structure.
99  * Corresponds to C structure types 'statx_timestamp' and 'timespec'.
100  */
101 extern(C)
102 struct timestamp_t {
103     /// Seconds since the Epoch (UNIX time).
104     long tv_sec;
105     /// Nanoseconds since tv_sec.
106     uint tv_nsec;
107 }
108 
109 
110 extern(C) private int clock_gettime(int __clock_id, timespec *__tp);
111 
112 
113 /*******************************************************************************
114  * Current time as timestamp_t.
115  */
116 timestamp_t getCurrentTimestamp() {
117     timespec t;
118     enum CLOCK_REALTIME = 0;
119     int ret = clock_gettime(CLOCK_REALTIME, &t);
120     enforce(ret != 1, new SysException("clock_gettime"));
121     timestamp_t ts = { cast(long)t.tv_sec, cast(uint)t.tv_nsec };
122     return ts;
123 }
124 
125 
126 /*******************************************************************************
127  * Transforms UNIX timestamp structure to std.datetime.systime.SysTime.
128  * SysTime stores hectonanoseconds, so some of the timestamp info is lost.
129  */
130 SysTime convTimestampToSysTime(timestamp_t t) {
131     ulong hnsecs = t.tv_sec * 10_000_000 + t.tv_nsec / 100;
132     return SysTime(621_355_968_000_000_000L + hnsecs);
133 }
134 
135 
136 /*******************************************************************************
137  * Returns string with timezone offset (hours and minutes) like +0300 or -0700.
138  */
139 string getTZOffsetAsString() {
140     Duration d = LocalTime().utcOffsetAt(Clock.currTime().stdTime);
141     int hours, minutes;
142     abs(d).split!("hours", "minutes")(hours, minutes);
143     auto offsetFmt = d < Duration.zero ? "-%02d%02d" : "+%02d%02d";
144     return format(offsetFmt, hours, minutes);
145 }
146 
147 
148 /*******************************************************************************
149  * The function makes a delay, expressed in seconds.
150  */
151 void sleep(double seconds) {
152     ulong microseconds = (seconds <= 0) ? 0 : to!ulong(seconds * (10^^6));
153     Thread.sleep(dur!("usecs")(microseconds));
154 }
155 
156 
157 /*******************************************************************************
158  * The function makes a delay, expressed in milliseconds.
159  */
160 void msleep(ulong milliseconds) {
161     Thread.sleep(dur!("msecs")(milliseconds));
162 }
163 
164 
165 /*******************************************************************************
166  * The function makes a delay, expressed in microseconds.
167  */
168 void usleep(ulong microseconds) {
169     Thread.sleep(dur!("usecs")(microseconds));
170 }
171