2

I need to load POSIXlt variables from microsecond values since the epoch. Is there a better way to do this:

options(digits.secs=6)
mytime=1366039619645990
as.POSIXlt(mytime %/% 1e6, tz="EST", origin="1970-01-01") + (mytime %% 1e6)/1e6
[1] "2013-04-15 10:26:59.64598 EST"

It seems a bit convoluted given I have millions of records to load.

Robert Kubrick
  • 8,413
  • 13
  • 59
  • 91
  • This seems to produce some rounding errors - such as with `mytime=1366039619646000`? – Simon O'Hanlon Apr 23 '13 at 21:53
  • @SimonO101 it might be, I think the underlying value is implemented as double, so it can give a different rounding on your computer. – Robert Kubrick Apr 23 '13 at 22:00
  • what exactly is the point of adding this zero - `(mytime %% mytime)/1000000`? :) – eddi Apr 23 '13 at 22:43
  • @eddi that is what I thought. But try it without adding the *0*. I get .64598 without it. Weird. – Simon O'Hanlon Apr 23 '13 at 22:45
  • @SimonO101 I get the exact same result, .64598 with both. – eddi Apr 23 '13 at 22:46
  • @eddi I get .64599 with it and .64598 wihtout. What platform are you on? – Simon O'Hanlon Apr 23 '13 at 23:00
  • @SimonO101 I had a typing error in the example, it is (mytime %% 1000000)/1000000. I want to add the microseconds from the original epoch value to the POSIX object. – Robert Kubrick Apr 23 '13 at 23:44
  • @RobertKubrick but if I copy/paste the code you now have above I get `[1] "2013-04-15 10:27:00.29197 EST"`!! What do you get? – Simon O'Hanlon Apr 24 '13 at 08:53
  • @SimonO101 That's right, I fixed the command output too now. Sorry for the many edits. We still get a different rounding. – Robert Kubrick Apr 24 '13 at 11:46
  • 1
    @RobertKubrick Sorry for digging this back up after so long (I've been looking into time issues lately). You're adding the subsecond values in twice (as `/` is not integer division). The "correct" subsecond value would be .645990. This gives it (modulo rounding error): `as.POSIXlt(mytime%/%1e6, tz="EST", origin="1970-01-01") + (mytime %% 1e6)/1e6` – Matthew Lundberg May 20 '13 at 01:53

2 Answers2

2

The modulo division may produce some rounding errors (which I found on my system). Addition of a small fraction of time, half the maximum accuracy of the times should fix this, though in essence it is not really any different from what you are already doing:

as.POSIXlt( mytime/1e6 , tz="EST", origin="1970-01-01") + 5e-7
[1] "2013-04-15 10:26:59.64599 EST"

Contrast that with:

mytime=1366039619646000

# Produces rounding error
as.POSIXlt(mytime/1000000, tz="EST", origin="1970-01-01") + (mytime %% mytime)/1000000
[1] "2013-04-15 10:26:59.645 EST"

as.POSIXlt( mytime/1e6 , tz="EST", origin="1970-01-01") + 5e-7
[1] "2013-04-15 10:26:59.646 EST"

And when

mytime=1366039619645991
as.POSIXlt(mytime/1000000, tz="EST", origin="1970-01-01") + 5e-7
[1] "2013-04-15 10:26:59.645991 EST"
Simon O'Hanlon
  • 58,647
  • 14
  • 142
  • 184
  • this doesn't solve rounding errors for me, it just shifts them around. With `mytime=1366039619645991` I get `> as.POSIXlt(mytime/1000000, tz="EST", origin="1970-01-01") + 1e-6 [1] "2013-04-15 10:26:59.645992 EST" > as.POSIXlt(mytime/1000000, tz="EST", origin="1970-01-01") [1] "2013-04-15 10:26:59.645991 EST" ` – eddi Apr 23 '13 at 22:47
  • @eddi the fraction added was too big. It is the same as the smallest possible increment of time. Adding half this increment should fix this. I have updated. Does this give correct results for you too? – Simon O'Hanlon Apr 23 '13 at 22:58
  • :) after a few attempts @ writing the correct expression, it seems to do the trick, but it's unclear to me why this works – eddi Apr 23 '13 at 23:03
0

This would get rid of the modulo and division:

> mytime=1366039619645991
> mytime.secs = mytime %/% 1e+6
> mytime.usecs = mytime - as.integer(mytime.secs)*1e6
> as.POSIXlt(mytime.secs, tz="", origin="1970-01-01") + mytime.usecs*1e-6+0.0000005
[1] "2013-04-15 11:26:59.645991 EDT"
Robert Kubrick
  • 8,413
  • 13
  • 59
  • 91