2 Unix SMB/CIFS implementation.
3 time handling functions
5 Copyright (C) Andrew Tridgell 1992-2004
6 Copyright (C) Stefan (metze) Metzmacher 2002
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #define TIME_T_MIN ((time_t)0 < (time_t) -1 ? (time_t) 0 \
27 : ~ (time_t) 0 << (sizeof (time_t) * 8 - 1))
30 #define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
33 /*******************************************************************
34 External access to time_t_min and time_t_max.
35 ********************************************************************/
36 time_t get_time_t_max(void)
41 /*******************************************************************
42 a gettimeofday wrapper
43 ********************************************************************/
44 void GetTimeOfDay(struct timeval *tval)
46 #ifdef HAVE_GETTIMEOFDAY_TZ
47 gettimeofday(tval,NULL);
53 /*******************************************************************
54 yield the difference between *A and *B, in seconds, ignoring leap seconds
55 ********************************************************************/
56 static int tm_diff(struct tm *a, struct tm *b)
58 int ay = a->tm_year + (1900 - 1);
59 int by = b->tm_year + (1900 - 1);
60 int intervening_leap_days =
61 (ay/4 - by/4) - (ay/100 - by/100) + (ay/400 - by/400);
63 int days = 365*years + intervening_leap_days + (a->tm_yday - b->tm_yday);
64 int hours = 24*days + (a->tm_hour - b->tm_hour);
65 int minutes = 60*hours + (a->tm_min - b->tm_min);
66 int seconds = 60*minutes + (a->tm_sec - b->tm_sec);
71 /*******************************************************************
72 return the UTC offset in seconds west of UTC, or 0 if it cannot be determined
73 ******************************************************************/
74 int get_time_zone(time_t t)
76 struct tm *tm = gmtime(&t);
84 return tm_diff(&tm_utc,tm);
87 #define TIME_FIXUP_CONSTANT (369.0*365.25*24*60*60-(3.0*24*60*60+6.0*60*60))
89 /****************************************************************************
90 interpret an 8 byte "filetime" structure to a time_t
91 It's originally in "100ns units since jan 1st 1601"
92 ****************************************************************************/
93 time_t nt_time_to_unix(const NTTIME *nt)
102 d = ((double)nt->high)*4.0*(double)(1<<30);
103 d += (nt->low&0xFFF00000);
106 /* now adjust by 369 years to make the secs since 1970 */
107 d -= TIME_FIXUP_CONSTANT;
109 if (TIME_T_MIN >= d || d >= TIME_T_MAX) {
113 ret = (time_t)(d+0.5);
119 /****************************************************************************
120 put a 8 byte filetime from a time_t
121 This takes GMT as input
122 ****************************************************************************/
123 void unix_to_nt_time(NTTIME *nt, time_t t)
132 if (t == TIME_T_MAX) {
133 nt->low = 0xffffffff;
134 nt->high = 0x7fffffff;
138 nt->low = 0xffffffff;
139 nt->high = 0xffffffff;
144 d += TIME_FIXUP_CONSTANT;
147 nt->high = (uint32)(d * (1.0/(4.0*(double)(1<<30))));
148 nt->low = (uint32)(d - ((double)nt->high)*4.0*(double)(1<<30));
152 /****************************************************************************
153 check if it's a null mtime
154 ****************************************************************************/
155 BOOL null_mtime(time_t mtime)
158 mtime == (time_t)0xFFFFFFFF ||
162 /*******************************************************************
163 create a 16 bit dos packed date
164 ********************************************************************/
165 static uint16 make_dos_date1(struct tm *t)
168 ret = (((unsigned)(t->tm_mon+1)) >> 3) | ((t->tm_year-80) << 1);
169 ret = ((ret&0xFF)<<8) | (t->tm_mday | (((t->tm_mon+1) & 0x7) << 5));
173 /*******************************************************************
174 create a 16 bit dos packed time
175 ********************************************************************/
176 static uint16 make_dos_time1(struct tm *t)
179 ret = ((((unsigned)t->tm_min >> 3)&0x7) | (((unsigned)t->tm_hour) << 3));
180 ret = ((ret&0xFF)<<8) | ((t->tm_sec/2) | ((t->tm_min & 0x7) << 5));
184 /*******************************************************************
185 create a 32 bit dos packed date/time from some parameters
186 This takes a GMT time and returns a packed localtime structure
187 ********************************************************************/
188 static uint32 make_dos_date(time_t unixdate, int zone_offset)
197 unixdate -= zone_offset;
199 t = gmtime(&unixdate);
204 ret = make_dos_date1(t);
205 ret = ((ret&0xFFFF)<<16) | make_dos_time1(t);
210 /*******************************************************************
211 put a dos date into a buffer (time/date format)
212 This takes GMT time and puts local time in the buffer
213 ********************************************************************/
214 void push_dos_date(char *buf, int offset, time_t unixdate, int zone_offset)
216 uint32 x = make_dos_date(unixdate, zone_offset);
220 /*******************************************************************
221 put a dos date into a buffer (date/time format)
222 This takes GMT time and puts local time in the buffer
223 ********************************************************************/
224 void push_dos_date2(char *buf,int offset,time_t unixdate, int zone_offset)
227 x = make_dos_date(unixdate, zone_offset);
228 x = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
232 /*******************************************************************
233 put a dos 32 bit "unix like" date into a buffer. This routine takes
234 GMT and converts it to LOCAL time before putting it (most SMBs assume
235 localtime for this sort of date)
236 ********************************************************************/
237 void push_dos_date3(char *buf,int offset,time_t unixdate, int zone_offset)
239 if (!null_mtime(unixdate)) {
240 unixdate -= zone_offset;
242 SIVAL(buf,offset,unixdate);
245 /*******************************************************************
246 interpret a 32 bit dos packed date/time to some parameters
247 ********************************************************************/
248 static void interpret_dos_date(uint32 date,int *year,int *month,int *day,int *hour,int *minute,int *second)
252 p0=date&0xFF; p1=((date&0xFF00)>>8)&0xFF;
253 p2=((date&0xFF0000)>>16)&0xFF; p3=((date&0xFF000000)>>24)&0xFF;
255 *second = 2*(p0 & 0x1F);
256 *minute = ((p0>>5)&0xFF) + ((p1&0x7)<<3);
257 *hour = (p1>>3)&0xFF;
259 *month = ((p2>>5)&0xFF) + ((p3&0x1)<<3) - 1;
260 *year = ((p3>>1)&0xFF) + 80;
263 /*******************************************************************
264 create a unix date (int GMT) from a dos date (which is actually in
266 ********************************************************************/
267 time_t pull_dos_date(const uint8 *date_ptr, int zone_offset)
273 dos_date = IVAL(date_ptr,0);
275 if (dos_date == 0) return (time_t)0;
277 interpret_dos_date(dos_date,&t.tm_year,&t.tm_mon,
278 &t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec);
288 /*******************************************************************
289 like make_unix_date() but the words are reversed
290 ********************************************************************/
291 time_t pull_dos_date2(const uint8 *date_ptr, int zone_offset)
295 x = IVAL(date_ptr,0);
296 x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
299 return pull_dos_date((void *)&x, zone_offset);
302 /*******************************************************************
303 create a unix GMT date from a dos date in 32 bit "unix like" format
304 these generally arrive as localtimes, with corresponding DST
305 ******************************************************************/
306 time_t pull_dos_date3(const uint8 *date_ptr, int zone_offset)
308 time_t t = (time_t)IVAL(date_ptr,0);
309 if (!null_mtime(t)) {
316 /***************************************************************************
317 return a HTTP/1.0 time string
318 ***************************************************************************/
319 char *http_timestring(TALLOC_CTX *mem_ctx, time_t t)
323 struct tm *tm = localtime(&t);
326 return talloc_asprintf(mem_ctx,"%ld seconds since the Epoch",(long)t);
329 #ifndef HAVE_STRFTIME
330 buf = talloc_strdup(mem_ctx, asctime(tm));
331 if (buf[strlen(buf)-1] == '\n') {
332 buf[strlen(buf)-1] = 0;
335 strftime(tempTime, sizeof(tempTime)-1, "%a, %d %b %Y %H:%M:%S %Z", tm);
336 buf = talloc_strdup(mem_ctx, tempTime);
337 #endif /* !HAVE_STRFTIME */
342 /***************************************************************************
343 return a LDAP time string
344 ***************************************************************************/
345 char *ldap_timestring(TALLOC_CTX *mem_ctx, time_t t)
347 struct tm *tm = gmtime(&t);
353 /* formatted like: 20040408072012.0Z */
354 return talloc_asprintf(mem_ctx,
355 "%04u%02u%02u%02u%02u%02u.0Z",
356 tm->tm_year+1900, tm->tm_mon+1,
357 tm->tm_mday, tm->tm_hour, tm->tm_min,
363 /****************************************************************************
364 Return the date and time as a string
365 ****************************************************************************/
366 char *timestring(TALLOC_CTX *mem_ctx, time_t t)
374 return talloc_asprintf(mem_ctx,
375 "%ld seconds since the Epoch",
380 /* some versions of gcc complain about using %c. This is a bug
381 in the gcc warning, not a bug in this code. See a recent
382 strftime() manual page for details.
384 strftime(tempTime,sizeof(tempTime)-1,"%c %Z",tm);
385 TimeBuf = talloc_strdup(mem_ctx, tempTime);
387 TimeBuf = talloc_strdup(mem_ctx, asctime(tm));
393 /****************************************************************************
395 ****************************************************************************/
396 BOOL nt_time_is_zero(NTTIME *nt)
398 return (nt->high==0);
402 return a talloced string representing a NTTIME for human consumption
404 const char *nt_time_string(TALLOC_CTX *mem_ctx, const NTTIME *nt)
406 time_t t = nt_time_to_unix(nt);
407 return talloc_strdup(mem_ctx, timestring(mem_ctx, t));
412 put a NTTIME into a packet
414 void push_nttime(void *base, uint16 offset, NTTIME *t)
416 SIVAL(base, offset, t->low);
417 SIVAL(base, offset+4, t->high);
421 pull a NTTIME from a packet
423 NTTIME pull_nttime(void *base, uint16 offset)
426 ret.low = IVAL(base, offset);
427 ret.high = IVAL(base, offset+4);
432 convert a NTTIME to a double in 100-nano-seconds since 1601
434 double nttime_to_double_nt(NTTIME t)
436 const double t32 = 4294967296.0;
437 return t.high*t32 + t.low;
441 convert a double in 100-nano-seconds since 1601 to a NTTIME
443 NTTIME nttime_from_double_nt(double t)
445 const double t32 = 4294967296.0;
448 ret.low = t - (ret.high*t32);
453 parse a nttime as a large integer in a string and return a NTTIME
455 NTTIME nttime_from_string(const char *s)
457 return nttime_from_double_nt(strtod(s, NULL));