Odd Output from R Posixlt

Odd output from R POSIXlt

POSIXlt objects are lists. You changed the mon element of the list. That does not change the year element of the list.

d <- as.POSIXlt("1900-01-01")
unclass(d)
d$mon <- 12
unclass(d)

If you want your change to alter any/all of the other list elements, convert it to POSIXct then back to POSIXlt.

unclass(as.POSIXlt(as.POSIXct(d)))

Odd behavor with POSIXct/POSIXlt and subsecond accuracy

@GSee is right, this is a floating point arithmetic problem. And Gavin Simpson's answer is correct in that it's how the object is printed.

R> options(digits=17)
R> .index(x)
[1] 1295589600.0009999 1295589600.0020001 1295589600.0030000 1295589600.0039999
[5] 1295589600.0050001 1295589600.0060000 1295589600.0070000 1295589600.0079999
[9] 1295589600.0090001 1295589600.0100000

All the precision is there, but these lines in format.POSIXlt cause options(digits.secs=6) to not be honored.

np <- getOption("digits.secs")
if (is.null(np))
np <- 0L
else
np <- min(6L, np)
if (np >= 1L) {
for (i in seq_len(np) - 1L) {
if (all(abs(secs - round(secs, i)) < 1e-06)) {
np <- i
break
}
}
}

Due to precision issues, in your example np is reset to 3 in the above for loop. And the format "%Y-%m-%d %H:%M:%OS3" yields the times you posted. You can see the times are accurate if you use the "%Y-%m-%d %H:%M:%OS6" format.

R> format(as.POSIXlt(index(x)[1:2]), "%Y-%m-%d %H:%M:%OS3")
[1] "2011-01-21 00:00:00.000" "2011-01-21 00:00:00.002"
R> format(as.POSIXlt(index(x)[1:2]), "%Y-%m-%d %H:%M:%OS6")
[1] "2011-01-21 00:00:00.000999" "2011-01-21 00:00:00.002000"

Another POSIXlt quandary in R

This (a) works for me with the R and session details as below:

> a$mon = a$mon-1
> a=as.POSIXlt(as.POSIXct(a))
> a
[1] "2003-10-01 01:00:00 BST"
> unlist(a)
sec min hour mday mon year wday yday isdst
0 0 1 1 9 103 3 273 1

Without any further information as per your locale and time zone settings etc, I would have to guess that in your locale/time zone that the date/time indicated by a after you subtracted 1 from the $mon element didn't exist. R is pretty clever about these things but time zones and locales often catch people out.

The real question is why are you using a date/time object when you are handling just dates?
a <- as.Date("2003-11-01", "%Y-%m-%d") would be sufficient in this example.

Details of my R session:

> sessionInfo()
R version 2.15.0 Patched (2012-04-14 r59019)
Platform: x86_64-unknown-linux-gnu (64-bit)

locale:
[1] LC_CTYPE=en_GB.utf8 LC_NUMERIC=C
[3] LC_TIME=en_GB.utf8 LC_COLLATE=en_GB.utf8
[5] LC_MONETARY=en_GB.utf8 LC_MESSAGES=en_GB.utf8
[7] LC_PAPER=C LC_NAME=C
[9] LC_ADDRESS=C LC_TELEPHONE=C
[11] LC_MEASUREMENT=en_GB.utf8 LC_IDENTIFICATION=C

attached base packages:
[1] stats graphics grDevices utils datasets methods
[7] base

other attached packages:
[1] ggplot2_0.9.1

loaded via a namespace (and not attached):
[1] colorspace_1.1-1 dichromat_1.2-4 digest_0.5.2
[4] grid_2.15.0 labeling_0.1 MASS_7.3-18
[7] memoise_0.1 munsell_0.3 plyr_1.7.1
[10] proto_0.3-9.2 RColorBrewer_1.0-5 reshape2_1.2.1
[13] scales_0.2.1 stringr_0.6 tools_2.15.0

Using which() on POSIXct object grabs wrong elements

You should probably keep it as a POSIXlt datetime (which strptime creates), and then compare against another datetime object in the appropriate timezone. E.g.:

x <- strptime(c("2018-08-30 08:04", "2018-08-30 08:05", "2018-08-30 08:06", 
"2018-08-30 08:07", "2018-08-30 08:08"), format="%Y-%m-%d %H:%M", tz="UTC")
#[1] "2018-08-30 08:04:00 UTC" "2018-08-30 08:05:00 UTC"
#[3] "2018-08-30 08:06:00 UTC" "2018-08-30 08:07:00 UTC"
#[5] "2018-08-30 08:08:00 UTC"

Text comparison gives odd results:

x > "2018-08-30 08:06:00 UTC"
#TRUE TRUE TRUE TRUE TRUE

Datetime comparison:

x > as.POSIXlt("2018-08-30 08:06:00", tz="UTC")
#[1] FALSE FALSE FALSE TRUE TRUE

Iterate over POSIXlt in R

It's happening cause lapply works on list and you're right about storing, after help("DateTimeClasses"):

Class "POSIXlt" is a named list of vectors (...)

If you really need to work with POSIXlt I propose convert to list, e.g.:

times.input.L <- split(times.input, seq_along(times.input))
lapply(times.input.L, print)
[1] "2013-01-01 01:00:00 CET"
[1] "2013-01-01 01:00:01 CET"

Extract date elements from POSIXlt and put into data frame in R

POSIXlt objects are a list of 9 components (see the Details section of ?POSIXlt for more information). Because the dd_mmm_yy column is POSIXlt, you don't need a function to extract the components. You can just extract the components by their names:

orders$day <- orders$dd_mmm_yy$mday        # day of month
orders$month <- orders$dd_mmm_yy$mon+1 # month of year (zero-indexed)
orders$year <- orders$dd_mmm_yy$year+1900 # years since 1900
orders
# order_id dd_mmm_yy day month year
# 1 1 2005-07-28 28 7 2005
# 2 2 2007-03-04 4 3 2007

as.Date(as.POSIXct()) gives the wrong date?

The safe way to do this is to pass the date value through format. This does create an additional step but as.Date will accept the character result if it is formated with a "-" or "/":

as.Date( format( as.POSIXct('2019-03-11 23:59:59'), "%Y-%m-%d") )
[1] "2019-03-11"

as.Date( as.POSIXct('2019-03-11 23:59:59') ) # I'm in a locale where the problem might exist
[1] "2019-03-12"

The documentation for timezones is confusing to me too. In some (and this case as it turned out) case EST may not be unambiguous and may actually refer to a tz in Australia. Try "EST5EDT" or "America/New_York" if you happen to be in North America.

In this case it could also relate to differences in how your unstated OS handles the 'tz' argument, since I get "2012-08-06". ( I'm in PDT US tz at the moment, although I'm not sure that should matter. )Changing which function gets the tz argument may clarify (or not):

> as.Date(as.POSIXct('2012-08-06 19:35:23', tz='EST'))
[1] "2012-08-07"
> as.Date(as.POSIXct('2012-08-06 17:35:23', tz='EST'))
[1] "2012-08-06"

> as.Date(as.POSIXct('2012-08-06 21:35:23'), tz='EST')
[1] "2012-08-06"
> as.Date(as.POSIXct('2012-08-06 22:35:23'), tz='EST')
[1] "2012-08-07"

If you omit the tz from as.POSIXct then UTC is assumed.

These are the unambiguous names of the Ozzie TZ's (at least on my Mac):

tzfile <- "/usr/share/zoneinfo/zone.tab"
tzones <- read.delim(tzfile, row.names = NULL, header = FALSE,
col.names = c("country", "coords", "name", "comments"),
as.is = TRUE, fill = TRUE, comment.char = "#")
grep("^Aus", tzones$name, value=TRUE)
[1] "Australia/Lord_Howe" "Australia/Hobart"
[3] "Australia/Currie" "Australia/Melbourne"
[5] "Australia/Sydney" "Australia/Broken_Hill"
[7] "Australia/Brisbane" "Australia/Lindeman"
[9] "Australia/Adelaide" "Australia/Darwin"
[11] "Australia/Perth" "Australia/Eucla"

It seems that there is a weird Segmentation Fault when using R POSIXct class

[moved from comments]

Solaris has a smaller user base, hence is less thoroughly tested, hence there is a slightly larger possibility than usual that you have found a new bug. Update to R 2.12.1 patched (to avoid getting Ripleyed), run with --vanilla (avoid loading any other packages), and see if the problem persists. If it does, post to r-devel and/or submit a bug report (with full system details, middle name of your maternal grandmother, etc.) ... [runs fine for me on R 2.12.1 on Ubuntu Linux]

Passing POSIXct object to function returns numeric vector

We can use lapply instead of sapply as sapply by default has the option simplify = TRUE. So, if the list elements are of the same length, it will simplify it to vector or matrix depending on the length of the list elements and POSIXct is stored as numeric.

lst <- lapply(dates, function(x) x)

If we need to use sapply, then an option would simplify = FALSE

lst <- sapply(dates, function(x) x, simplify=FALSE)

After applying the function, if we need as a vector output,

do.call("c", lst)

Regarding the change of timezone, it is documented in the ?DateTimeClasses

Using c on "POSIXlt" objects converts them to the current time zone,
and on "POSIXct" objects drops any "tzone" attributes (even if they
are all marked with the same time zone).

So, the possible option would be (as mentioned in the comments by @kmo)

.POSIXct(lst, tz = "America/Los_Angeles")
#[1] "2012-02-01 12:32:00 PST" "2012-10-24 17:25:56 PDT" "2008-09-26 17:13:31 PDT" "2011-08-23 11:11:17 PDT" "2015-09-19 22:28:33 PDT"

Or as @thelatemail mentioned in the comments

.POSIXct(sapply(dates,I), attr(dates,"tzone") )


Related Topics



Leave a reply



Submit