In 2013, the switch from Central European Time (CET) to Central European Summer Time (CEST) took place on Sunday 2013-03-31. Clocks are advanced by one hour from 2am to 3pm, so basically there is no 2am.
start <- strptime("2013-03-31 01:00:00", format="%F %T", tz="CET")
times <- start + (0:5) * 60*15
times
[1] "2013-03-31 01:00:00 CET" "2013-03-31 01:15:00 CET"
[3] "2013-03-31 01:30:00 CET" "2013-03-31 01:45:00 CET"
[5] "2013-03-31 03:00:00 CEST" "2013-03-31 03:15:00 CEST"
Rounding the vector times to hours gives NAs. Even for times before 01:30, which aren't affected by the transition at all.
library(lubridate)
round_date(times, unit = "hour")
[1] "2013-03-31 01:00:00 CET" NA
[3] NA NA
[5] NA "2013-03-31 03:00:00 CEST"
This seems to be a bug, or am I missing something? I am running:
sessionInfo()
R version 3.1.0 (2014-04-10)
Platform: x86_64-w64-mingw32/x64 (64-bit)
locale:
[1] LC_COLLATE=German_Austria.1252 LC_CTYPE=German_Austria.1252
[3] LC_MONETARY=German_Austria.1252 LC_NUMERIC=C
[5] LC_TIME=German_Austria.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] lubridate_1.3.3
loaded via a namespace (and not attached):
[1] digest_0.6.4 memoise_0.2.1 plyr_1.8.1 Rcpp_0.11.2 stringr_0.6.2
It looks like the culprit is ceiling_date which is called by round_date:
ceiling_date(times,"hour")
[1] "2013-03-31 01:00:00 CET" NA
[3] NA NA
[5] NA "2013-03-31 04:00:00 CEST"
Looking at the code it works by adding 1 to the hour, thereby creating a non-existant time. It is definitely a bug.
base::round has support for times to do what you want though:
round(times,"hour")
[1] "2013-03-31 01:00:00 CET" "2013-03-31 01:00:00 CET"
[3] "2013-03-31 03:00:00 CEST" "2013-03-31 03:00:00 CEST"
[5] "2013-03-31 03:00:00 CEST" "2013-03-31 03:00:00 CEST"
It's an edge case and you could consider the behavior a bug. round_date uses ceiling_date and there this happens:
y <- floor_date(times - eseconds(1), "hour")
#[1] "2013-03-31 00:00:00 CET" "2013-03-31 01:00:00 CET" "2013-03-31 01:00:00 CET" "2013-03-31 01:00:00 CET" "2013-03-31 01:00:00 CET" "2013-03-31 03:00:00 CEST"
hour(y) <- hour(y) + 1
#[1] "2013-03-31 01:00:00 CET" NA NA NA NA "2013-03-31 04:00:00 CEST"
As you see it tries to increment 2013-03-31 01:00:00 CET by one hour and doesn't deal correctly with the time zones.
The root issue is probably in the "hour<-" POSIXct S4 method.
This has been fixed in master:
> times <- ymd_hms("2013-03-31 01:00:00 CET", "2013-03-31 01:15:00 CEST",
+ "2013-03-31 01:30:00 CEST", "2013-03-31 01:45:00 CEST",
+ "2013-03-31 03:00:00 CEST", "2013-03-31 03:15:00 CEST",
+ tz = "Europe/Amsterdam")
> round_date(times, unit = "hour")
[1] "2013-03-31 01:00:00 CET" "2013-03-31 01:00:00 CET" "2013-03-31 03:00:00 CEST"
[4] "2013-03-31 03:00:00 CEST" "2013-03-31 03:00:00 CEST" "2013-03-31 03:00:00 CEST"
> ceiling_date(times, unit = "hour")
[1] "2013-03-31 01:00:00 CET" "2013-03-31 03:00:00 CEST" "2013-03-31 03:00:00 CEST"
[4] "2013-03-31 03:00:00 CEST" "2013-03-31 03:00:00 CEST" "2013-03-31 04:00:00 CEST"
Related
I have convert my date from chr to POSIXCT using formula below.
crime2$Date = parse_date_time(crime2$Date, orders = c('dmy_HM'),tz="UTC")
so my date actually now in this format.
> head(crime2$Date, 10)
[1] "2015-03-18 19:44:00 UTC" "2015-03-18 22:45:00 UTC"
[3] "2015-03-18 22:30:00 UTC" "2015-03-18 22:00:00 UTC"
[5] "2015-03-18 23:00:00 UTC" "2015-03-18 21:35:00 UTC"
[7] "2015-03-18 22:50:00 UTC" "2015-03-18 23:40:00 UTC"
[9] "2015-03-18 23:30:00 UTC" "2015-03-18 22:45:00 UTC"
However, if i want to remove the time and keep the date only, what can i do about this?
Example, they will look like this
" 2015-03-18 " "2015-03-18 "
I am trying to use lubridate to process the results of a differential equation solved using ode. My simulation begins on a certain date (01-01-2021) and is on the order of days (a one unit-time increase is equal to a one day calendar time increase). How can I use lubridate to process a continuous double of time since simulation start?
For ex, I want to go from the left column to the right column:
ODE time
Calendar Time
0.0
01-01-2021 00:00
0.5
01-01-2021 12:00
1.0
01-02-2021 00:00
etc...
Thank you
I am not fully sure I understand your question. But from your example it appears you want to create timesteps. When I understand it correctly, a "one unit" is a adding 24 hours, while the half day is adding 12 hours. Your data frame example suggest you want to have this in a dataframe/tibble.
With {lubridate} you can "coerce" datetimestamps. There are some handy time formatting functions. From a character you can go to a timestamp.
For example
# create dataframe/tibble of ODE and Calendar times
mydata <- tribble(
~ODE_time, ~Calendar_Time
,0.0 , "01-01-2021 00:00"
,0.5 , "01-01-2021 12:00"
,1.0 , "01-02-2021 00:00"
,1.5 , "01-02-2021 12:00"
)
mydata <- mydata %>%
mutate(time = lubridate::mdy_hm(Calendar_Time))
In your case, I use the mdy_hm() function to make a timestamp (dttm) object.
I assign it to the time variable/column so you can check the presentation in R/RStudio.
What I get from your question is that you want to create a sequence of timestamps.
Here you can use the seq() function and work with the time offset, in your case 12 hours (or half a day). I limit the length out to 10 ... you can obviously define longer sequences or determine your end day (i.e. to parameter of seq())
date_time_seq <- seq( from = lubridate::mdy_hm("01-01-2021 00:00")
,length.out = 10,
,by = "12 hours")
This gives you a sequence of timestamps
date_time_seq
[1] "2021-01-01 00:00:00 UTC" "2021-01-01 12:00:00 UTC" "2021-01-02 00:00:00 UTC"
[4] "2021-01-02 12:00:00 UTC" "2021-01-03 00:00:00 UTC" "2021-01-03 12:00:00 UTC"
[7] "2021-01-04 00:00:00 UTC" "2021-01-04 12:00:00 UTC" "2021-01-05 00:00:00 UTC"
[10] "2021-01-05 12:00:00 UTC"
The syntax allows you to add various "steps" and you can use increments of different time units, e.g. mins, hours, days, weeks, etc.
This timestep vector you can operate in your dataframe/tibble and perform your other operations.
Good luck!
You could directly add the number of seconds to the start date:
ODETime <- seq(0,10,by=0.5)
calendarTime <- as.POSIXct("2021-01-01 00:00") + ODETime * 86400
calendarTime
[1] "2021-01-01 00:00:00 CET" "2021-01-01 12:00:00 CET" "2021-01-02 00:00:00 CET"
[4] "2021-01-02 12:00:00 CET" "2021-01-03 00:00:00 CET" "2021-01-03 12:00:00 CET"
[7] "2021-01-04 00:00:00 CET" "2021-01-04 12:00:00 CET" "2021-01-05 00:00:00 CET"
[10] "2021-01-05 12:00:00 CET" "2021-01-06 00:00:00 CET" "2021-01-06 12:00:00 CET"
[13] "2021-01-07 00:00:00 CET" "2021-01-07 12:00:00 CET" "2021-01-08 00:00:00 CET"
[16] "2021-01-08 12:00:00 CET" "2021-01-09 00:00:00 CET" "2021-01-09 12:00:00 CET"
[19] "2021-01-10 00:00:00 CET" "2021-01-10 12:00:00 CET" "2021-01-11 00:00:00 CET"
or with lubridate:
as.POSIXct("2021-01-01 00:00") + lubridate::period(24,'hour') * ODETime
[1] "2021-01-01 00:00:00 CET" "2021-01-01 12:00:00 CET" "2021-01-02 00:00:00 CET"
[4] "2021-01-02 12:00:00 CET" "2021-01-03 00:00:00 CET" "2021-01-03 12:00:00 CET"
[7] "2021-01-04 00:00:00 CET" "2021-01-04 12:00:00 CET" "2021-01-05 00:00:00 CET"
[10] "2021-01-05 12:00:00 CET" "2021-01-06 00:00:00 CET" "2021-01-06 12:00:00 CET"
[13] "2021-01-07 00:00:00 CET" "2021-01-07 12:00:00 CET" "2021-01-08 00:00:00 CET"
[16] "2021-01-08 12:00:00 CET" "2021-01-09 00:00:00 CET" "2021-01-09 12:00:00 CET"
[19] "2021-01-10 00:00:00 CET" "2021-01-10 12:00:00 CET" "2021-01-11 00:00:00 CET"
I've got some data with POSIXct timestamps in "CET" (Central European Time = Winter time = UTC+0100) and "CEST" (Central European Summer Time = UTC+0200). Since I've had some trouble with plots and calculations because of that daylight savings time, I want all of the timestamps to be in UTC+0100 time.
Here is an example for my timestamps on switch-back-to-winter-time-day:
> tdf$time_posix_vec[1:20]
[1] "2015-10-25 00:00:00 CEST" "2015-10-25 00:15:00 CEST" "2015-10-25 00:30:00 CEST" "2015-10-25 00:45:00 CEST" "2015-10-25 01:00:00 CEST"
[6] "2015-10-25 01:15:00 CEST" "2015-10-25 01:30:00 CEST" "2015-10-25 01:45:00 CEST" "2015-10-25 02:00:00 CEST" "2015-10-25 02:15:00 CEST"
[11] "2015-10-25 02:30:00 CEST" "2015-10-25 02:45:00 CEST" "2015-10-25 02:00:00 CET" "2015-10-25 02:15:00 CET" "2015-10-25 02:30:00 CET"
[16] "2015-10-25 02:45:00 CET" "2015-10-25 03:00:00 CET" "2015-10-25 03:15:00 CET" "2015-10-25 03:30:00 CET" "2015-10-25 03:45:00 CET"
To demonstrate the issue i picked an example timestamp:
> tx <- tdf$time_posix_vec[7]
> tx
[1] "2015-10-25 01:30:00 CEST"
I already tried lubridate's with_tz function, but if I use it with "CET", this is what happens:
> with_tz(tx, tzone = "CET")
[1] "2015-10-25 01:30:00 CEST"
I assume, the timezone handler knows that in my location CET becomes CEST between last week of march and last week of october.
To solve the issue I could use Algeria's timezone, since Algeria uses CET without daylight savings time (as wikipedia told me). However, this could change in the future, and
I wonder if this solution would be a bit unsafe because of that?
> with_tz(tx, tzone = "Africa/Algiers")
[1] "2015-10-25 00:30:00 CET"
The best way, I thought, would be to use "UTC+1", but the behaviour of with_tz is exactly the opposite of what I expected:
> with_tz(tx, tzone = "UTC+1")
[1] "2015-10-24 22:30:00 UTC"
to get 00:30:00 I would have to use:
> with_tz(tx, tzone = "UTC-1")
[1] "2015-10-25 00:30:00 UTC"
but then also the label "UTC" is wrong, because in UTC it would be
> with_tz(tx, tzone = "UTC")
[1] "2015-10-24 23:30:00 UTC"
Why is "UTC+1" switching the timestamp to UTC-0100 instead of UTC+0100?
And is there a function that forces the timestamp to UTC+0100 and also gives puts the correct timezone label to the timestamp, so the result would be "2015-10-25 00:30:00 UTC+1"?
Thanks in advance,
greetings, Peter
I think I found the solution: now I use
t1 <- as.POSIXct("2016-07-12 17:43","Etc/GMT-1")
for example. It confused me that GMT-1 is the same as UTC+0100, they seem to turn around the sign at bsd style timezones.
I have offset time between UTC and local time at different locations as following (+/-HH:MM):
> x
# [1] "+00:00" "+00:00" "-03:00" "+01:00" "+03:00" "+03:00" "+00:00" "+01:00"
# [9] "+00:00" "+00:00" "+02:00" "+01:00" "+02:00" "-02:00" "+00:00" "+01:00"
How can I convert this to a time interval, then use it to shift Sys.Date() using the numbers above?
Another solution using as.difftime (there is a bit of gymnastics to do because it doesn't recognized signed character input):
x <- c("+00:00","+00:00","-03:00","+01:00","+03:00","+03:00","+00:00","+01:00","+00:00","+00:00","+02:00","+01:00","+02:00","-02:00","+00:00","+01:00")
as.difftime(gsub("[+-]","",x), format ="%H:%M") * ifelse(grepl("^-",x),-1,1)
#Time differences in secs
# [1] 0 0 -10800 3600 10800 10800 0 3600 0 0 7200 3600 7200 -7200 0 3600
#attr(,"tzone")
#[1] ""
So to shift from Sys.time(), it's simply:
Sys.time()+as.difftime(gsub("[+-]","",x),format ="%H:%M") * ifelse(grepl("^-",x),-1,1)
#[1] "2015-07-10 10:36:32 CEST" "2015-07-10 10:36:32 CEST" "2015-07-10 07:36:32 CEST" "2015-07-10 11:36:32 CEST" "2015-07-10 13:36:32 CEST" "2015-07-10 13:36:32 CEST" "2015-07-10 10:36:32 CEST"
#[8] "2015-07-10 11:36:32 CEST" "2015-07-10 10:36:32 CEST" "2015-07-10 10:36:32 CEST" "2015-07-10 12:36:32 CEST" "2015-07-10 11:36:32 CEST" "2015-07-10 12:36:32 CEST" "2015-07-10 08:36:32 CEST"
#[15] "2015-07-10 10:36:32 CEST" "2015-07-10 11:36:32 CEST"
If you had your input as numbers, it would be even more straightforward, since it does recognized signed numeric input:
y <- c(-1,2,3,0,-4,-6.5)
Sys.time() + as.difftime(y, units="hours")
# [1] "2015-07-10 09:39:31 CEST" "2015-07-10 12:39:31 CEST" "2015-07-10 13:39:31 CEST" "2015-07-10 10:39:31 CEST" "2015-07-10 06:39:31 CEST" "2015-07-10 04:09:31 CEST"
Here I have a (clumsy) solution, but it works I think. Waiting for more elegant solutions. Steps are, gsub to strings all punctuations and the + sign. convert them all in numeric, divide by 100 in order to have, example -200 as -2, and them pass them all as arguments of the hours function.
library(lubridate)
x1 <- gsub("[:punct:]|\\+", "", x)
x1 <- as.numeric(as.character(x1))
x1 <- x1 / 100
Sys.Date() + hours(x1)
[1] "2015-07-09 00:00:00 UTC" "2015-07-09 00:00:00 UTC"
[3] "2015-07-08 21:00:00 UTC" "2015-07-09 01:00:00 UTC"
[5] "2015-07-09 03:00:00 UTC" "2015-07-09 03:00:00 UTC"
[7] "2015-07-09 00:00:00 UTC" "2015-07-09 01:00:00 UTC"
[9] "2015-07-09 00:00:00 UTC" "2015-07-09 00:00:00 UTC"
[11] "2015-07-09 02:00:00 UTC" "2015-07-09 01:00:00 UTC"
[13] "2015-07-09 02:00:00 UTC" "2015-07-08 22:00:00 UTC"
[15] "2015-07-09 00:00:00 UTC" "2015-07-09 01:00:00 UTC"
data I have used:
x <- c("+00:00", "+00:00", "-03:00", "+01:00", "+03:00", "+03:00", "+00:00", "+01:00",
"+00:00", "+00:00", "+02:00", "+01:00", "+02:00", "-02:00", "+00:00", "+01:00")
Edit: a solution for minutes too
Here the data used is the vector y that contains minutes too.
y <- c("+03:30", "+02:45", "-03:50", "-05:00")
y1 <- unlist(strsplit(y, "[:punct:]"))
y1 <- gsub("\\+", "", y1)
y1 <- as.numeric(as.character(y1))
MinuteS <- y1[1:length(y1) %% 2 == 0]
HourS <- y1[1:length(y1) %% 2 == 1]
Sys.Date() + minutes(MinuteS) + hours(HourS)
[1] "2015-07-09 03:30:00 UTC"
[2] "2015-07-09 02:45:00 UTC"
[3] "2015-07-08 21:50:00 UTC"
[4] "2015-07-08 19:00:00 UTC"
Melting the dataframe t.wide changes how the column "time" (class POSIXct) is printed.
t.wide <- data.frame(product=letters[1:5],
result=c(2, 4, 0, 0, 1),
t1=as.POSIXct("2014-05-26") + seq(0, 10800, length.out=5),
t2=as.POSIXct("2014-05-27") + seq(0, 10800, length.out=5),
t3=as.POSIXct("2014-05-28") + seq(0, 10800, length.out=5))
library(reshape2)
t.long <- melt(t.wide, measure.vars=c("t1", "t2", "t3"), value.name="time")
t.long$time
[1] 1401055200 1401057900 1401060600 1401063300 1401066000 1401141600 1401144300
[8] 1401147000 1401149700 1401152400 1401228000 1401230700 1401233400 1401236100
[15] 1401238800
attr(,"class")
[1] "POSIXct" "POSIXt"
Strangely, if print() is called explicitly, the object is printed as expected (timestamps, not their numeric representation).
print(t.long$time)
[1] "2014-05-26 00:00:00 CEST" "2014-05-26 00:45:00 CEST" "2014-05-26 01:30:00 CEST"
[4] "2014-05-26 02:15:00 CEST" "2014-05-26 03:00:00 CEST" "2014-05-27 00:00:00 CEST"
[7] "2014-05-27 00:45:00 CEST" "2014-05-27 01:30:00 CEST" "2014-05-27 02:15:00 CEST"
[10] "2014-05-27 03:00:00 CEST" "2014-05-28 00:00:00 CEST" "2014-05-28 00:45:00 CEST"
[13] "2014-05-28 01:30:00 CEST" "2014-05-28 02:15:00 CEST" "2014-05-28 03:00:00 CEST"
Setting the attributes to the same value as before magically changes how the object is printed.
attributes(t.long$time) <- attributes(t.long$time)
t.long$time
[1] "2014-05-26 00:00:00 CEST" "2014-05-26 00:45:00 CEST" "2014-05-26 01:30:00 CEST"
[4] "2014-05-26 02:15:00 CEST" "2014-05-26 03:00:00 CEST" "2014-05-27 00:00:00 CEST"
[7] "2014-05-27 00:45:00 CEST" "2014-05-27 01:30:00 CEST" "2014-05-27 02:15:00 CEST"
[10] "2014-05-27 03:00:00 CEST" "2014-05-28 00:00:00 CEST" "2014-05-28 00:45:00 CEST"
[13] "2014-05-28 01:30:00 CEST" "2014-05-28 02:15:00 CEST" "2014-05-28 03:00:00 CEST"
Can anyone explain this behavior?
UPDATE:
I opened this as Issue #50 on the git repo hadley/reshape2.
UPDATE: FIXED
This issue has been fixed in the development version of reshape2.
Thanks #kevin-ushey!
I believe the reason is because after the reshaping for whatever reason R does not think that t.long$time has attributes. For some reason the OBJECT flag (which indicates the vector has attributes) in the SEXP header for your vector is not being set. When you copy the attributes back to it, the OBJECT flag gets set and the correct print method is dispatched...
# No "OBJ" in SEXP header (the '[NAM(2),ATT]' part below)
.Internal(inspect( t.long$time ) )
##10359e548 14 REALSXP g0c6 [NAM(2),ATT] (len=15, tl=0) 1.40106e+09,...
# Now we have "OBJ" in the SEXP header indicating attributes
# So the print method for POSIXct get dispatched...
attributes(t.long$time) <- attributes(t.long$time)
.Internal(inspect( t.long$time ) )
##1118d7f50 14 REALSXP g0c6 [OBJ,NAM(2),ATT] (len=15, tl=0) 1.40106e+09,...
From the R Internals document...
The actual autoprinting is done by PrintValueEnv in file print.c. If the object to be printed has the S4 bit set and S4 methods dispatch is on, show is called to print the object. Otherwise, if the object bit is set (so the object has a "class" attribute), print is called to dispatch methods: for objects without a class the internal code of print.default is called.
Check the difference between..
print.default(t.long$time)
# [1] 1401058800 1401061500 1401064200 1401066900 1401069600 1401145200 1401147900 1401150600 1401153300 1401156000 1401231600 1401234300
#[13] 1401237000 1401239700 1401242400
#attr(,"class")
#[1] "POSIXct" "POSIXt"
print.POSIXct(t.long$time)
# [1] "2014-05-26 00:00:00 BST" "2014-05-26 00:45:00 BST" "2014-05-26 01:30:00 BST" "2014-05-26 02:15:00 BST" "2014-05-26 03:00:00 BST"
# [6] "2014-05-27 00:00:00 BST" "2014-05-27 00:45:00 BST" "2014-05-27 01:30:00 BST" "2014-05-27 02:15:00 BST" "2014-05-27 03:00:00 BST"
#[11] "2014-05-28 00:00:00 BST" "2014-05-28 00:45:00 BST" "2014-05-28 01:30:00 BST" "2014-05-28 02:15:00 BST" "2014-05-28 03:00:00 BST"
Now I can only speculate, but perhaps this is due to some internal code in reshape2 and is related to this warning..
One thing to watch is that if you copy attributes from one object to another you may (un)set the "class" attribute and so need to copy the object and S4 bits as well. There is a macro/function DUPLICATE_ATTRIB to automate this.