4 * Conversion between Windows NT timestamps and UNIX timestamps.
8 * Copyright (C) 2012-2017 Eric Biggers
10 * This file is free software; you can redistribute it and/or modify it under
11 * the terms of the GNU Lesser General Public License as published by the Free
12 * Software Foundation; either version 3 of the License, or (at your option) any
15 * This file is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this file; if not, see http://www.gnu.org/licenses/.
28 #include "wimlib/timestamp.h"
31 * Timestamps in WIM files are Windows NT timestamps, or FILETIMEs: 64-bit
32 * values storing the number of 100-nanosecond ticks since January 1, 1601.
34 * Note: UNIX timestamps are signed; Windows timestamps are not. Negative UNIX
35 * timestamps represent times before 1970-01-01. When such a timestamp is
36 * converted to a Windows timestamp, we can preserve the correct date provided
37 * that it is not also before 1601-01-01.
40 #define NANOSECONDS_PER_TICK 100
41 #define TICKS_PER_SECOND (1000000000 / NANOSECONDS_PER_TICK)
42 #define TICKS_PER_MICROSECOND (TICKS_PER_SECOND / 1000000)
45 * EPOCH_DISTANCE is the number of seconds separating the Windows NT and UNIX
46 * epochs. This is equal to ((1970-1601)*365+89)*24*60*60. 89 is the number
47 * of leap years between 1970 and 1601.
49 #define EPOCH_DISTANCE 11644473600
51 /* Windows NT timestamps to UNIX timestamps */
54 wim_timestamp_to_time_t(u64 timestamp)
56 return (timestamp / TICKS_PER_SECOND) - EPOCH_DISTANCE;
60 wim_timestamp_to_timeval(u64 timestamp)
62 return (struct timeval) {
63 .tv_sec = wim_timestamp_to_time_t(timestamp),
64 .tv_usec = (timestamp % TICKS_PER_SECOND) / TICKS_PER_MICROSECOND,
69 wim_timestamp_to_timespec(u64 timestamp)
71 return (struct timespec) {
72 .tv_sec = wim_timestamp_to_time_t(timestamp),
73 .tv_nsec = (timestamp % TICKS_PER_SECOND) * NANOSECONDS_PER_TICK,
77 /* UNIX timestamps to Windows NT timestamps */
80 time_t_to_wim_timestamp(time_t t)
82 return ((u64)t + EPOCH_DISTANCE) * TICKS_PER_SECOND;
86 timeval_to_wim_timestamp(const struct timeval *tv)
88 return time_t_to_wim_timestamp(tv->tv_sec) +
89 (u32)tv->tv_usec * TICKS_PER_MICROSECOND;
93 timespec_to_wim_timestamp(const struct timespec *ts)
95 return time_t_to_wim_timestamp(ts->tv_sec) +
96 (u32)ts->tv_nsec / NANOSECONDS_PER_TICK;
99 /* Retrieve the current time as a WIM timestamp. */
101 now_as_wim_timestamp(void)
105 /* On Windows we rely on MinGW providing gettimeofday() for us. This
106 * could be changed to calling GetSystemTimeAsFileTime() directly, but
107 * now_as_wim_timestamp() isn't called much and it's simpler to keep the
108 * code for all platforms the same. */
109 gettimeofday(&tv, NULL);
110 return timeval_to_wim_timestamp(&tv);
113 /* Translate a WIM timestamp into a human-readable string. */
115 wim_timestamp_to_str(u64 timestamp, tchar *buf, size_t len)
118 time_t t = wim_timestamp_to_time_t(timestamp);
120 tstrftime(buf, len, T("%a %b %d %H:%M:%S %Y UTC"), &tm);