as.Date() has a useful function in that it can give you the last n days as, e.g.:
dt <- Sys.Date()-6
> dt
[1] "2015-09-25"
Is there a way to tell it to give the last six months instead of the last six days?
I need something more precise than 6*30, as it should be the last day of the month.
You cannot use just Sys.Date to do this but there are ways. The following will give you just the correct months but not the correct days (i.e. the last day of the month):
#Sys.Date will return 2015-10-01 today
dates <- seq( Sys.Date() - months(6), Sys.Date(), '1 month')
dates
[1] "2015-04-01" "2015-05-01" "2015-06-01" "2015-07-01" "2015-08-01" "2015-09-01" "2015-10-01"
However, I found this very nice blog on R-bloggers which defines this function ( I slightly modified it to work with Dates) that returns the last day of the month:
eom <- function(date) {
# date character string containing POSIXct date
date.lt <- as.POSIXlt(dates) # add a month, then subtract a day:
mon <- date.lt$mon + 2
year <- date.lt$year
year <- year + as.integer(mon==13) # if month was December add a year
mon[mon==13] <- 1
iso = ISOdate(1900+year, mon, 1, hour=0, tz='')
result = as.POSIXct(iso) - 86400 # subtract one day
result + (as.POSIXlt(iso)$isdst - as.POSIXlt(result)$isdst)*3600
}
Now running:
> eom(dates)
[1] "2015-04-30 BST" "2015-05-31 BST" "2015-06-30 BST" "2015-07-31 BST" "2015-08-31 BST" "2015-09-30 BST" "2015-10-31 GMT"
Returns the correct results.
Is that what you are looking for?
today = Sys.Date()
lastSixMonths = seq(today, length.out=6, by="-1 month")
print(lastSixMonths)
# [1] "2015-10-01" "2015-09-01" "2015-08-01" "2015-07-01" "2015-06-01"
# [6] "2015-05-01"
Related
I have datetime object and I want to change all times to 2PM and keep the dates same.
I used floor_date to get the start of the corresponding date and then added period of 14 hours to get 2PM.
Sometime, result shows only the date and no time. Sometimes it shows both date and time.
Is there another approach to do this
library(lubridate)
t1 <- floor_date(Sys.time(), unit = "day") + hours(14)
t2 <- floor_date(ymd_hms("2021-08-25 10:36:00"), unit = "day") + hours(14)
You can replace the time component with the hour. Here is a function to do that.
change_time_to_x <- function(time, x) {
as.POSIXct(sub('\\s.*', x, time), tz = 'UTC')
}
input <- lubridate::ymd_hms(Sys.time(), "2021-08-25 10:36:00", "2012-12-31 00:00:00")
change_time_to_x(input, '14:00:00')
#[1] "2021-08-26 14:00:00 UTC" "2021-08-25 14:00:00 UTC" "2012-12-31 14:00:00 UTC"
I am struggling a bit with lubridate
I have a date series in the past in df$mydate variable as POSIXct. I want to take max(df$mydate) subtract it from now(), then subtract 2 more days from that time interval - i.e. make the interval 2 days shorter than the difference between the latest date of the series and today. The obtained time interval then should be added to all dates in df$mydate so that the dates block is brought forward to end 2 days in the past from today.
How can I do this with lubridate?
when I try to convert now() - max(df$mydate) to interval I get an empty interval. So I do not even get to step 2 - shortening the interval by 2 days and to step 3 - trying to then add this time length to dates I have.
The Idee with lubridate is to take care of all the transformation between intervals and dates for you so you don't need to think about it. This simple code does exactly that what you want.
library(lubridate)
my_date <-as.POSIXlt(paste0("2009-08-",1:10))
time_diff <- now() - max(my_date)
time_diff_short = time_diff - 2
my_date + time_diff_short
What I found was that you need my_date to be of the format POSIXlt
You can use difftime from base to get the time difference to now Sys.time() and subtract 2 days.
x <- x + (difftime(Sys.time(), max(x), units = "days") - 2)
x
#[1] "2020-09-11 10:32:20 CEST" "2020-09-12 10:32:20 CEST"
#[3] "2020-09-13 10:32:20 CEST" "2020-09-14 10:32:20 CEST"
Sys.time()
#[1] "2020-09-16 10:32:20 CEST"
Data:
(x <- seq(as.POSIXct("2000-01-01 12:00:00"), length.out = 4, by = "days"))
#[1] "2000-01-01 12:00:00 CET" "2000-01-02 12:00:00 CET"
#[3] "2000-01-03 12:00:00 CET" "2000-01-04 12:00:00 CET"
I tried to generate a sequence of dates between two dates. By search all the old posts, I found very nice solution using seq.Date.
For example:
> seq.Date(as.Date("2016/1/15"), as.Date("2016/5/1"), by = "month")
[1] "2016-01-15" "2016-02-15" "2016-03-15" "2016-04-15"
The above function yields very nice solution. However, it doesnt work when the date is 30 or 31 in Jan.
> seq.Date(as.Date("2016/1/30"), as.Date("2016/5/1"), by = "month")
[1] "2016-01-30" "2016-03-01" "2016-03-30" "2016-04-30"
The second anniversary jumps to March instead of being capped at 29/Feb. I couldnt find a workaround for this.
Here's an approach that also works in other cases:
library(lubridate)
fun <- function(from, to, by) {
mySeq <- seq.Date(as.Date(from), as.Date(to), by = by)
as.Date(sapply(mySeq, function(d) d + 1 - which.max(day(d - 0:3))), origin = "1970-01-01")
}
fun("2016/1/30", "2016/5/1", "month")
# [1] "2016-01-30" "2016-02-29" "2016-03-30" "2016-04-30"
fun("2017/1/31", "2017/5/1", "month")
# [1] "2017-01-31" "2017-02-28" "2017-03-31" "2017-04-30"
fun("2017/1/29", "2017/5/1", "month")
# [1] "2017-01-29" "2017-02-28" "2017-03-29" "2017-04-29"
What fun does is that it subtracts 0:3 from each date and chooses the one that has the largest day.
With lubridate package
library('lubridate')
pmin(
ymd('2018-01-30') + months(0:11), # NA where month goes over
ymd('2018-01-01') + months(1:12) - days(1), # last day of month
na.rm = T
)
[1] "2018-01-30" "2018-02-28" "2018-03-30"
[4] "2018-04-30" "2018-05-30" "2018-06-30"
[7] "2018-07-30" "2018-08-30" "2018-09-30"
[10] "2018-10-30" "2018-11-30" "2018-12-30"
I have a Data Frame with dates in this format 2014-06-10 06:12:35 BRT I would compare dates to see if they are part of the same social day (3:00 to 3:00 am on a day to another). But when I try to select only the day
format(as.Date(df$x,format="%Y-%m-%dT%H:%M:%SZ"), "%d"),
sometimes he adds + 1, for example
2014-06-13 22:54:36 BRT it shows 14.
And if I try to take the time
format(as.Date(df$x,format="%Y-%m-%dT%H:%M:%SZ"), "%H")
it appears always 00.
How should I work with dates in the R?
In R, times use POSIXct and POSIXlt classes and dates use the Date class.
Dates are stored as the number of days since January 1st, 1970 and times are stored as the number of seconds since January 1st, 1970.
So, for example:
d <- as.Date("1971-01-01")
unclass(d) # one year after 1970-01-01
# [1] 365
pct <- Sys.time() # in POSIXct
unclass(pct) # number of seconds since 1970-01-01
# [1] 1450276559
plt <- as.POSIXlt(pct)
up <- unclass(plt) # up is now a list containing the components of time
names(up)
# [1] "sec" "min" "hour" "mday" "mon" "year" "wday" "yday" "isdst" "zone"
# [11] "gmtoff"
up$hour
# [1] 9
To perform operations on dates and times:
plt - as.POSIXlt(d)
# Time difference of 16420.61 days
And to process dates, you can use strptime() (borrowing these examples from the manual page):
strptime("20/2/06 11:16:16.683", "%d/%m/%y %H:%M:%OS")
# [1] "2006-02-20 11:16:16 EST"
# And in vectorized form:
dates <- c("1jan1960", "2jan1960", "31mar1960", "30jul1960")
strptime(dates, "%d%b%Y")
# [1] "1960-01-01 EST" "1960-01-02 EST" "1960-03-31 EST" "1960-07-30 EDT"
To process your specific date[s]:
dateString <- "2014-06-10 06:12:35"
d <- strptime(dateString, "%Y-%m-%d %H:%M:%S")
NOTE: I'm not finding the "BRT" timezone in the R list of zones, so my time above is set to the EDT timezone:
"BRT" %in% OlsonNames()
# [1] FALSE
How might I generate a list of date objects (POSIXct or lt) for each Monday of a year?
For instance this year would be (In Year, Month, Day):
2012_01_02,
2012_01_09,
2102_01_16,
etc
EDIT: On further reflection, here's a cleaner function for doing the same thing:
getAllMondays <- function(year) {
days <- as.POSIXlt(paste(year, 1:366, sep="-"), format="%Y-%j")
Ms <- days[days$wday==1]
Ms[!is.na(Ms)] # Needed to remove NA from day 366 in non-leap years
}
getAllMondays(2012)
Here's a function that'll perform the more general task of finding the first Monday in an arbitrary year, and then listing it and all of the other Mondays in that year. It uses seq.POSIXt(), and the argument by = "week" (which is also available for seq.Date()).
getAllMondays <- function(year) {
day1 <- as.POSIXlt(paste(year, "01-01", sep="-"))
day365 <- as.POSIXlt(paste(year, "12-31", sep="-"))
# Find the first Monday of year
week1 <- as.POSIXlt(seq(day1, length.out=7, by="day"))
monday1 <- week1[week1$wday == 1]
# Return all Mondays in year
seq(monday1, day365, by="week")
}
head(getAllMondays(2012))
# [1] "2012-01-02 PST" "2012-01-09 PST" "2012-01-16 PST" "2012-01-23 PST"
# [5] "2012-01-30 PST" "2012-02-06 PST"
I found seq.Date which is part of base. Not sure if there are caveats to this method but it seems to do what I want:
x = seq(as.Date("2012/01/02"), as.Date("2013/01/01"), "7 days")
as.POSIXct(x)
as.Date("2012_01_02", format="%Y_%m_%d") +seq(0,366,by=7) # 2012 is a leap year.
If you really want them as DateTimes with all the attendant hassles of timezones then you can coerce them with as.POSIXct.