132
|
1 /*******************************************************************************
|
|
2
|
|
3 copyright: Copyright (c) 2007 Kris Bell. All rights reserved
|
|
4
|
|
5 license: BSD style: $(LICENSE)
|
|
6
|
|
7 version: Feb 2007: Initial release
|
|
8
|
|
9 author: Kris
|
|
10
|
|
11 *******************************************************************************/
|
|
12
|
|
13 module tango.time.Clock;
|
|
14
|
|
15 public import tango.time.Time;
|
|
16
|
|
17 private import tango.sys.Common;
|
|
18
|
|
19 private import tango.core.Exception;
|
|
20
|
|
21 /******************************************************************************
|
|
22
|
|
23 Exposes UTC time relative to Jan 1st, 1 AD. These values are
|
|
24 based upon a clock-tick of 100ns, giving them a span of greater
|
|
25 than 10,000 years. These units of time are the foundation of most
|
|
26 time and date functionality in Tango.
|
|
27
|
|
28 Interval is another type of time period, used for measuring a
|
|
29 much shorter duration; typically used for timeout periods and
|
|
30 for high-resolution timers. These intervals are measured in
|
|
31 units of 1 second, and support fractional units (0.001 = 1ms).
|
|
32
|
|
33 *******************************************************************************/
|
|
34
|
|
35 struct Clock
|
|
36 {
|
|
37 version (Win32)
|
|
38 {
|
|
39 /***************************************************************
|
|
40
|
|
41 Return the current time as UTC since the epoch
|
|
42
|
|
43 ***************************************************************/
|
|
44
|
|
45 static Time now ()
|
|
46 {
|
|
47 FILETIME fTime = void;
|
|
48 GetSystemTimeAsFileTime (&fTime);
|
|
49 return convert (fTime);
|
|
50 }
|
|
51
|
|
52 /***************************************************************
|
|
53
|
|
54 Set Date fields to represent the current time.
|
|
55
|
|
56 ***************************************************************/
|
|
57
|
|
58 static DateTime toDate ()
|
|
59 {
|
|
60 return toDate (now);
|
|
61 }
|
|
62
|
|
63 /***************************************************************
|
|
64
|
|
65 Set fields to represent the provided UTC time. Note
|
|
66 that the conversion is limited by the underlying OS,
|
|
67 and will fail to operate correctly with Time
|
|
68 values beyond the domain. On Win32 the earliest
|
|
69 representable date is 1601. On linux it is 1970. Both
|
|
70 systems have limitations upon future dates also. Date
|
|
71 is limited to millisecond accuracy at best.
|
|
72
|
|
73 ***************************************************************/
|
|
74
|
|
75 static DateTime toDate (Time time)
|
|
76 {
|
|
77 DateTime dt = void;
|
|
78 SYSTEMTIME sTime = void;
|
|
79
|
|
80 auto fTime = convert (time);
|
|
81 FileTimeToSystemTime (&fTime, &sTime);
|
|
82
|
|
83 dt.date.year = sTime.wYear;
|
|
84 dt.date.month = sTime.wMonth;
|
|
85 dt.date.day = sTime.wDay;
|
|
86 dt.date.dow = sTime.wDayOfWeek;
|
|
87 dt.date.doy = 0;
|
|
88 dt.date.era = 0;
|
|
89 dt.time.hours = sTime.wHour;
|
|
90 dt.time.minutes = sTime.wMinute;
|
|
91 dt.time.seconds = sTime.wSecond;
|
|
92 dt.time.millis = sTime.wMilliseconds;
|
|
93 return dt;
|
|
94 }
|
|
95
|
|
96 /***************************************************************
|
|
97
|
|
98 Convert Date fields to Time
|
|
99
|
|
100 Note that the conversion is limited by the underlying
|
|
101 OS, and will not operate correctly with Time
|
|
102 values beyond the domain. On Win32 the earliest
|
|
103 representable date is 1601. On linux it is 1970. Both
|
|
104 systems have limitations upon future dates also. Date
|
|
105 is limited to millisecond accuracy at best.
|
|
106
|
|
107 ***************************************************************/
|
|
108
|
|
109 static Time fromDate (inout DateTime dt)
|
|
110 {
|
|
111 SYSTEMTIME sTime = void;
|
|
112 FILETIME fTime = void;
|
|
113
|
|
114 sTime.wYear = cast(ushort) dt.date.year;
|
|
115 sTime.wMonth = cast(ushort) dt.date.month;
|
|
116 sTime.wDayOfWeek = 0;
|
|
117 sTime.wDay = cast(ushort) dt.date.day;
|
|
118 sTime.wHour = cast(ushort) dt.time.hours;
|
|
119 sTime.wMinute = cast(ushort) dt.time.minutes;
|
|
120 sTime.wSecond = cast(ushort) dt.time.seconds;
|
|
121 sTime.wMilliseconds = cast(ushort) dt.time.millis;
|
|
122
|
|
123 SystemTimeToFileTime (&sTime, &fTime);
|
|
124 return convert (fTime);
|
|
125 }
|
|
126
|
|
127 /***************************************************************
|
|
128
|
|
129 Convert FILETIME to a Time
|
|
130
|
|
131 ***************************************************************/
|
|
132
|
|
133 package static Time convert (FILETIME time)
|
|
134 {
|
|
135 auto t = *cast(long*) &time;
|
|
136 t *= 100 / TimeSpan.NanosecondsPerTick;
|
|
137 return Time.epoch1601 + TimeSpan(t);
|
|
138 }
|
|
139
|
|
140 /***************************************************************
|
|
141
|
|
142 Convert Time to a FILETIME
|
|
143
|
|
144 ***************************************************************/
|
|
145
|
|
146 package static FILETIME convert (Time dt)
|
|
147 {
|
|
148 FILETIME time = void;
|
|
149
|
|
150 TimeSpan span = dt - Time.epoch1601;
|
|
151 assert (span >= TimeSpan.zero);
|
|
152 *cast(long*) &time.dwLowDateTime = span.ticks;
|
|
153 return time;
|
|
154 }
|
|
155 }
|
|
156
|
|
157 version (Posix)
|
|
158 {
|
|
159 /***************************************************************
|
|
160
|
|
161 Return the current time as UTC since the epoch
|
|
162
|
|
163 ***************************************************************/
|
|
164
|
|
165 static Time now ()
|
|
166 {
|
|
167 timeval tv = void;
|
|
168 if (gettimeofday (&tv, null))
|
|
169 throw new PlatformException ("Clock.now :: Posix timer is not available");
|
|
170
|
|
171 return convert (tv);
|
|
172 }
|
|
173
|
|
174 /***************************************************************
|
|
175
|
|
176 Set Date fields to represent the current time.
|
|
177
|
|
178 ***************************************************************/
|
|
179
|
|
180 static DateTime toDate ()
|
|
181 {
|
|
182 return toDate (now);
|
|
183 }
|
|
184
|
|
185 /***************************************************************
|
|
186
|
|
187 Set fields to represent the provided UTC time. Note
|
|
188 that the conversion is limited by the underlying OS,
|
|
189 and will fail to operate correctly with Time
|
|
190 values beyond the domain. On Win32 the earliest
|
|
191 representable date is 1601. On linux it is 1970. Both
|
|
192 systems have limitations upon future dates also. Date
|
|
193 is limited to millisecond accuracy at best.
|
|
194
|
|
195 **************************************************************/
|
|
196
|
|
197 static DateTime toDate (Time time)
|
|
198 {
|
|
199 DateTime dt = void;
|
|
200 auto timeval = convert (time);
|
|
201 dt.time.millis = timeval.tv_usec / 1000;
|
|
202
|
|
203 tm t = void;
|
|
204 gmtime_r (&timeval.tv_sec, &t);
|
|
205
|
|
206 dt.date.year = t.tm_year + 1900;
|
|
207 dt.date.month = t.tm_mon + 1;
|
|
208 dt.date.day = t.tm_mday;
|
|
209 dt.date.dow = t.tm_wday;
|
|
210 dt.date.doy = 0;
|
|
211 dt.date.era = 0;
|
|
212 dt.time.hours = t.tm_hour;
|
|
213 dt.time.minutes = t.tm_min;
|
|
214 dt.time.seconds = t.tm_sec;
|
|
215 return dt;
|
|
216 }
|
|
217
|
|
218 /***************************************************************
|
|
219
|
|
220 Convert Date fields to Time
|
|
221
|
|
222 Note that the conversion is limited by the underlying
|
|
223 OS, and will not operate correctly with Time
|
|
224 values beyond the domain. On Win32 the earliest
|
|
225 representable date is 1601. On linux it is 1970. Both
|
|
226 systems have limitations upon future dates also. Date
|
|
227 is limited to millisecond accuracy at best.
|
|
228
|
|
229 ***************************************************************/
|
|
230
|
|
231 static Time fromDate (inout DateTime dt)
|
|
232 {
|
|
233 tm t = void;
|
|
234
|
|
235 t.tm_year = dt.date.year - 1900;
|
|
236 t.tm_mon = dt.date.month - 1;
|
|
237 t.tm_mday = dt.date.day;
|
|
238 t.tm_hour = dt.time.hours;
|
|
239 t.tm_min = dt.time.minutes;
|
|
240 t.tm_sec = dt.time.seconds;
|
|
241
|
|
242 auto seconds = timegm (&t);
|
|
243 return Time.epoch1970 +
|
|
244 TimeSpan.seconds(seconds) +
|
|
245 TimeSpan.millis(dt.time.millis);
|
|
246 }
|
|
247
|
|
248 /***************************************************************
|
|
249
|
|
250 Convert timeval to a Time
|
|
251
|
|
252 ***************************************************************/
|
|
253
|
|
254 package static Time convert (inout timeval tv)
|
|
255 {
|
|
256 return Time.epoch1970 +
|
|
257 TimeSpan.seconds(tv.tv_sec) +
|
|
258 TimeSpan.micros(tv.tv_usec);
|
|
259 }
|
|
260
|
|
261 /***************************************************************
|
|
262
|
|
263 Convert Time to a timeval
|
|
264
|
|
265 ***************************************************************/
|
|
266
|
|
267 package static timeval convert (Time time)
|
|
268 {
|
|
269 timeval tv = void;
|
|
270
|
|
271 TimeSpan span = time - time.epoch1970;
|
|
272 assert (span >= TimeSpan.zero);
|
|
273 tv.tv_sec = span.seconds;
|
|
274 tv.tv_usec = span.micros % 1_000_000L;
|
|
275 return tv;
|
|
276 }
|
|
277 }
|
|
278 }
|
|
279
|
|
280
|
|
281
|
|
282 debug (UnitTest)
|
|
283 {
|
|
284 unittest
|
|
285 {
|
|
286 auto time = Clock.now;
|
|
287 assert (Clock.convert(Clock.convert(time)) is time);
|
|
288
|
|
289 time -= TimeSpan(time.ticks % TimeSpan.TicksPerSecond);
|
|
290 auto date = Clock.toDate(time);
|
|
291
|
|
292 assert (time is Clock.fromDate(date));
|
|
293 }
|
|
294 }
|
|
295
|
|
296 debug (Clock)
|
|
297 {
|
|
298 void main()
|
|
299 {
|
|
300 auto time = Clock.now;
|
|
301 }
|
|
302 } |