]> wimlib.net Git - wimlib/blobdiff - src/timestamp.c
Cleanup timestamp conversion code
[wimlib] / src / timestamp.c
index 33c617469ac56d55d7fee7165f8f51303bcf6e63..6bbdd8ac41ac2741683e001b4c8bab2ed5025f79 100644 (file)
 /*
  * timestamp.c
+ *
+ * Conversion between Windows NT timestamps and UNIX timestamps.
  */
 
 /*
- * Copyright (C) 2012, 2013 Eric Biggers
- *
- * This file is part of wimlib, a library for working with WIM files.
+ * Copyright (C) 2012, 2013, 2014 Eric Biggers
  *
- * wimlib is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 3 of the License, or (at your option)
- * any later version.
+ * This file is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option) any
+ * later version.
  *
- * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * This file is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  * details.
  *
- * You should have received a copy of the GNU General Public License
- * along with wimlib; if not, see http://www.gnu.org/licenses/.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this file; if not, see http://www.gnu.org/licenses/.
  */
 
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
 #endif
 
-#include "wimlib/types.h"
 #include "wimlib/timestamp.h"
 
-#include <time.h>
-#include <sys/time.h>
+/*
+ * Timestamps in WIM files are Windows NT timestamps, or FILETIMEs: 64-bit
+ * values storing the number of 100-nanosecond ticks since January 1, 1601.
+ */
+
+#define NANOSECONDS_PER_TICK   100
+#define TICKS_PER_SECOND       (1000000000 / NANOSECONDS_PER_TICK)
+#define TICKS_PER_MICROSECOND  (TICKS_PER_SECOND / 1000000)
+
+/*
+ * EPOCH_DISTANCE is the number of 100-nanosecond ticks separating the
+ * Windows NT and UNIX epochs.  This is equal to ((1970-1601)*365+89)*
+ * 24*60*60*10000000.  89 is the number of leap years between 1970 and 1601.
+ */
+#define EPOCH_DISTANCE         116444736000000000
+
+#define TO_WINNT_EPOCH(timestamp)      ((timestamp) + EPOCH_DISTANCE)
+#define TO_UNIX_EPOCH(timestamp)       ((timestamp) - EPOCH_DISTANCE)
+
+/* Windows NT timestamps to UNIX timestamps  */
+
+time_t
+wim_timestamp_to_time_t(u64 timestamp)
+{
+       timestamp = TO_UNIX_EPOCH(timestamp);
+
+       return timestamp / TICKS_PER_SECOND;
+}
+
+struct timeval
+wim_timestamp_to_timeval(u64 timestamp)
+{
+       timestamp = TO_UNIX_EPOCH(timestamp);
+
+       return (struct timeval) {
+               .tv_sec = timestamp / TICKS_PER_SECOND,
+               .tv_usec = (timestamp % TICKS_PER_SECOND) / TICKS_PER_MICROSECOND,
+       };
+}
+
+struct timespec
+wim_timestamp_to_timespec(u64 timestamp)
+{
+       timestamp = TO_UNIX_EPOCH(timestamp);
+
+       return (struct timespec) {
+               .tv_sec = timestamp / TICKS_PER_SECOND,
+               .tv_nsec = (timestamp % TICKS_PER_SECOND) * NANOSECONDS_PER_TICK,
+       };
+}
+
+/* UNIX timestamps to Windows NT timestamps  */
+
+u64
+time_t_to_wim_timestamp(time_t t)
+{
+       u64 timestamp = (u64)t * TICKS_PER_SECOND;
+
+       return TO_WINNT_EPOCH(timestamp);
+}
+
+u64
+timeval_to_wim_timestamp(const struct timeval *tv)
+{
+       u64 timestamp = (u64)tv->tv_sec * TICKS_PER_SECOND +
+                       (u64)tv->tv_usec * TICKS_PER_MICROSECOND;
+
+       return TO_WINNT_EPOCH(timestamp);
+}
+
+u64
+timespec_to_wim_timestamp(const struct timespec *ts)
+{
+       u64 timestamp = (u64)ts->tv_sec * TICKS_PER_SECOND +
+                       (u64)ts->tv_nsec / NANOSECONDS_PER_TICK;
+
+       return TO_WINNT_EPOCH(timestamp);
+}
 
+/* Retrieve the current time as a WIM timestamp.  */
 u64
-get_wim_timestamp(void)
+now_as_wim_timestamp(void)
 {
        struct timeval tv;
+
+       /* On Windows we rely on MinGW providing gettimeofday() for us.  This
+        * could be changed to calling GetSystemTimeAsFileTime() directly, but
+        * now_as_wim_timestamp() isn't called much and it's simpler to keep the
+        * code for all platforms the same.  */
        gettimeofday(&tv, NULL);
-       return timeval_to_wim_timestamp(tv);
+       return timeval_to_wim_timestamp(&tv);
 }
 
+/* Translate a WIM timestamp into a human-readable string.  */
 void
 wim_timestamp_to_str(u64 timestamp, tchar *buf, size_t len)
 {
        struct tm tm;
-       time_t t = wim_timestamp_to_unix(timestamp);
+       time_t t = wim_timestamp_to_time_t(timestamp);
        gmtime_r(&t, &tm);
        tstrftime(buf, len, T("%a %b %d %H:%M:%S %Y UTC"), &tm);
 }
-