Get number of days, months and weeks since Epoch in R - r

What is the best way to get the number of days, months and weeks since Epoch time in R ?
( A solution exists for Java : Get the number of days, weeks, and months, since Epoch in Java )
I know to get seconds from epoch, but how to get number of weeks ?
as.integer( Sys.time()) #.... gives number of seconds since epoch time

One option is to use lubridate::interval as:
library(lubridate)
span <- interval(ymd_hms("1970-01-01 00:00:00"), Sys.time())
as.period(span, unit = "days")
#[1] "17622d 19H 57M 10.5912010669708S"
as.period(span, unit = "months")
#[1] "579m 0d 19H 57M 10.5912010669708S"
as.period(span, unit = "years")
#[1] "48y 3m 0d 19H 57M 10.5912010669708S"

The internal representation of "Date" class is the number of days since the Epoch. (If you have a POSIXct variable then convert it to Date class using as.Date first however watch out for time zone conversion problems.)
now <- Sys.Date() # Date
d <- as.numeric(now) # days since Epoch
Now use the facts that there are an average of 365.25 days per year and 365.25 / 12 days per month to get the years and months since the Epoch.
m <- d / (365.25 / 12) # months since Epoch
y <- d / 365.25 # years since Epoch
years/months/days
If we did not want years, months and days separately but rather want the number of whole years and months (0-11) and days (0-30) then use POSIXlt:
lt <- as.POSIXlt(format(Sys.Date()))
with(lt, data.frame(years = year - 70, months = mon - 0, days = mday - 1))
This also works if lt is a vector, e.g. lt <- c(lt, lt) .

Related

Difference between dates in years-months-days format

I'm trying to replicate what this website does - get difference between 2 dates expressed in years-months-days.
I managed to get years-months difference in pretty dirty way:
paste(
floor(
interval(as.Date("1985-09-17"),
as.Date("1996-03-13"))
%/% months(1) /12), ' years, ',
ifelse(
ceiling(((interval(as.Date("1985-09-17"),
as.Date("1996-03-13"))
%/% months(1) /12) %% 1 )*12)<10,
paste0('0',ceiling(((interval(as.Date("1985-09-17"),
as.Date("1996-03-13"))
%/% months(1) /12) %% 1)*12)),
ceiling(((interval(as.Date("1985-09-17"),
as.Date("1996-03-13"))
%/% months(1) /12) %% 1 )*12)),' months', sep='')
[1] "10 years, 04 months"
Is there a better way to do this? I found similar question here but it doesn't have satisfying answer and I'm guessing many new packages been developed since then, so maybe there is a simple way to do this
You might try something like the following:
as.Date(as.numeric(as.Date("1996-03-13"))
-as.numeric(as.Date("1985-09-17")),
origin = "2000-01-01")
and then read the years months and days starting from the origin as your difference.
I had the same issue recently and this worked for me:
First get the difftime in days, then divide over 365.25 days per year and keep the integer value to get the number of years.
Then keep the decimal part and multiply by 12 to get the number of months.
To get the number of days, you want to keep the decimal part after you get the number of months and multiply by 365.25/12.
paste(as.integer(difftime("1996-03-13", "1985-09-17")/365.25), "years",
as.integer(as.numeric(difftime("1996-03-13", "1985-09-17")/365.25)%%1 * 12), "months",
as.integer((as.numeric(difftime("1996-03-13", "1985-09-17")/365.25)%%1 * 12)%%1 * 365.25/12), "days")
[1] "10 years 5 months 25 days"
If you prefer to work with library(lubridate):
paste(as.integer(time_length(interval("1985-09-17", "1996-03-13"), "days")/365.25), "years",
as.integer((time_length(interval("1985-09-17", "1996-03-13"), "days")/365.25)%%1 * 12), "months",
as.integer(((time_length(interval("1985-09-17", "1996-03-13"), "days")/365.25)%%1 * 12)%%1 * 365.25/12), "days")

Converting a number into time (0,5 of an hour = 00:30:00)

I am trying to convert a number into time format.
For example:
I calculate how long has to be charged an electric car at the charging station of 11 kWh.
Energy demand - 2,8 kWh
Charging time = 2,8 kWh/11 kWh = 0,257 h
0,257 h = 15 min 25 sec. = 00:15:25
How can I convert 0,257 h into 00:15:25 in R?
Based on the example, we will assume that the input is less than 24 (but if that is not the case these could be modified to handle that depending on the definition of what such an input should produce).
1) chron::times Use chron times like this. times measures times in fractions of a day so divide the hours (.257) by 24 to give the fraction of a day that it represents.
library(chron)
times(.257 / 24)
## [1] 00:15:25
This gives a chron "times" class object. If x is such an object use format(x) to convert it to a character string, if desired.
2) POSIXct This uses no packages although it is longer. It returns the time as a character string. POSIXct measures time in seconds and so multiply the hours (.257) by 3600 as there are 3600 seconds in an hour.
format(as.POSIXct("1970-01-01") + 3600 * .257, "%H:%M:%S")
## [1] "00:15:25"
2a) This variation would also work. It is longer but it involves no conversion factors. It returns a character string.
format(as.POSIXct("1970-01-01") + as.difftime(.257, units = "hours"), "%H:%M:%S")
## [1] "00:15:25"
Updates: Added (2). Also added (2a) and improved (2).
The answer by #GGrothendieck seems to be the way to go here. But if you had to do this in base R, you could just compute the hour, minute, and second components and build the time string manually:
x <- 2.257 # number of hours
total <- round(x*60*60, digits=0) # the total number of seconds
hours <- trunc(total / (60*60))
minutes <- trunc((x - hours) * 60)
seconds <- total %% 60
ts <- paste0(formatC(hours, width=2, flag="0"), ":",
formatC(minutes, width=2, flag="0"), ":",
formatC(seconds, width=2, flag="0"))
ts
[1] "02:15:25"
Demo
The tidyverse solution would use the hms package:
hms::hms(0.257 * 60^2)
#> 00:15:25.2
Gives you an object of classes hms and difftime. If you want a string:
format(hms::hms(0.257 * 60^2))
#> [1] "00:15:25.2"

Time difference with R. When day, month and year absent

How to get date difference with R (in term of minutes) when day, month and year were not provided.
For instance minutes betweeen "23:14:01" and "00:02:01".
You can use difftime:
a <- strptime("23:14:01",format = "%H:%M:%S")
b <- strptime("00:02:01",format = "%H:%M:%S")
difftime(a,b, units = "mins")
# Time difference of 1392 mins
difftime_res_2 <- 1440 - difftime_res # In case the times are from following days
difftime_res_2
# Time difference of 48 mins

How can I create a Vector of weekdays from "Today" to a date 75 days ago in R? [duplicate]

This question already has answers here:
Fill a vector with weekdays only
(2 answers)
Closed 6 years ago.
I want to create a vector that begins on the most recent weekday date and runs back for 75 days to the weekday 75 weekdays ago - how can I do this? Assume I can use seq? I'm very much a newbie to R.
If today is a Sunday (e.g. 21-08-2016), then the sequence should begin on the prior Friday (19-08-2016) and work back to the weekday 09-05-16. Very much similar to the Excel function =WORKDAY(A1,-1) for example.
We can make a sequence of days, reject any weekend days (NB - this will depend on your locale) and then trim the output to 75 days.
s1 <- seq(Sys.Date()-120, Sys.Date(), by = "day")
s1 <- s1[!weekdays(s1) %in% c("Saturday", "Sunday")]
s1[(length(s1)-74):length(s1)]
To produce output in the other direction
n <- 75
s1 <- seq(Sys.Date(), Sys.Date() - (n * 7/5 + 3) , by = "-1 day")
s1 <- s1[!weekdays(s1) %in% c("Saturday", "Sunday")]
s1[1:n]
Since 75 days is not a large number, it might be something like this:
library(chron)
library(lubridate)
n = 75
Filter(function(x) !is.weekend(x), seq.Date(today(), by = '-1 day', length.out = (n+2)*7/5))[1:n]
# [1] "2016-08-19" "2016-08-18" "2016-08-17" "2016-08-16"
# [5] "2016-08-15" "2016-08-12" "2016-08-11" "2016-08-10"
# ...

Get date difference in years (floating point)

I want to correct source activity based on the difference between reference and measurement date and source half life (measured in years). Say I have
ref_date <- as.Date('06/01/08',format='%d/%m/%y')
and a column in my data.frame with the same date format, e.g.,
today <- as.Date(Sys.Date(), format='%d/%m/%y')
I can find the number of years between these dates using the lubridate package
year(today)-year(ref_date)
[1] 5
Is there a function I can use to get a floating point answer today - ref_date = 5.2y, for example?
Yes, of course, use difftime() with an as numeric:
R> as.numeric(difftime(as.Date("2003-04-05"), as.Date("2001-01-01"),
+ unit="weeks"))/52.25
[1] 2.2529
R>
Note that we do have to switch to weeks scaled by 52.25 as there is a bit of ambiguity
there in terms of counting years---a February 29 comes around every 4 years but not every 100th etc.
So you have to define that. difftime() handles all time units up to weeks. Months cannot be done for the same reason of the non-constant 'numerator'.
The lubridate package contains a built-in function, time_length, which can help perform this task.
time_length(difftime(as.Date("2003-04-05"), as.Date("2001-01-01")), "years")
[1] 2.257534
time_length(difftime(as.Date("2017-03-01"), as.Date("2012-03-01")),"years")
[1] 5.00274
Documentation for the lubridate package can be found here.
Inspired by Bryan F, time_length() would work better if using interval object
time_length(interval(as.Date("2003-04-05"), as.Date("2001-01-01")), "years")
[1] -2.257534
time_length(difftime(as.Date("2017-03-01"), as.Date("2012-03-01")),"years")
[1] 5.00274
time_length(interval(as.Date("2017-03-01"), as.Date("2012-03-01")),"years")
[1] -5
You can see if you use interval() to get the time difference and then pass it to time_length(), time_length() would take into account the fact that not all months and years have the same number of days, e.g., the leap year.
Not an exact answer to your question, but the answer from Dirk Eddelbuettel in some situations can produce small errors.
Please, consider the following example:
as.numeric(difftime(as.Date("2012-03-01"), as.Date("2017-03-01"), unit="weeks"))/52.25
[1] -4.992481
The correct answer here should be at least 5 years.
The following function (using lubridate package) will calculate a number of full years between two dates:
# Function to calculate an exact full number of years between two dates
year.diff <- function(firstDate, secondDate) {
yearsdiff <- year(secondDate) - year(firstDate)
monthsdiff <- month(secondDate) - month(firstDate)
daysdiff <- day(secondDate) - day(firstDate)
if ((monthsdiff < 0) | (monthsdiff == 0 & daysdiff < 0)) {
yearsdiff <- yearsdiff - 1
}
yearsdiff
}
You can modify it to calculate a fractional part depending on how you define the number of days in the last (not finished) year.
You can use the function AnnivDates() of the package BondValuation:
R> library('BondValuation')
R> DateIndexes <- unlist(
+ suppressWarnings(
+ AnnivDates("2001-01-01", "2003-04-05", CpY=1)$DateVectors[2]
+ )
+ )
R> names(DateIndexes) <- NULL
R> DateIndexes[length(DateIndexes)] - DateIndexes[1]
[1] 2.257534
Click here for documentation of the package BondValuation.
To get the date difference in years (floating point) you can convert the dates to decimal numbers of Year and calculate then their difference.
#Example Dates
x <- as.Date(c("2001-01-01", "2003-04-05"))
#Convert Date to decimal year:
date2DYear <- function(x) {
as.numeric(format(x,"%Y")) + #Get Year an add
(as.numeric(format(x,"%j")) - 0.5) / #Day of the year divided by
as.numeric(format(as.Date(paste0(format(x,"%Y"), "-12-31")),"%j")) #days of the year
}
diff(date2DYear(x)) #Get the difference in years
#[1] 2.257534
I subtract 0.5 from the day of the year as it is not known if you are at the beginning or the end of the day and %j starts with 1.
I think the difference between 2012-03-01 and 2017-03-01 need not to be 5 Years, as 2012 has 366 days and 2017 365 and 2012-03-01 is on the 61 day of the year and 2017-03-01 on the 60.
x <- as.Date(c("2012-03-01", "2017-03-01"))
diff(date2DYear(x))
#[1] 4.997713
Note that using time_length and interval from lubridate need not come to the same result when you make a cumulative time difference.
library(lubridate)
x <- as.Date(c("2012-01-01", "2012-03-01", "2012-12-31"))
time_length(interval(x[1], x[3]), "years")
#[1] 0.9972678
time_length(interval(x[1], x[2]), "years") +
time_length(interval(x[2], x[3]), "years")
#[1] 0.9995509 #!
diff(date2DYear(x[c(1,3)]))
#[1] 0.9972678
diff(date2DYear(x[c(1,2)])) + diff(date2DYear(x[c(2,3)]))
#[1] 0.9972678
x <- as.Date(c("2013-01-01", "2013-03-01", "2013-12-31"))
time_length(interval(x[1], x[3]), "years")
#[1] 0.9972603
time_length(interval(x[1], x[2]), "years") +
time_length(interval(x[2], x[3]), "years")
#[1] 0.9972603
diff(date2DYear(x[c(1,3)]))
#[1] 0.9972603
diff(date2DYear(x[c(1,2)])) + diff(date2DYear(x[c(2,3)]))
#[1] 0.9972603
Since you are already using lubridate package, you can obtain number of years in floating point using a simple trick:
find number of seconds in one year:
seconds_in_a_year <- as.integer((seconds(ymd("2010-01-01")) - seconds(ymd("2009-01-01"))))
now obtain number of seconds between the 2 dates you desire
seconds_between_dates <- as.integer(seconds(date1) - seconds(date2))
your final answer for number of years in floating points will be
years_between_dates <- seconds_between_dates / seconds_in_a_year

Resources