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 }