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
Visual Bug When Changing Robinson Projection's Central Meridian with Ggplot2
How to Know a Dimension of Matrix or Vector in R
Interleave Columns of Two Data Frames
Calculate Difference Between Dates by Group in R
R Bnlearn Eval Inside Function
How to Render Custom Map Tiles Created with Gdal2Tiles in Leaflet for R
Rolling by Group in Data.Table R
Choose Specific Number with Probability
Highlight a Single "Bar" in Ggplot
R: Read in Random Rows from File Using Fread or Equivalent
Count Number of Distinct Values in a Vector
Replace All Values Lower Than Threshold in R
Ggplot Line Plot Different Colors for Sections
How to Substitute Symbols in a Language Object
R Geom_Tile Ggplot2 What Kind of Stat Is Applied
R - Pivoting Duplicate Rows into Multiple Column with Unknown Number of Columns
How to Pass Multiple Group_By Arguments and a Dynamic Variable Argument to a Dplyr Function