1 /*******************************************************************************
2 
3         copyright:      Copyright (c) 2007 Kris Bell. All rights reserved
4 
5         license:        BSD style: $(LICENSE)
6 
7         version:        Apr 2007: split away from utc
8 
9         author:         Kris
10 
11 *******************************************************************************/
12 
13 module tango.time.WallClock;
14 
15 public  import  tango.time.Time;
16 
17 private import  tango.time.Clock;
18 
19 private import  tango.sys.Common;
20 
21 /******************************************************************************
22 
23         Exposes wall-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         Please note that conversion between UTC and Wall time is performed
29         in accordance with the OS facilities. In particular, Win32 systems
30         behave differently to Posix when calculating daylight-savings time
31         (Win32 calculates with respect to the time of the call, whereas a
32         Posix system calculates based on a provided point in time). Posix
33         systems should typically have the TZ environment variable set to 
34         a valid descriptor.
35 
36 *******************************************************************************/
37 
38 struct WallClock
39 {
40         version (Win32)
41         {
42                 /***************************************************************
43 
44                         Return the current local time
45 
46                 ***************************************************************/
47 
48                 @property static Time now ()
49                 {
50                         return Clock.now - localBias();
51                 }
52 
53                 /***************************************************************
54 
55                         Return the timezone relative to GMT. The value is 
56                         negative when west of GMT
57 
58                 ***************************************************************/
59 
60                 @property static TimeSpan zone ()
61                 {
62                         TIME_ZONE_INFORMATION tz = void;
63 
64                         auto tmp = GetTimeZoneInformation (&tz);
65                         return TimeSpan.fromMinutes(-tz.Bias);
66                 }
67 
68                 /***************************************************************
69 
70                         Set fields to represent a local version of the 
71                         current UTC time. All values must fall within 
72                         the domain supported by the OS
73 
74                 ***************************************************************/
75 
76                 static DateTime toDate ()
77                 {
78                         return toDate (Clock.now);
79                 }
80 
81                 /***************************************************************
82 
83                         Set fields to represent a local version of the 
84                         provided UTC time. All values must fall within 
85                         the domain supported by the OS
86 
87                 ***************************************************************/
88 
89                 static DateTime toDate (const(Time) utc)
90                 {
91                         return Clock.toDate (utc - localBias());
92                 }
93 
94                 /***************************************************************
95 
96                         Convert Date fields to local time
97 
98                 ***************************************************************/
99 
100                 static Time fromDate (ref const(DateTime) date)
101                 {
102                         return (Clock.fromDate(date) + localBias());
103                 }
104 
105                 /***************************************************************
106 
107                         Retrieve the local bias, including DST adjustment.
108                         Note that Win32 calculates DST at the time of call
109                         rather than based upon a point in time represented
110                         by an argument.
111                          
112                 ***************************************************************/
113 
114                 private static TimeSpan localBias () 
115                 { 
116                        int bias; 
117                        TIME_ZONE_INFORMATION tz = void; 
118 
119                        switch (GetTimeZoneInformation (&tz)) 
120                               { 
121                               default: 
122                                    bias = tz.Bias; 
123                                    break; 
124                               case 1: 
125                                    bias = tz.Bias + tz.StandardBias; 
126                                    break; 
127                               case 2: 
128                                    bias = tz.Bias + tz.DaylightBias; 
129                                    break; 
130                               } 
131 
132                        return TimeSpan.fromMinutes(bias); 
133                }
134         }
135 
136         version (Posix)
137         {
138                 /***************************************************************
139 
140                         Return the current local time
141 
142                 ***************************************************************/
143 
144                 @property static Time now ()
145                 {
146                         tm t = void;
147                         timeval tv = void;
148                         gettimeofday (&tv, null);
149                         localtime_r (&tv.tv_sec, &t);
150                         tv.tv_sec = timegm (&t);
151                         return Clock.convert (tv);
152                 }
153 
154                 /***************************************************************
155 
156                         Return the timezone relative to GMT. The value is 
157                         negative when west of GMT
158 
159                 ***************************************************************/
160 
161                 @property static TimeSpan zone ()
162                 {
163                         version(OSX)
164                                 {
165                                 timezone_t tz = void;
166                                 gettimeofday (null, &tz);
167                                 return TimeSpan.fromMinutes(-tz.tz_minuteswest);
168                                 }
169                              else
170                                 return TimeSpan.fromSeconds(-timezone);
171                 }
172 
173                 /***************************************************************
174 
175                         Set fields to represent a local version of the 
176                         current UTC time. All values must fall within 
177                         the domain supported by the OS
178 
179                 ***************************************************************/
180 
181                 static DateTime toDate ()
182                 {
183                         return toDate (Clock.now);
184                 }
185 
186                 /***************************************************************
187 
188                         Set fields to represent a local version of the 
189                         provided UTC time. All values must fall within 
190                         the domain supported by the OS
191 
192                 ***************************************************************/
193 
194                 static DateTime toDate (const(Time) utc)
195                 {
196                         DateTime dt = void;
197                         auto timeval = Clock.convert (utc);
198                         dt.time.millis = cast(uint)timeval.tv_usec / 1000;
199 
200                         tm t = void;
201                         localtime_r (&timeval.tv_sec, &t);
202         
203                         dt.date.year    = t.tm_year + 1900;
204                         dt.date.month   = t.tm_mon + 1;
205                         dt.date.day     = t.tm_mday;
206                         dt.date.dow     = t.tm_wday;
207                         dt.date.era     = 0;
208                         dt.time.hours   = t.tm_hour;
209                         dt.time.minutes = t.tm_min;
210                         dt.time.seconds = t.tm_sec;
211 
212                         Clock.setDoy(dt);
213                         return dt;
214                 }
215 
216                 /***************************************************************
217 
218                         Convert Date fields to local time
219 
220                 ***************************************************************/
221 
222                 static Time fromDate (ref const(DateTime) dt)
223                 {
224                         tm t = void;
225 
226                         t.tm_year = dt.date.year - 1900;
227                         t.tm_mon  = dt.date.month - 1;
228                         t.tm_mday = dt.date.day;
229                         t.tm_hour = dt.time.hours;
230                         t.tm_min  = dt.time.minutes;
231                         t.tm_sec  = dt.time.seconds;
232 
233                         auto seconds = mktime (&t);
234                         return Time.epoch1970 + TimeSpan.fromSeconds(seconds) 
235                                               + TimeSpan.fromMillis(dt.time.millis);
236                 }
237         }
238 
239         /***********************************************************************
240 
241         ***********************************************************************/
242         
243         static Time toLocal (const(Time) utc)
244         {
245                 auto mod = utc.ticks % TimeSpan.TicksPerMillisecond;
246                 auto date=toDate(utc);
247                 return Clock.fromDate(date) + TimeSpan(mod);
248         }
249 
250         /***********************************************************************
251 
252         ***********************************************************************/
253         
254         static Time toUtc (const(Time) wall)
255         {
256                 auto mod = wall.ticks % TimeSpan.TicksPerMillisecond;
257                 auto date=Clock.toDate(wall);
258                 return fromDate(date) + TimeSpan(mod);
259         }
260 }
261 
262 
263 version (Posix)
264 {
265     version(OSX) {}
266     else
267     {
268         shared static this()
269         {
270             tzset();
271         }
272     }
273 }