6bbdd8ac41ac2741683e001b4c8bab2ed5025f79
[wimlib] / src / timestamp.c
1 /*
2  * timestamp.c
3  *
4  * Conversion between Windows NT timestamps and UNIX timestamps.
5  */
6
7 /*
8  * Copyright (C) 2012, 2013, 2014 Eric Biggers
9  *
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
13  * later version.
14  *
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
18  * details.
19  *
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/.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #include "wimlib/timestamp.h"
29
30 /*
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.
33  */
34
35 #define NANOSECONDS_PER_TICK    100
36 #define TICKS_PER_SECOND        (1000000000 / NANOSECONDS_PER_TICK)
37 #define TICKS_PER_MICROSECOND   (TICKS_PER_SECOND / 1000000)
38
39 /*
40  * EPOCH_DISTANCE is the number of 100-nanosecond ticks separating the
41  * Windows NT and UNIX epochs.  This is equal to ((1970-1601)*365+89)*
42  * 24*60*60*10000000.  89 is the number of leap years between 1970 and 1601.
43  */
44 #define EPOCH_DISTANCE          116444736000000000
45
46 #define TO_WINNT_EPOCH(timestamp)       ((timestamp) + EPOCH_DISTANCE)
47 #define TO_UNIX_EPOCH(timestamp)        ((timestamp) - EPOCH_DISTANCE)
48
49 /* Windows NT timestamps to UNIX timestamps  */
50
51 time_t
52 wim_timestamp_to_time_t(u64 timestamp)
53 {
54         timestamp = TO_UNIX_EPOCH(timestamp);
55
56         return timestamp / TICKS_PER_SECOND;
57 }
58
59 struct timeval
60 wim_timestamp_to_timeval(u64 timestamp)
61 {
62         timestamp = TO_UNIX_EPOCH(timestamp);
63
64         return (struct timeval) {
65                 .tv_sec = timestamp / TICKS_PER_SECOND,
66                 .tv_usec = (timestamp % TICKS_PER_SECOND) / TICKS_PER_MICROSECOND,
67         };
68 }
69
70 struct timespec
71 wim_timestamp_to_timespec(u64 timestamp)
72 {
73         timestamp = TO_UNIX_EPOCH(timestamp);
74
75         return (struct timespec) {
76                 .tv_sec = timestamp / TICKS_PER_SECOND,
77                 .tv_nsec = (timestamp % TICKS_PER_SECOND) * NANOSECONDS_PER_TICK,
78         };
79 }
80
81 /* UNIX timestamps to Windows NT timestamps  */
82
83 u64
84 time_t_to_wim_timestamp(time_t t)
85 {
86         u64 timestamp = (u64)t * TICKS_PER_SECOND;
87
88         return TO_WINNT_EPOCH(timestamp);
89 }
90
91 u64
92 timeval_to_wim_timestamp(const struct timeval *tv)
93 {
94         u64 timestamp = (u64)tv->tv_sec * TICKS_PER_SECOND +
95                         (u64)tv->tv_usec * TICKS_PER_MICROSECOND;
96
97         return TO_WINNT_EPOCH(timestamp);
98 }
99
100 u64
101 timespec_to_wim_timestamp(const struct timespec *ts)
102 {
103         u64 timestamp = (u64)ts->tv_sec * TICKS_PER_SECOND +
104                         (u64)ts->tv_nsec / NANOSECONDS_PER_TICK;
105
106         return TO_WINNT_EPOCH(timestamp);
107 }
108
109 /* Retrieve the current time as a WIM timestamp.  */
110 u64
111 now_as_wim_timestamp(void)
112 {
113         struct timeval tv;
114
115         /* On Windows we rely on MinGW providing gettimeofday() for us.  This
116          * could be changed to calling GetSystemTimeAsFileTime() directly, but
117          * now_as_wim_timestamp() isn't called much and it's simpler to keep the
118          * code for all platforms the same.  */
119         gettimeofday(&tv, NULL);
120         return timeval_to_wim_timestamp(&tv);
121 }
122
123 /* Translate a WIM timestamp into a human-readable string.  */
124 void
125 wim_timestamp_to_str(u64 timestamp, tchar *buf, size_t len)
126 {
127         struct tm tm;
128         time_t t = wim_timestamp_to_time_t(timestamp);
129         gmtime_r(&t, &tm);
130         tstrftime(buf, len, T("%a %b %d %H:%M:%S %Y UTC"), &tm);
131 }