Changing dates in different time zones by adding to POSIXlt - r

I am running into an error when I try to localize times for "date" (a variable of class=POSIXlt) in my dataset. Example code is as follows:
# All dates are coded by survey software in EST(not local time)
date <- c("2011-07-26 07:23", "2011-07-29 07:34", "2011-07-29 07:40")
region <-c("USA-EST", "UK", "Singapore")
#Change the times based on time-zone differences
start_time<-strptime(date,"%Y-%m-%d %h:%m")
localtime=as.POSIXlt(start_time)
localtime<-ifelse(region=="UK",start_time+6,start_time)
localtime<-ifelse(region=="Singapore",start_time+12,start_time)
#Then, I need to extract the hour and weekday
weekday<-weekdays(localtime)
hour<-factor(localtime)
There must be something wrong with my "ifelse" statement, because I get the error: number of items to replace is not a multiple of replacement length. Please help!

How about using R's native time code? The trick is that you can't have more than one time-zone in a POSIX vector, so use a list instead:
region <- c("EST","Europe/London","Asia/Singapore")
(localtime <- lapply(seq(date),function(x) as.POSIXlt(date[x],tz=region[x])))
[[1]]
[1] "2011-07-26 07:23:00 EST"
[[2]]
[1] "2011-07-29 07:34:00 Europe/London"
[[3]]
[1] "2011-07-29 07:40:00 Asia/Singapore"
And to convert to a vector in a single timezone:
Reduce("c",localtime)
[1] "2011-07-26 13:23:00 BST" "2011-07-29 07:34:00 BST"
[3] "2011-07-29 00:40:00 BST"
Note that my system timezone is BST, but if yours is EST it will convert to that.

You can use the timezone handling built in in POSIXct:
> start_time <- as.POSIXct(date,"%Y-%m-%d %H:%M", tz = "America/New_York")
> start_time
[1] "2011-07-26 07:23:00 EDT" "2011-07-29 07:34:00 EDT" "2011-07-29 07:40:00 EDT"
> format(start_time, tz="Europe/London", usetz=TRUE)
[1] "2011-07-26 12:23:00 BST" "2011-07-29 12:34:00 BST" "2011-07-29 12:40:00 BST"
> format(start_time, tz="Asia/Singapore", usetz=TRUE)
[1] "2011-07-26 19:23:00 SGT" "2011-07-29 19:34:00 SGT" "2011-07-29 19:40:00 SGT"

Related

convert integer to date and time in R

I have an int column with values like 30, 2230, 130 is there any function that I could convert them in time format like 30 to 00:30 and 130 to 01:30? I used:
format(strftime(col,format="%H:%M"), format="%H:%M")
but it returned an error:
as.POSIXlt(x, tz=tz)::'origin' must be supplied
I also need to add yy-mm-dd in before the time after the time conversion so the ultimate output could like "1980-05-28 00:30", " 1980-05-28 22:30", and " 1980-05-28 01:30".
Can anyone help?
You can try using as.POSIXct and sprintf along with paste to create date/time:
as.POSIXct(paste("1980-05-28", sprintf("%04d",c(130, 2030, 1120, 30,0120)),sep = " "),
format = "%Y-%m-%d %H%M")
# [1] "1980-05-28 01:30:00 BST" "1980-05-28 20:30:00 BST" "1980-05-28 11:20:00 BST"
# [4] "1980-05-28 00:30:00 BST" "1980-05-28 01:20:00 BST"
Note: The solution is something similar to what suggested by #r2evans. I tried to simplify it a bit.

Best way to deal with differing date data [duplicate]

I am trying to do some simple operation in R, after loading a table i encountered a date column which has many formats combined.
**Date**
1/28/14 6:43 PM
1/29/14 4:10 PM
1/30/14 12:09 PM
1/30/14 12:12 PM
02-03-14 19:49
02-03-14 20:03
02-05-14 14:33
I need to convert this to format like 28-01-2014 18:43 i.e. %d-%m-%y %h:%m
I tried this
tablename$Date <- as.Date(as.character(tablename$Date), "%d-%m-%y %h:%m")
but doing this its filling NA in the entire column. Please help me to get this right!
The lubridate package makes quick work of this:
library(lubridate)
d <- parse_date_time(dates, names(guess_formats(dates, c("mdy HM", "mdy IMp"))))
d
## [1] "2014-01-28 18:43:00 UTC" "2014-01-29 16:10:00 UTC"
## [3] "2014-01-30 12:09:00 UTC" "2014-01-30 12:12:00 UTC"
## [5] "2014-02-03 19:49:00 UTC" "2014-02-03 20:03:00 UTC"
## [7] "2014-02-05 14:33:00 UTC"
# put in desired format
format(d, "%m-%d-%Y %H:%M:%S")
## [1] "01-28-2014 18:43:00" "01-29-2014 16:10:00" "01-30-2014 12:09:00"
## [4] "01-30-2014 12:12:00" "02-03-2014 19:49:00" "02-03-2014 20:03:00"
## [7] "02-05-2014 14:33:00"
You'll need to adjust the vector in guess_formats if you come across other format variations.

How to create a range of dates in R

From two integers (1, 5) one can create a range in the following way
1:5
[1] 1 2 3 4 5
How can you make a range of dates if you are give two dates ("2014-09-04 JST", "2014-09-11 JST")
The output must be
[1] ("2014-09-04 JST", "2014-09-05 JST", "2014-09-06 JST", "2014-09-07 JST", "2014-09-08 JST")
Does this help?
seq(as.Date("2014/09/04"), by = "day", length.out = 5)
# [1] "2014-09-04" "2014-09-05" "2014-09-06" "2014-09-07" "2014-09-08"
edit: adding in something about timezones
this works for my current timezone
seq(c(ISOdate(2014,4,9)), by = "DSTday", length.out = 5)
#[1] "2014-04-09 08:00:00 EDT" "2014-04-10 08:00:00 EDT" "2014-04-11 08:00:00 EDT" "2014-04-12 08:00:00 EDT"
#[5] "2014-04-13 08:00:00 EDT"
edit2:
OlsonNames() # I used this to find out what to write for the JST tz - it's "Japan"
x <- as.POSIXct("2014-09-04 23:59:59", tz="Japan")
format(seq(x, by="day", length.out=5), "%Y-%m-%d %Z")
# [1] "2014-09-04 JST" "2014-09-05 JST" "2014-09-06 JST" "2014-09-07 JST" "2014-09-08 JST"
To get a sequence of dates ( days, weeks,.. ) using only start and end dates you can use:
seq(as.Date("2014/1/1"), as.Date("2014/1/10"), "days”)
[1] "2014-01-01" "2014-01-02" "2014-01-03" "2014-01-04" "2014-01-05" "2014-01-06" "2014-01-07"
[8] "2014-01-08" "2014-01-09" "2014-01-10”
Here's an answer, admittedly worse than #jalapic's, that doesn't use seq and instead uses a for loop:
date1 <- "2014-09-04"
date2 <- "2014-09-11"
dif <- as.numeric(abs(as.Date(date1) - as.Date(date2)))
dates <- vector()
for (i in 1:dif) {
date <- (as.Date(date1) + i)
dates <- append(dates, date)
}
# [1] "2014-09-05" "2014-09-06" "2014-09-07" "2014-09-08" "2014-09-09" "2014-09-10" "2014-09-11
here's a shot though the timezone JST isn't recognized by my system
d1<-ISOdate(year=2014,month=9,day=4,tz="GMT")
seq(from=d1,by="day",length.out=5)
[1] "2014-09-04 12:00:00 GMT" "2014-09-05 12:00:00 GMT" "2014-09-06 12:00:00 GMT" "2014-09-07 12:00:00 GMT" "2014-09-08 12:00:00 GMT"
While using seq(date1, date2, "days") is by far the better option in nearly all cases, I'd just like to add, that the following works too, if you need a range of dates that are n_number of days from a date:
1:10 + as.Date("2020-01-01")
# [1] "2020-01-02" "2020-01-03" "2020-01-04" "2020-01-05"
# [5] "2020-01-06" "2020-01-07" "2020-01-08" "2020-01-09"
# [9] "2020-01-10" "2020-01-11"

Round a POSIX date (POSIXct) with base R functionality

I'm currently playing around a lot with dates and times for a package I'm building.
Stumbling across this post reminded me again that it's generally not a bad idea to check out if something can be done with basic R features before turning to contrib packages.
Thus, is it possible to round a date of class POSIXct with base R functionality?
I checked
methods(round)
which "only" gave me
[1] round.Date round.timeDate*
Non-visible functions are asterisked
This is what I'd like to do (Pseudo Code)
x <- as.POSIXct(Sys.time())
[1] "2012-07-04 10:33:55 CEST"
round(x, atom="minute")
[1] "2012-07-04 10:34:00 CEST"
round(x, atom="hour")
[1] "2012-07-04 11:00:00 CEST"
round(x, atom="day")
[1] "2012-07-04 CEST"
I know this can be done with timeDate, lubridate etc., but I'd like to keep package dependencies down. So before going ahead and checking out the source code of the respective packages, I thought I'd ask if someone has already done something like this.
base has round.POSIXt to do this. Not sure why it doesn't come up with methods.
x <- as.POSIXct(Sys.time())
x
[1] "2012-07-04 10:01:08 BST"
round(x,"mins")
[1] "2012-07-04 10:01:00 BST"
round(x,"hours")
[1] "2012-07-04 10:00:00 BST"
round(x,"days")
[1] "2012-07-04"
On this theme with lubridate, also look into the ceiling_date() and floor_date() functions:
x <- as.POSIXct("2009-08-03 12:01:59.23")
ceiling_date(x, "second")
# "2009-08-03 12:02:00 CDT"
ceiling_date(x, "hour")
# "2009-08-03 13:00:00 CDT"
ceiling_date(x, "day")
# "2009-08-04 CDT"
ceiling_date(x, "week")
# "2009-08-09 CDT"
ceiling_date(x, "month")
# "2009-09-01 CDT"
If you don't want to call external libraries and want to keep POSIXct as I do this is one idea (inspired by this question): use strptime and paste a fake month and day. It should be possible to do it more straight forward, as said in this comment
"For strptime the input string need not specify the date completely:
it is assumed that unspecified seconds, minutes or hours are zero, and
an unspecified year, month or day is the current one."
Thus it seems that you have to use strftime to output a truncated string, paste the missing part and convert again in POSIXct.
This is how an update answer could look:
x <- as.POSIXct(Sys.time())
x
[1] "2018-12-27 10:58:51 CET"
round(x,"mins")
[1] "2018-12-27 10:59:00 CET"
round(x,"hours")
[1] "2018-12-27 11:00:00 CET"
round(x,"days")
[1] "2018-12-27 CET"
as.POSIXct(paste0(strftime(x,format="%Y-%m"),"-01")) #trunc by month
[1] "2018-12-01 CET"
as.POSIXct(paste0(strftime(x,format="%Y"),"-01-01")) #trunc by year
[1] "2018-01-01 CET"

R converting POSIXct dates with BST/GMT tags using as.Date()

I need to use as.Date on the index of a zoo object. Some of the dates are in BST and so when converting I lose a day on (only) these entries. I don't care about one hour's difference or even the time part of the date at all, I just want to make sure that the dates displayed stay the same. I'm guessing this is not very hard but I can't manage it. Can somebody help please?
class(xtsRet)
#[1] "xts" "zoo"
index(xtsRet)
#[1] "2007-07-31 BST" "2007-08-31 BST" "2007-09-30 BST" "2007-10-31 GMT"
class(index(xtsRet))
#[1] "POSIXt" "POSIXct"
index(xtsRet) <- as.Date(index(xtsRet))
index(xtsRet)
#[1] "2007-07-30" "2007-08-30" "2007-09-29" "2007-10-31"
Minimally reproducible example (not requiring zoo package):
my_date <- as.POSIXct("2007-04-01") # Users in non-UK timezone will need to
# do as.POSIXct("2007-04-01", "Europe/London")
my_date
#[1] "2017-04-01 BST"
as.Date(my_date)
#[1] "2017-03-31"
Suppose we have this sample data:
library(zoo)
x <- as.POSIXct("2000-01-01", tz = "GMT")
Then see if any of these are what you want:
# use current time zone
as.Date(as.character(x, tz = ""))
# use GMT
as.Date(as.character(x, tz = "GMT"))
# set entire session to GMT
Sys.setenv(TZ = "GMT")
as.Date(x)
Also try "BST" in place of "GMT" and note the article on dates and times in R News 4/1 .
You can offset the POSIX objects so its not based around midnight. 1 hour (3600 secs) should be sufficient:
d <- as.POSIXct(c("2007-07-31","2007-08-31","2007-09-30","2007-10-31"))
d
[1] "2007-07-31 BST" "2007-08-31 BST" "2007-09-30 BST" "2007-10-31 GMT"
as.Date(d)
[1] "2007-07-30" "2007-08-30" "2007-09-29" "2007-10-31"
as.Date(d+3600)
[1] "2007-07-31" "2007-08-31" "2007-09-30" "2007-10-31"
I would suggest using as.POSIXlt to convert to a date object, wrapped in as.Date:
d <- as.POSIXct(c("2007-07-31","2007-08-31","2007-09-30","2007-10-31"))
d
[1] "2007-07-31 BST" "2007-08-31 BST" "2007-09-30 BST" "2007-10-31 GMT"
as.Date(as.POSIXlt(d))
[1] "2007-07-31" "2007-08-31" "2007-09-30" "2007-10-31"
Achieves the same thing as the +3600 above, but slightly less of a hack

Resources