Find difference between times in R - r

Help me to find difference between times.For eg: these are the date and time
2015-11-24 16:49:14
2014-12-02 16:52:43
Need the result in HH:MM:SS format using r.

As you need difference between only the time, ignoring the dates you can first extract the time using strptime
x <- strptime(substr(a, 12, 19), format="%H:%M:%S")
y <- strptime(substr(b, 12, 19), format="%H:%M:%S")
Then using the seconds_to_period function of lubridate package you can get the time difference and then format the output using sprintf
library(lubridate)
temp <- seconds_to_period(as.numeric(difftime(y, x, units = "secs")))
sprintf('%02d:%02d:%02d', hour(temp), minute(temp), second(temp))
# [1] "00:03:29"
data
a <- as.POSIXct("2015-11-24 16:49:14")
b <- as.POSIXct("2014-12-02 16:52:43")

Following code to get the difference
library(lubridate)
interval(ymd_hms("2015-11-2416:17:38"),ymd_hms("2015-11-24 14:19:44"))
span<-interval(as.POSIXct("2015-11-24 16:17:38"),
as.POSIXct("2015-11-24 14:19:44"))
as.period(span)
Format of answer
> -1H -57M -54S
Also display the difference in year, month & date

Related

Converting numbers into time and date

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")

How to format a Date as "YYYY-Mon" with Lubridate?

I would like to create a vector of dates between two specified moments in time with step 1 month, as described in this thread (Create a Vector of All Days Between Two Dates), to be then converted into factors for data visualization.
However, I'd like to have the dates in the YYYY-Mon, ie. 2010-Feb, format. But so far I managed only to have the dates in the standard format 2010-02-01, using a code like this:
require(lubridate)
first <- ymd_hms("2010-02-07 15:00:00 UTC")
start <- ymd(floor_date(first, unit="month"))
last <- ymd_hms("2017-10-29 20:00:00 UTC")
end <- ymd(ceiling_date(last, unit="month"))
> start
[1] "2010-02-01"
> end
[1] "2017-11-01"
How can I change the format to YYYY-Mon?
You can use format():
start %>% format('%Y-%b')
To create the vector, use seq():
seq(start, end, by = 'month') %>% format('%Y-%b')
Obs: Use capital 'B' for full month name: '%Y-%B'.

How to convert a date to YYYYDDD?

I can't figure out how to turn Sys.Date() into a number in the format YYYYDDD. Where DDD is the day of the year, i.e. Jan 1 would be 2016001 Dec 31 would be 2016365
Date <- Sys.Date() ## The Variable Date is created as 2016-01-01
SomeFunction(Date) ## Returns 2016001
You can just use the format function as follows:
format(Date, '%Y%j')
which gives:
[1] "2016161" "2016162" "2016163"
If you want to format it in other ways, see ?strptime for all the possible options.
Alternatively, you could use the year and yday functions from the data.table or lubridate packages and paste them together with paste0:
library(data.table) # or: library(lubridate)
paste0(year(Date), yday(Date))
which will give you the same result.
The values that are returned by both options are of class character. Wrap the above solutions in as.numeric() to get real numbers.
Used data:
> Date <- Sys.Date() + 1:3
> Date
[1] "2016-06-09" "2016-06-10" "2016-06-11"
> class(Date)
[1] "Date"
Here's one option with lubridate:
library(lubridate)
x <- Sys.Date()
#[1] "2016-06-08"
paste0(year(x),yday(x))
#[1] "2016160"
This should work for creating a new column with the specified date format:
Date <- Sys.Date
df$Month_Yr <- format(as.Date(df$Date), "%Y%d")
But, especially when working with larger data sets, it is easier to do the following:
library(data.table)
setDT(df)[,NewDate := format(as.Date(Date), "%Y%d"
Hope this helps. May have to tinker if you only want one value and are not working with a data set.

Test Weekday then Add Number to Date in R

I've got a column with dates (df$Date) and I would like to create a new column (df$NewColumn) that adds a variable number of days depending on the day of the week (using Lubridate's wday) that is in df$Date, e.g.:
df$NewColumn <- ifelse(wday(df$Date) == 6, df$Date + 3,
ifelse(wday(df$Date) == 7, df$Date + 3,
df$Date + 2))
It is seemingly working, only problem is my date format is in a 16XXX format and I can't seem to convert it back to a proper-looking date. Thanks for your help!
One way to deal with this is to use the class() function:
R> testdate <- 16716
R> class(testdate) <- "Date"
R> testdate
[1] "2015-10-08"
As stated in the comments, ifelse changes formats. If you can avoid using it, then the format should stay the same. The following code creates the output you're looking for:
library(lubridate)
df <- data.frame(Date=as.Date(c("2011/01/01",
"2011/01/02")))
df$NewColumn <- df$Date + 2 + as.numeric(wday(df$Date)>=6)

Add correct century to dates with year provided as "Year without century", %y

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)))

Resources