I have data provided in the form of a date telling the day (format "YYYY-MM-DD", e.g. "2015-03-11" and the hours of the day numbered (0-23).
What is the most convenient way to produce time objects of the form
"2015-03-11" and hour = 0 -> "2015-03-11 00:00"
"2015-03-11" and hour = 1 -> "2015-03-11 01:00"
"2015-03-11" and hour = 2 -> "2015-03-11 02:00"
I could use the Date function from Base or something from xts or timeDate.
Should be easy but I am sure someone out there knows it quickly.
EDIT: the data is provided in 2 columns, one for the date and one numerical.
You don't need an external package to do that.
If your data is in this format:
df=data.frame(date=c("2015-03-11","2015-03-11","2015-03-11"),hour=0:2)
just apply the following function:
format(as.POSIXct(df$date)+df$hour*60*60, format = "%Y-%m-%d %H:%M")
Suppose we have this input:
date <- c("2015-03-11", "2015-03-12")
hour <- 2:3
then try one of these:
1) chron
library(chron)
as.chron(date) + hour/24
giving:
[1] (03/11/15 02:00:00) (03/12/15 03:00:00)
2) POSIXct. This one only uses the base of R, no packages:
as.POSIXct(date) + 3600 * hour
giving, on my system:
[1] "2015-03-11 02:00:00 EDT" "2015-03-12 03:00:00 EDT"
If you wanted the result in the UTC time zone use:
as.POSIXct(date, tz = "UTC") + 3600 * hour
3) lubridate
library(lubridate)
ymd(date) + hours(hour)
giving:
[1] "2015-03-11 02:00:00 UTC" "2015-03-12 03:00:00 UTC"
If you want it in the current time zone then:
ymd(date, tz = "") + hours(hour)
Note that the chron solution gives a date/time class that does not use time zones eliminating the many problems that time zones can cause. The POSIXct and lubridate solutions give the date/time in a specific time zone as shown.
You could try
dtime <- with(df, as.POSIXct(sprintf('%s %02d', date, hour),
format = "%Y-%m-%d %H"))
and then use format as in the other posts
Or
library(lubridate)
ymd_h(with(df, sprintf('%s %02d', date, hour)))
Or slightly more compact
ymd_h(do.call(paste, df))
Try this. You can format it without seconds afterwards using format if you wish, though I think it is preferable to keep it in POSIXct class so you can manipulate it afterwords (adding removing days, seconds, etc.)
as.POSIXct(do.call(paste, df), format = "%Y-%m-%d %H")
## [1] "2015-03-11 00:00:00 IST" "2015-03-11 01:00:00 IST" "2015-03-11 02:00:00 IST"
Though, If you insist on your exact output, here's the solution with format
format(as.POSIXct(do.call(paste, df), format = "%Y-%m-%d %H"), "%Y-%m-%d %H:%M")
## [1] "2015-03-11 00:00" "2015-03-11 01:00" "2015-03-11 02:00"
Data
df <- structure(list(V1 = structure(c(1L, 1L, 1L), .Label = "2015-03-11", class = "factor"),
V2 = 0:2), .Names = c("V1", "V2"), class = "data.frame", row.names = c(NA,
-3L))
Related
I have a variable for the date of medical admission. However, it is not properly formatted. It is a factor and formatted as "DDMMYEAR HRMN", like "01012016 1215", which should mean "01-01-2016 12:15". How can I reformat it and assign weekdays?
You can use lubridate to parse the date, then weekdays from base R to get the day of week as a character.
library(lubridate)
d <- dmy_hm("01012016 1215")
weekdays(d)
Use as.POSIXct/strptime to convert to date time and then use weekdays.
df$date <- as.POSIXct(df$date, format = '%d%m%Y %H%M', tz = 'UTC')
df$weekday <- weekdays(df$date)
For example,
string <- '01012016 1215'
date <- as.POSIXct(string, format = '%d%m%Y %H%M', tz = 'UTC')
date
#[1] "2016-01-01 12:15:00 UTC"
weekdays(date)
#[1] "Friday"
I have data value
dput(a)
"1/3/2019 15:59"
I need to round the time to to the next hour. I need this date to be "1/3/2019 16:00"?
How can I do this?
We can use lubridate dmy_hm to convert to datetime object and then use ceiling_date to convert it to next hour.
library(lubridate)
ceiling_date(dmy_hm("1/3/2019 15:59"), "hour")
#[1] "2019-03-01 16:00:00 UTC"
Use round.POSIXt. No packages are used.
x <- as.POSIXct("1/3/2019 15:59", format = "%m/%d/%Y %H:%M")
round(x + 3600/2 - !(as.numeric(x) %% 3600), "hours")
## [1] "2019-01-03 16:00:00 EST"
If this question has been asked before, please downvote and direct me. I have been looking through SO, but it seems no one has had the need for a non-midnight start time i.e. everyone wants to know how to convert seconds from a specific midnight value.
I'm trying to convert my second values to a data value. What I have are seconds from the time 2017-05-21 22:00.
I tried using the as.POSIXct() function, however it only seem to take Y-m-d into account and disregards if I write h:m after it.
e.g file$date = as.POSIXct(file$Time,origin = "2017-05-21 22:00") gives me
Time date
1 0.00 2017-05-22 00:00:00
I have found if I use
file$Time = file$Time-3600*4
file$date = as.POSIXct(file$Time,origin = "2017-05-22")
for some reason gives me the correct output which is of course
Time date
1 0.00 2017-05-21 22:00:00
Any idea on how to do this more elegantly?
Also, if you have a clue on why that gives me the correct output, I'm all ears.
You can simply try as.POSIXct to convert your starting time and then keep on adding seconds. as:
as.POSIXct("2017-05-21 22:00:00", format = "%Y-%m-%d %H:%M:%S")
#[1] "2017-05-21 22:00:00 BST"
as.POSIXct("2017-05-21 22:00:00", format = "%Y-%m-%d %H:%M:%S") + 1
#[1] "2017-05-21 22:00:01 BST"
as.POSIXct("2017-05-21 22:00:00", format = "%Y-%m-%d %H:%M:%S") + 100
#[1] "2017-05-21 22:01:40 BST"
as.POSIXct("2017-05-21 22:00:00", format = "%Y-%m-%d %H:%M:%S") + 300
#[1] "2017-05-21 22:05:00 BST
You can even specify time-zone using tz parameter as:
as.POSIXct("2017-05-21 22:00:00", tz = "UTC", format = "%Y-%m-%d %H:%M:%S")
#[1] "2017-05-21 22:00:00 UTC"
as.POSIXct("2017-05-21 22:00:00", tz = "UTC", format = "%Y-%m-%d %H:%M:%S") + 96
#[1] "2017-05-21 22:01:36 UTC"
Have a look at lubridate...
library(lubridate)
ymd_hm("2017-05-21 22:00") + seconds(1.01)
So in your case it would be something like
file$date <- ymd_hm("2017-05-21 22:00") + seconds(file$Time)
I have this data frame which gives me Date and Time columns. I am trying to combine these 2 columns but strptime is returning NA. i want to understand why is it happening?
x <- data.frame(date = "1/2/2007", time = "00:00:02")
y <- strptime(paste(x$date,x$time,sep = " "), format = "%b/%d/%y %H:%M:%S")
We need %m and %Y in place of %b and %y (%b - Abbreviated month name in the current locale on this platform. %y - Year without century (00–99)).
strptime(paste(x$date,x$time,sep = " "), "%m/%d/%Y %H:%M:%S")
#[1] "2007-01-02 00:00:02 IST"
For understanding the format, it is better to check ?strptime
Or we can use mdy_hms from lubridate
library(lubridate)
with(x, mdy_hms(paste(date, time)))
#[1] "2007-01-02 00:00:02 UTC"
Hi I have a character vector (rr) that is several million in length, and it represents time and date stamps in the format %Y-%m-%d %H:%M:%S recorded in Australia/Sydney.
How do get a POSIXct object (quickly) that represents this.
I have found fastPOSIXct in the fasttime package, but for this to be accurate, it requires the original character string to be in GMT/UTC, (which mine is not) and then converted back into the correct timezone using the tz arguement...
> head(rr)
[1] "2009-05-01 10:01:00" "2009-05-01 10:02:00" "2009-05-01 10:03:00" "2009-05-01 10:04:00"
[5] "2009-05-01 10:05:00" "2009-05-01 10:06:00"
> as.POSIXct(head(rr),tz="Australia/Sydney")
[1] "2009-05-01 10:01:00 EST" "2009-05-01 10:02:00 EST" "2009-05-01 10:03:00 EST"
[4] "2009-05-01 10:04:00 EST" "2009-05-01 10:05:00 EST" "2009-05-01 10:06:00 EST"
The above line takes ages if doing it on the full set of data...so any speed improvements would be appreciated. Thanks.
Inspired by Dirk's answer to this qn, I made this wrapper for handling a whole bunch of dates across the year:
fastPOSIXct_generic <- function(x, mytz = "America/New_York")
{
# Caution, read: ?DateTimeClasses
stopifnot(is.character(x))
times_UTC <- fastPOSIXct(x, tz='UTC')
num_times <- as.numeric(times_UTC)
t1 <- as.POSIXct(x[1], tz = mytz)
t2 <- as.POSIXct(x[1], tz = "UTC")
offset <- as.numeric(difftime(t1, t2, units = "secs"))
daylightoffset <- as.POSIXlt(t1)$isdst
# For this first 'time' in t1 and t2, remove possible impact of losing one hour by setting clocks one hour forward during summer months:
offset <- offset + daylightoffset * 3600
num_times <- num_times + offset
new_num_times <- as.POSIXct(num_times, tz = mytz, origin = '1970-01-01')
new_num_times2 <- new_num_times - as.POSIXlt(new_num_times)$isdst * 3600
return(new_num_times2)
}
# Test Sydney time
mm <- as.POSIXct(c("2015-03-15 15:00:00", "2015-4-10 15:00:00", "2014-10-01 15:00:00", "2015-10-15 15:00:00"), tz = "Australia/Sydney")
# "2015-03-15 15:00:00 AEDT" "2015-04-10 15:00:00 AEST" "2014-10-01 15:00:00 AEST" "2015-10-15 15:00:00 AEDT"
aus_stamps <- as.character(mm)
aus_back <- fastPOSIXct_generic(x = aus_stamps, mytz = "Australia/Sydney")
#"2015-03-15 15:00:00 AEDT" "2015-04-10 15:00:00 AEST" "2014-10-01 15:00:00 AEST" "2015-10-15 15:00:00 AEDT"
identical(mm, aus_back)
# TRUE
My use cases are nearly always UTC to America/New_York, where so far it has seemed to work fine. I don't know whether it works correctly for other time zones; just the cases where dst has time go forward an hour.
Here is one approach:
i) Lie to fasttime() and pretend the data was UTC, use to parse the data into a vector x
ii) Compute an offset to UTC using your first data point:
R> d1 <- "2009-05-01 10:01:01" ## or use `head(rr,1)`
R> t1 <- as.POSIXct(d1,tz="Australia/Sydney")
R> t2 <- as.POSIXct(d1,tz="UTC")
R> offset <- as.numeric(difftime(t2, t1, units="secs"))
R> offset
[1] 36000
iii) Apply the offset value to your data -- that is a quick addition as POSIXct really is a numeric type with (fractional) seconds (since epoch) as its unit.