I have data for more than 3 years. For each year I want to find the day corresponding to Jaunary 1 of that year. For example:
> x <- c('5/5/2007','12/31/2007','1/2/2008')
> #Convert to day of year (julian date) –
> strptime(x,"%m/%d/%Y")$yday+1
[1] 125 365 2
I want to know how to do the same thing but with time added. But I still get the day not time. Can anyone suggest what is the better way to find the julian date with date and time ?
> x1 <- c('5/5/2007 02:00','12/31/2007 05:58','1/2/2008 16:25')
> #Convert to day of year (julian date) –
> strptime(x1,"%m/%d/%Y %H:%M")$yday+1
[1] 125 365 2
Rather than this result, I want the output in decimal days. For example the first example would be 125.0833333 and so on.
Thank you so much.
Are you hoping to get the day + a numerical part of a day as output? If so, something like this will work:
test <- strptime(x1,"%m/%d/%Y %H:%M")
(test$yday+1) + (test$hour/24) + (test$min/(24*60))
#[1] 125.083333 365.248611 2.684028
Although this matches what you ask for, I think removing the +1 might make more sense:
(test$yday) + (test$hour/24) + (test$min/(24*60))
#[1] 124.083333 364.248611 1.684028
Though my spidey senses are tingling that Dirk is going to show up and show me how to do this with a POSIXct date/time representation.
Here is an attempt of such an answer using base functions:
mapply(julian, as.POSIXct(test), paste(format(test,"%Y"),"01","01",sep="-"))
#[1] 124.083333 364.248611 1.684028
You can also use POSIXct and POSIXlt representations along with firstof function from xts.
x1 <- c("5/5/2007 02:00", "12/31/2007 05:58", "1/2/2008 16:25")
x1
## [1] "5/5/2007 02:00" "12/31/2007 05:58" "1/2/2008 16:25"
y <- as.POSIXlt(x1, format = "%m/%d/%Y %H:%M")
result <- mapply(julian, x = as.POSIXct(y), origin = firstof(y$year + 1900))
result
## [1] 124.083333 364.248611 1.684028
if you don't want to use xts then perhaps something like this
result <- mapply(julian,
x = as.POSIXct(x1, format = "%m/%d/%Y %H:%M", tz = "GMT"),
origin = as.Date(paste0(gsub(".*([0-9]{4}).*", "\\1", x1),
"-01-01"),
tz = "GMT"))
result
## [1] 124.083333 364.248611 1.684028
If you want to do the other way around (convert day of the year to date and time), you can use this little function:
doy2date = function(mydoy){
mydate = as.Date(mydoy, origin = "2008-01-01 00:00:00", tz = "GMT")
dech = (mydoy - as.integer(mydoy)) * 24
myh = as.integer(dech)
mym = as.integer( (dech - as.integer(dech)) * 60)
mys = round(I( (((dech - as.integer(dech)) * 60) - mym) * 60), digits=0 )
posixdate = as.POSIXct(paste(mydate, " ", myh,":",mym,":",mys, sep=""), tz = "GMT")
return(posixdate)
}
As an example, if you try:
doy2date(117.6364)
The function will return "2008-04-27 15:16:25 GMT" as a POSIXct.
Related
I am trying to convert numeric values into times and dates. I am working with a data set so it would be appreciated if you should show an example using a dataset.
Here are some examples, converting 93537 into 09:35:57 (HH:MM:SS). Additionally, I need to convert 220703 into 22-07-03 (YY:MM:DD).
I will add an example of my code below:
CPLF_data$HMS <- substr(as.POSIXct(sprintf("%04.0f", CPLF_data$StartTime), format='%H%M%S'), 12, 16)
CPLF_data$YMD <- as.POSIXct(CPLF_data$Date, tz="UTC", origin ="1970-01-01", format ="%Y-%M-%D")
The first line is correct however, it does not show seconds.
The second line is incorrect.
Thank you.
I want my final product to be a new column with the times and dates in the correct format with their own columns.
Use chron times class to get the times or if a character string is wanted use as.character on that. Use as.Date to get a Date class object. The sub puts colons between the parts of the time after which we can convert it to times class. The sprintf pads the date with 0 on the left if it is only 5 characters and otherwise leaves it as 6 characters and then we convert that to Date class.
library(chron)
time <- 93537
date <- 220703
tt <- times(sub("(..)(..)$", ":\\1:\\2", time))
tt
## [1] "09:35:37"
as.character(tt)
## [1] "09:35:37"
dd <- as.Date(sprintf("%06d", date), "%y%m%d")
dd
## [1] "2022-07-03"
as.character(dd)
## [1] "2022-07-03"
Try the ymd_hms function in the lubridate package.
output$datetime <- ymd_hms(paste(input$year, input$month, input$day,
input$HH, input$MM, input$SS, sep="-"))
You can enter 00 if you don't have seconds, for example ....
Base R does not have a class for just "time" (of day), as.POSIXct doesn't deal with "times", it deals with "date-times". The lubridate:: package does give number-like HMS values, which may be relevant, but since each row has both date and time, it seems relevant to combine them instead of putting them into separate columns.
CPLF_data |>
transform(
StartTime = as.numeric(StartTime),
Date = as.numeric(Date)
) |>
transform(
DateTime = ISOdate(
2000 + Date %/% 10000, (Date %% 10000) %/% 100, Date %% 100,
StartTime %/% 10000, (StartTime %% 10000) %/% 100, StartTime %% 100)
)
# StartTime Date DateTime
# 1 93537 220703 2022-07-03 09:35:37
Note: I'm assuming that all years are 2-digits and at/after 2000. If this is not true, it's not difficult to work around it with some custom code. Also, over to you if you want to set the timezone of this timestamp by adding tz="US/Mountain" or whichever is more appropriate for the data.
Data
CPLF_data <- data.frame(StartTime = "93537", Date = "220703")
so I'm trying to convert a F1 Laptime that is written in a chr in to time which I can then plot into a histogram.
This is what i tried. But with no success.
lapTimes <- lapTimes %>% mutate(Time = ms(Time))
format(as.POSIXct(lapTimes$time, tz = ""), format = "%M:%S.%OS")
The time always looks like this 1:11.111, with minutes first then secunds and then milliseconds.
If anyone has a idea I would greatly apprichiate that.
Thanks in advance! :D
As stated previously, I am assuming your data looks something like this:
laptime <- c("1:11.111", "2:02.2222")
What this represents is a time interval not a date time. As such you can convert this to a difftime class and then to numeric if needed.
as.difftime(laptime, format = "%M:%S.%OS")
#Time differences in mins
#[1] 1.183333 2.033333
since you provided no example data, I assumed it is stored as a character.
laptime <- "1:11.111"
> as.POSIXlt.character(laptime, format = "%M:%S.%OS", tz = 'GMT')
[1] "2021-01-14 00:01:11 GMT"
# compute time difference from dates
laptime <- "1:11.111"
t2 <- as.POSIXlt.character(laptime, format = "%M:%S.%OS", tz = 'GMT')
t1 <- as.Date(t2)
> difftime(t2, t1)
Time difference of 1.183333 mins
You could also take a look at this link, looks very useful for your specific problem: https://rstudio-pubs-static.s3.amazonaws.com/276999_042092be8e31414f82ef4f41e31fe5c8.html
I am just learning R and have come up against this.
I have the below time series observations,
10/08/2015 02:31:04.450
I want to split the date and the time to separate columns.
Do i need need to round the Milliseconds in time? if so how.
I have been looking at, data table, lubridate to try and figure it out. I looked at XTS but that seems to be more orientated to aggregation of dates.
Are they any existing packages in R that allows for this splitting? and what sort of argument would I use.
Any help would be much appreciated.
Using data.table it is very straight forward:
require(data.table)
x <- "10/08/2015 02:31:04.450"
IDateTime(strptime(x, "%d/%m/%Y %H:%M:%OS"))
gives you the following data.table
idate itime
1: 2015-08-10 02:31:04
x <- "10/08/2015 02:31:04.450"
temp <- strptime(x, "%d/%m/%Y %H:%M:%OS")
format(temp,"%H:%M:%S")
#[1] "02:31:04"
as.Date(temp)
#[1] "2015-08-10"
If you do not need the time part in character form you can add few steps
x <- "10/08/2015 02:31:04.450"
temp <- strptime(x, "%d/%m/%Y %H:%M:%OS")
library(chron)
chron(times = format(temp,"%H:%M:%S"))
#[1] 02:31:04
class(chron(times = format(temp,"%H:%M:%S")))
#[1] "times"
as.Date(temp)
# [1] "2015-08-10"
string_timeStamp = "10/08/2015 02:31:04.450"
parsed_timeStamp = strptime(string_timeStamp, "%d/%m/%Y %H:%M:%OS")
date_time_dataFrame = data.frame(date = cut(parsed_timeStamp, breaks = "days"),
time = format(parsed_timeStamp, "%H:%M:%OS" ))
For more formatting options, check ?strptime
Suppose I have the following data.frame foo
start.time duration
1 2012-02-06 15:47:00 1
2 2012-02-06 15:02:00 2
3 2012-02-22 10:08:00 3
4 2012-02-22 09:32:00 4
5 2012-03-21 13:47:00 5
And class(foo$start.time) returns
[1] "POSIXct" "POSIXt"
I'd like to create a plot of foo$duration v. foo$start.time. In my scenario, I'm only interested in the time of day rather than the actual day of the year. How does one go about extracting the time of day as hours:seconds from POSIXct class of vector?
This is a good question, and highlights some of the difficulty in dealing with dates in R. The lubridate package is very handy, so below I present two approaches, one using base (as suggested by #RJ-) and the other using lubridate.
Recreate the (first two rows of) the dataframe in the original post:
foo <- data.frame(start.time = c("2012-02-06 15:47:00",
"2012-02-06 15:02:00",
"2012-02-22 10:08:00"),
duration = c(1,2,3))
Convert to POSIXct and POSIXt class (two ways to do this)
# using base::strptime
t.str <- strptime(foo$start.time, "%Y-%m-%d %H:%M:%S")
# using lubridate::ymd_hms
library(lubridate)
t.lub <- ymd_hms(foo$start.time)
Now, extract time as decimal hours
# using base::format
h.str <- as.numeric(format(t.str, "%H")) +
as.numeric(format(t.str, "%M"))/60
# using lubridate::hour and lubridate::minute
h.lub <- hour(t.lub) + minute(t.lub)/60
Demonstrate that these approaches are equal:
identical(h.str, h.lub)
Then choose one of above approaches to assign decimal hour to foo$hr:
foo$hr <- h.str
# If you prefer, the choice can be made at random:
foo$hr <- if(runif(1) > 0.5){ h.str } else { h.lub }
then plot using the ggplot2 package:
library(ggplot2)
qplot(foo$hr, foo$duration) +
scale_x_datetime(labels = "%S:00")
You could rely on base R:
# Using R 2.14.2
# The same toy data
foo <- data.frame(start.time = c("2012-02-06 15:47:00",
"2012-02-06 15:02:00",
"2012-02-22 10:08:00"),
duration = c(1,2,3))
Since class POSIXct contains date-time information in a structured manner, you can rely on substr to extract the characters in time positions within the POSIXct vector. That is, given you know the format of your POSIXct (how it would be presented when printed), you can extract hours and minutes:
# Extract hour and minute as a character vector, of the form "%H:%M"
substr(foo$start.time, 12, 16)
And then paste it to an arbitrary date to convert it back to POSIXct. In the example I use January first 2012, but if you don't specify a date and instead use format R uses the current date.
# Store time information as POSIXct, using an arbitrary date
foo$time <- as.POSIXct(paste("2012-01-01", substr(foo$start.time, 12, 16)))
And both plot and ggplot2 know how to format times in POSIXct out of the box.
# Plot it using base graphics
plot(duration~time, data=foo)
# Plot it using ggplot2 (0.9.2.1)
library(ggplot2)
qplot(x=time, y=duration, data=foo)
Lubridate doesn't handle time of day data, so Hadley recommends the hms package for this type of data. Something like this would work:
library(lubridate)
foo <- data.frame(start.time = parse_datetime(c("2012-02-06 15:47:00",
"2012-02-06 15:02:00",
"2012-02-22 10:08:00")),
duration = c(1,2,3))
foo<-foo %>% mutate(time_of_day=hms::hms(second(start.time),minute(start.time),hour(start.time)))
Watch out for 2 potential issues - 1) lubridate has a different function called hms and 2) hms::hms takes the arguments in the opposite order to that suggested by its name (so that just seconds may be supplied)
This code is much faster than converting to string and back to numeric
time <- c("1979-11-13T08:37:19-0500", "2014-05-13T08:37:19-0400");
time.posix <- as.POSIXct(time, format = "%Y-%m-%dT%H:%M:%S%z");
time.epoch <- as.vector(unclass(time.posix));
time.poslt <- as.POSIXlt(time.posix, tz = "America/New_York");
time.hour.new.york <- time.poslt$hour + time.poslt$min/60 + time.poslt$sec/3600;
> time;
[1] "1979-11-13T08:37:19-0500" "2014-05-13T08:37:19-0400"
> time.posix;
[1] "1979-11-13 15:37:19 IST" "2014-05-13 15:37:19 IDT"
> time.poslt;
[1] "1979-11-13 08:37:19 EST" "2014-05-13 08:37:19 EDT"
> time.epoch;
[1] 311348239 1399984639
> time.hour.new.york;
[1] 8.621944 8.621944
It is ancient topic, but I have found very few questions and answers about this matter. My solution is the following
library(hms)
foo <- data.frame(start.time = c("2012-02-06 15:47:00",
"2012-02-06 15:02:00",
"2012-02-22 10:08:00"),
duration = c(1,2,3))
foo$start.time = as.POSIXct( foo$start.time )
g1 = ggplot( ) + xlab("") +
geom_line( data = foo, aes(x = as.hms(start.time), y = duration ), color = "steelblue" )
g1
If you would like to add manual time (!) breaks, then
time_breaks = as.POSIXlt(c(
"2012-02-06 12:35:00 MSK",
"2012-02-06 13:15:00 MSK",
"2012-02-06 14:22:00 MSK",
"2012-02-06 15:22:00 MSK"))
g1 +
scale_x_time( breaks = as.hms( time_breaks ) ) +
theme( axis.text.x = element_text( angle=45, vjust=0.25) )
I have an file with birthdays in %d%b%y format. Some eg.
# "01DEC71" "01AUG54" "01APR81" "01MAY81" "01SEP83" "01FEB59"
I tried to reformat the date as
o108$fmtbirth <- format(as.Date(o108$birth, "%d%b%y"), "%Y/%m/%d")
and this is the result
# "1971/12/01" "2054/08/01" "1981/04/01" "1981/05/01" "1983/09/01" "2059/02/01"
These are birthdays and I see 2054. From this page I see that year values between 00 and 68 are coded as 20 for century. Is there a way to toggle this, in my case I want only 00 to 12 to be coded as 20.
1) chron. chron uses 30 by default so this will convert them converting first to Date (since chron can't read those sorts of dates) reformatting to character with two digit years into a format that chron can understand and finally back to Date.
library(chron)
xx <- c("01AUG11", "01AUG12", "01AUG13") # sample data
as.Date(chron(format(as.Date(xx, "%d%b%y"), "%m/%d/%y")))
That gives a cutoff of 30 but we can get a cutoff of 13 using chron's chron.year.expand option:
library(chron)
options(chron.year.expand =
function (y, cut.off = 12, century = c(1900, 2000), ...) {
chron:::year.expand(y, cut.off = cut.off, century = century, ...)
}
)
and then repeating the original conversion. For example assuming we had run this options statement already we would get the following with our xx :
> as.Date(chron(format(as.Date(xx, "%d%b%y"), "%m/%d/%y")))
[1] "2011-08-01" "2012-08-01" "1913-08-01"
2) Date only. Here is an alternative that does not use chron. You might want to replace "2012-12-31" with Sys.Date() if the idea is that otherwise future dates are really to be set 100 years back:
d <- as.Date(xx, "%d%b%y")
as.Date(ifelse(d > "2012-12-31", format(d, "19%y-%m-%d"), format(d)))
EDIT: added Date only solution.
See response from related thread:
format(as.Date("65-05-14", "%y-%m-%d"), "19%y-%m-%d")
o108$fmtbirth <- format(as.Date(o108$birth, "%d%b%y"), "%Y/%m/%d")
o108$fmtbirth <- as.Date(ifelse(o108$fmtbirth > Sys.Date(),
format(o108$fmtbirth, "19%y-%m-%d"),
format(o108$fmtbirth)))