Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R file.mtime() extremely poor precision on Mac OS and Windows 7

On Windows 7 and Mac OS 10.12.2 (with R 3.3.2), it appears that file.mtime() severely rounds or truncates timestamps. I verified that file.create("my_file.txt"); print(as.numeric(file.mtime("my_file.txt")), digits = 22) prints out several digits past the decimal on Linux, but everything past the decimal disappears on Windows 7 for the same my_file.txt. The behavior for Mac OS 10.12.2 is similar to that of Windows 7. Is there a platform-independent way to get precise file timestamps in R?

like image 573
landau Avatar asked Feb 09 '17 02:02

landau


2 Answers

You can wait about 2 weeks, at which point R 3.3.3 will solve this problem (at least for Windows). From the NEWS file:

(Windows only.) file.info() now returns file timestamps including fractions of seconds; it has done so on other platforms since R 2.14.0. (NB: some filesystems do not record modification and access timestamps to sub-second resolution.)

like image 67
Hong Ooi Avatar answered Oct 21 '22 12:10

Hong Ooi


I think the new file.info is likely the best way to go. If R-3.3.3 does not bring what you need (or in the interim, if it will), you can try to side-step it by capitalizing on the fact that stat is likely installed in the base OS (I have not tested on a Mac):

as.POSIXct(system2("stat", args = c("-c", "%y", "my_file.txt"), stdout = TRUE))
# [1] "2017-02-15 11:24:13 PST"

This can be formalized in a function that does a skosh more for you:

my_mtime <- function(filenames, stat = c("modified", "birth", "access", "status"),
                     exe = Sys.which("stat")) {
  if (! nzchar(exe)) stop("'stat' not found")
  stat <- switch(match.arg(stat), birth = "%w", access = "%x", modified = "%y", status = "%z")
  filenames <- Sys.glob(filenames) # expand wildcards, remove missing files
  if (length(filenames)) {
    outs <- setNames(system2(exe, args = c("-c", stat, shQuote(filenames)), stdout = TRUE),
                     nm = filenames)
    as.POSIXct(outs)
  }
}

my_mtime("[bh]*")
#                  b-file.R                  h-file.R 
# "2017-02-14 05:46:34 PST" "2017-02-14 05:46:34 PST"

Since you asked for file.mtime, I'm assuming "modified" is the most interesting to you, but it's easy enough to include some other file timestamps:

my_mtime("[bh]*", stat="birth")
#                  b-file.R                  h-file.R 
# "2017-02-13 22:04:01 PST" "2017-02-13 22:04:01 PST" 
my_mtime("[bh]*", stat="status")
#                  b-file.R                  h-file.R 
# "2017-02-14 05:46:34 PST" "2017-02-14 05:46:34 PST" 

Note that the lack of fractional seconds is an artifact of printing (as you stated), this can be remedied:

x <- my_mtime("[bh]*", stat="status")
x
#                  b-file.R                  h-file.R 
# "2017-02-14 05:46:34 PST" "2017-02-14 05:46:34 PST" 
options(digits.secs = 6)
x
#                         b-file.R                         h-file.R 
# "2017-02-14 05:46:34.307046 PST" "2017-02-14 05:46:34.313038 PST" 
class(x)
# [1] "POSIXct" "POSIXt" 

Update: after testing on a Mac, I confirmed a couple of things (thanks to @HongOoi for the prod): (1) stat is indeed different, not supporting the same command-line options, so this script would need to be updated; and (2) this answer suggests that the filesystem is not even storing sub-second resolution on the file times. If your filesystem type is HFS+, I think there may be nothing to be done here. If the underlying filesystem is different, you may have better results.

It's true that Windows does not come with a stat executable. However, Git for Windows (which some argue is a necessity in an analyst/dev toolkit) does, under /Program Files/Git/usr/bin/stat.exe. (In fact, my hack above was written on Windows, tested second on Ubuntu.)

Bottom line, unfortunately, you may not get what you want/need on MacOS depending on your filesystem type. I could not get the installed stat to give sub-second resolution (even with its different arguments), suggesting that the 4 year old answer I referenced has not changed.

like image 25
r2evans Avatar answered Oct 21 '22 12:10

r2evans