1 /**
2 * Proleptic Gregorian calendar: time
3 *
4 * Copyright: Maxim Freck, 2016–2017.
5 * Authors: Maxim Freck <maxim@freck.pp.ru>
6 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7 */
8 module pgc.time;
9
10 public import pgc.exception;
11
12 alias Time = uint;
13
14 /***********************************
15 * Returns: Time uint for a given time value (hour, minute, second and split)
16 *
17 * Params:
18 * hour = the number of the hour
19 * minute = the number of the minute
20 * second = the number of the second
21 * split = the number of the split (1/32767 of a second)
22 */
23 pure Time mkTime(int hour, int minute, int second, int split = 0) @safe
24 {
25 assertTime(hour, minute, second, split);
26 return (((hour & 0x1F) << 27) | ((minute & 0x3F) << 21) | ((second & 0x3F) << 15) | (split & 0x3FFF));
27 }
28
29 /***********************************
30 * Checks the validity of a time
31 *
32 * Params:
33 * hour = the number of the hour
34 * month = the number of the month
35 * year = the number of the year
36 */
37 pure private void assertTime(int hour, int minute, int second, int split = 0) @safe
38 {
39 import std.conv: to;
40 if (hour < 0 || hour > 23) throw new PgcException("Invalid hour value: "~to!string(hour));
41 if (minute < 0 || minute > 59) throw new PgcException("Invalid minute value: "~to!string(minute));
42 if (second < 0 || second > 59) throw new PgcException("Invalid second value: "~to!string(second));
43 if (split < 0 || split > 32_768) throw new PgcException("Split "~to!string(split)~" is out of bound [0..32768]");
44 }
45
46 /***********************************
47 * Returns: the hour of a given time
48 *
49 * Params:
50 * t = time
51 */
52 pure nothrow ubyte hour(Time t) @safe @nogc
53 {
54 return cast(ubyte)((t >> 27) & 0x1F);
55 }
56
57 /***********************************
58 * Returns: the minute of a given time
59 *
60 * Params:
61 * t = time
62 */
63 pure nothrow ubyte minute(Time t) @safe @nogc
64 {
65 return cast(ubyte)((t >> 21) & 0x3F);
66 }
67
68 /***********************************
69 * Returns: the second of a given time
70 *
71 * Params:
72 * t = time
73 */
74 pure nothrow ubyte second(Time t) @safe @nogc
75 {
76 return cast(ubyte)((t >> 15) & 0x3F);
77 }
78
79 /***********************************
80 * Returns: the split (1/32767) of a given time
81 *
82 * Params:
83 * t = time
84 */
85 pure nothrow ushort split(Time t) @safe @nogc
86 {
87 return cast(ushort)(t & 0x7FFF);
88 }
89
90 version(Posix) {
91 import core.sys.posix.sys.time: gettimeofday, gmtime, localtime, timeval;
92
93 /***********************************
94 * Returns: the current time in UTC
95 */
96 Time nowUTC()
97 {
98 timeval time;
99 gettimeofday(&time, null);
100 auto tm = gmtime(&time.tv_sec);
101
102 return mkTime(tm.tm_hour, tm.tm_min, tm.tm_sec, cast(int)(time.tv_usec/31));
103 }
104
105 /***********************************
106 * Returns: the current local time
107 */
108 Time nowLocal()
109 {
110 timeval time;
111 gettimeofday(&time, null);
112 auto tm = localtime(&time.tv_sec);
113
114 return mkTime(tm.tm_hour, tm.tm_min, tm.tm_sec, cast(int)(time.tv_usec/31));
115 }
116 }
117
118 version(Windows) {
119 import core.sys.windows.windows: GetLocalTime, GetSystemTime, SYSTEMTIME;
120
121 /***********************************
122 * Returns: the current time in UTC
123 */
124 Time nowUTC()
125 {
126 SYSTEMTIME time;
127 GetSystemTime(&time);
128 return mkTime(time.wHour, time.wMinute, time.wSecond, time.wMilliseconds*16);
129 }
130
131 /***********************************
132 * Returns: the current local time
133 */
134 Time nowLocal()
135 {
136 SYSTEMTIME time;
137 GetLocalTime(&time);
138 return mkTime(time.wHour, time.wMinute, time.wSecond, time.wMilliseconds*16);
139 }
140 }