Hi Paul, all, I'm trying to port utimens and futimens to native Windows. A major problem is the semantic of time_t on native Windows. An experiment (at the end of this mail) shows that:
* While on POSIX systems, time_t is the number of seconds since 1970-01-01 00:00:00 UTC/GMT [1][2], on native Windows, this is not the case. The Microsoft doc is ambiguous [3] "The time function returns the number of seconds elapsed since midnight (00:00:00), January 1, 1970, Coordinated Universal Time (UTC), according to the system clock." What the MSVC library returns, is local time minus DST shift. In other words, because of local_time = utc_time + timezone + dst_shift the time_t on native Windows is utc_time + timezone * On mingw, there is additionally a stat() bug. If you have DST today, mingw behaves as if you have DST throughout the year. * The gmtime function is useless: since time_t is (utc_time + timezone), it produces a time string that represents (gmt_time + timezone) as well. What can we do? (a) Accept the non-POSIX definition of time_t, and tell programmers not to use gmtime() when they want UTC time. (b) Make time_t be like on POSIX, by overriding time(), stat(), fstat(), and similar functions. I'm in favour of (b), because * Programs that need UTC usually do so because they exchange data with other machines, and this messes up with the native Windows notion of time_t. * POSIX also has APIs with 'struct timeval' (whose first element is a time_t), and utime(), and they also become problematic when time_t is offset by a timezone. Opinions? Bruno [1] http://pubs.opengroup.org/onlinepubs/9699919799/functions/time.html [2] http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_16 [3] https://msdn.microsoft.com/en-us/library/1f4c8f33.aspx ====================== Print st_mtime of an existing file ================ #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <stdlib.h> #include <time.h> int main (int argc, char *argv[]) { if (argc != 2) { fprintf (stderr, "Usage: stat-file FILE\n"); exit (1); } const char *filename = argv[1]; struct stat buf; if (stat (filename, &buf) < 0) { perror("stat"); exit(1); } time_t tt = buf.st_mtime; int day = tt / (24*3600); int hour = (tt / 3600) % 24; int seconds = tt % 3600; fprintf (stdout, "mtime = %d %d %d\n", day, hour, seconds); fprintf (stdout, "as GMT: %s\n", asctime (gmtime (&tt))); fprintf (stdout, "as localtime: %s\n", asctime (localtime (&tt))); } ================================ Results =========================== (I am in CEST, i.e. GMT+1 with DST since end of March.) A file last touched on 2016-11-27 18:32 GMT: $ ls -l t.tar -rw-r--r-- 1 bruno None 10240 Nov 27 19:32 t.tar Cygwin: mtime = 17132 18 1920 as GMT: Sun Nov 27 18:32:00 2016 (correct) as localtime: Sun Nov 27 19:32:00 2016 (correct) msvc: mtime = 17132 19 1920 as GMT: Sun Nov 27 19:32:00 2016 (off by 1 h) as localtime: Sun Nov 27 19:32:00 2016 (correct) mingw: mtime = 17132 20 1920 as GMT: Sun Nov 27 20:32:00 2016 (off by 2 h) as localtime: Sun Nov 27 20:32:00 2016 (off by 1 h) A file last touched on 2017-04-05 01:49 GMT: $ ls -l n.txt -rw-r--r-- 1 bruno None 93 Apr 5 03:49 n.txt Cygwin: mtime = 17261 1 2961 as GMT: Wed Apr 5 01:49:21 2017 (correct) as localtime: Wed Apr 5 03:49:21 2017 (correct) msvc: mtime = 17261 2 2961 as GMT: Wed Apr 5 02:49:21 2017 (off by 1 h) as localtime: Wed Apr 5 03:49:21 2017 (correct) mingw: mtime = 17261 2 2961 as GMT: Wed Apr 05 02:49:21 2017 (off by 1 h) as localtime: Wed Apr 05 03:49:21 2017 (correct)