Determine the Quarter from a date - r

Let say I have date as follows:
Date = as.Date('2020-11-30')
Now I want to determine the quarter for this date, So I can use the zoo package
library(zoo)
as.yearqtr(Date). ### [1] "2020 Q4"
However I want to determine the quarter with respect to a date, say
Date1 = as.Date("2020-05-31")
So with respect to this date, the quarter of Date should be Q2.
Is there any way to set up the base in the quarter calculation?
Any pointer will be highly appreciated.
Thanks,

if we want to extract the quarter, use format
format(as.yearqtr(Date1), 'Q%q')
[1] "Q2"
Or if it is based on difference, try
paste0("Q", (as.yearqtr(Date) - as.yearqtr(Date1)) * 4)
[1] "Q2"

Related

How to use cut function on dates

I have the following two dates:
dates <- c("2019-02-01", "2019-06-30")
I want to create the following bins from above two dates:
2019-05-30, 2019-04-30, 2019-03-31, 2019-02-28
I used cut function along with seq,
dt <- as.Date(dates)
cut(seq(dt[1], dt[2], by = "month"), "month")
but this does not produce correct results.
Could you please shed some light on the use of cut function on dates?
We assume that what is wanted is all end of months between but not including the 2 dates in dates. In the question dates[1] is the beginning of the month and dates[2] is the end of the month but we do not assume that although if we did it might be simplified. We have produced descending series below but usually in R one uses ascending.
The first approach below uses a monthly sequence and cut and the second approach below uses a daily sequence.
No packages are used.
1) We define a first of the month function, fom, which given a Date or character date gives the Date of the first of the month using cut. Then we calculate monthly dates between the first of the months of the two dates, convert those to end of the month and then remove any dates that are not strictly between the dates in dates.
fom <- function(x) as.Date(cut(as.Date(x), "month"))
s <- seq(fom(dates[2]), fom(dates[1]), "-1 month")
ss <- fom(fom(s) + 32) - 1
ss[ss > dates[1] & ss < dates[2]]
## [1] "2019-05-31" "2019-04-30" "2019-03-31" "2019-02-28"
2) Another approach is to compute a daily sequence between the two elements of dates after converting to Date class and then only keep those for which the next day has a different month and is between the dates in dates. This does not use cut.
dt <- as.Date(dates)
s <- seq(dt[2], dt[1], "-1 day")
s[as.POSIXlt(s)$mon != as.POSIXlt(s+1)$mon & s > dt[1] & s < dt[2]]
## [1] "2019-05-31" "2019-04-30" "2019-03-31" "2019-02-28"
There is no need for cut here:
library(lubridate)
dates <- c("2019-02-01", "2019-06-30")
seq(min(ymd(dates)), max(ymd(dates)), by = "months") - 1
#> [1] "2019-01-31" "2019-02-28" "2019-03-31" "2019-04-30" "2019-05-31"
Created on 2021-11-25 by the reprex package (v2.0.1)

How to convert character to Date format in R?

How to convert the below in character to Date format?
YYYY.MM
I am facing an issue dealing with zeroes after decimal points for month 10.
Say
2012.10
appears in my input source data as
2012.1
with the zero post decimal missing. How do I bring this back in the Date format?
Since you have only year and month, you need to assign some value for day before you convert to date. In the example below, the day has arbitrarily been chosen as 15.
IF THE INPUT IS CHARACTER
dates = c("2012.10", "2012.01")
lubridate::ymd(paste0(year_month = dates, day = "15"))
#[1] "2012-10-15" "2012-01-15"
IF THE INPUT IS NUMERIC
dates = c(2012.10, 2012.01)
do.call(c, lapply(strsplit(as.character(dates), "\\."), function(d){
if(nchar(d[2]) == 1){
d[2] = paste0(d[2],"0")
}
lubridate::ymd(paste0(year = d[1], month = d[2], day = "15"))
}))
#[1] "2012-10-15" "2012-01-15"
The zoo package has a "yearmon" class for representing year and month without day. Internally it stores them as year + fraction where fraction = 0 for Jan, 1/12 for Feb, 2/12 for Mar and so on but it prints in a nicer format and sorts as expected. Assuming that your input, x, is numeric convert it to character with 2 digit month and then apply as.yearmon with the appropriate format.
library(zoo)
x <- c(2012.1, 2012.01) # test data
as.yearmon(sprintf("%.2f", x), "%Y.%m")
## [1] "Oct 2012" "Jan 2012"
as.Date can be applied to convert a "yearmon" object to "Date" class if desired but normally that is not necessary.
as.Date(as.yearmon(sprintf("%.2f", x), "%Y.%m"))
## [1] "2012-10-01" "2012-01-01"
The code below uses the ymd() function from the lubridate package and sprintf() to coerce dates given in a numeric format
dates <- c(2012.1, 2012.01)
as well as dates given as a character string
dates <- c("2012.1", "2012.01")
where the part left of the decimal point specifies the year whereas the fractional part denote the month.
lubridate::ymd(sprintf("%.2f", as.numeric(dates)), truncated = 1L)
[1] "2012-10-01" "2012-01-01"
The format specification %.2f tells sprintf() to use 2 decimal places.
The parameter truncated = 1L indicates that one date element is missing (day) and should be completed by the default value (the first day of the month). Alternatively, the day of the month can be directly specified in the format specification to sprintf():
lubridate::ymd(sprintf("%.2f-15", as.numeric(dates)))
[1] "2012-10-15" "2012-01-15"

Converting variables in form of "2015M01" to date format in R?

I have a date frame df that simply looks like this:
month values
2012M01 99904
2012M02 99616
2012M03 99530
2012M04 99500
2012M05 99380
2012M06 99103
2013M01 98533
2013M02 97600
2013M03 96431
2013M04 95369
2013M05 94527
2013M06 93783
with month that was written in form of "M01", "M02"... and so on.
Now I want to convert this column to date format, is there a way to do it in R with lubridate?
I also want to select columns that contain one certain month from each year, like only March columns from all these years, what is the best way to do it?
The short answer is that dates require a year, month and day, so you cannot convert directly to a date format. You have 2 options.
Option 1: convert to a year-month format using zoo::as.yearmon.
library(zoo)
df$yearmon <- as.yearmon(df$month, "%YM%m")
# you can get e.g. month from that
months(df$yearmon[1])
# [1] "January"
Option 2: convert to a date by assuming that the day is always the first day of the month.
df$date <- as.Date(paste(df$month, "01", sep = "-"), "%YM%m-%d")
For selection (and I think you mean select rows, not columns), you already have everything you need. For example, to select only March 2013:
library(dplyr)
df %>% filter(month == "2013M03")
Something like this will get it:
raw <- "2012M01"
dt <- strptime(raw,format = "%YM%m")
dt will be in a Posix format. The strptime function will assign a '1' as the default day of month to make it a complete date.

Get beginning of next quarter from current Date in R

I am trying to get beginning of next quarter from the current date.
library(lubridate)
current_date = Sys.Date()
quarter(Sys.Date(), with_year= TRUE)
or from the function quarters.Date(Sys.Date())I could get quarter. I could not add quarter to the above code .
Are there are any other packages I can use or any other function in the default packages to do this?
1) zoo Convert to "yearqtr" class, add 1/4 and if you want the date at the end of the quarter apply as.Date using frac = 1
library(zoo)
today <- Sys.Date() # 2016-01-27
as.Date(as.yearqtr(today) + 1/4, frac = 1)
## [1] "2016-06-30"
Omit frac=1 if you want the start of the quarter. Omit as.Date if you want the "yearqtr" object:
as.yearqtr(today) + 1/4
[1] "2016 Q2"
2) base of R. This will give the beginning date of the next quarter with no packages. We use cut to get the beginning of the current quarter, convert to "Date" class and add enough days to get to the next quarter and apply cut and as.Date again:
as.Date(cut(as.Date(cut(today, "quarter")) + 100, "quarter"))
## [1] "2016-04-01"
If you want the end of the quarter add enough days to get to the second next quarter and subtact 1 day to get to the end of the prior quarter:
as.Date(cut(as.Date(cut(today, "quarter")) + 200, "quarter")) - 1
## [1] "2016-06-30"
The above answer does indeed work. If you would like to leverage the lubridate library, you can use the following:
ceiling_date(current_date, "quarter")
This will return the first date of the next quarter. Other helpful functions that are similar are floor_date and round_date. Both can be found in the lubridate documentation -
https://cran.r-project.org/web/packages/lubridate/lubridate.pdf.

Bucketing data into weekly, bi-weekly, monthly and quarterly data in R

I have a data frame with two columns. Date, Gender
I want to change the Date column to the start of the week for that observation. For example if Jun-28-2011 is a Tuesday, I'd like to change it to Jun-27-2011. Basically I want to re-label Date fields such that two data points that are in the same week have the same Date.
I also want to be able to do it by-weekly, or monthly and specially quarterly.
Update:
Let's use this as a dataset.
datset <- data.frame(date = as.Date("2011-06-28")+c(1:100))
One slick way to do this that I just learned recently is to use the lubridate package:
library(lubridate)
datset <- data.frame(date = as.Date("2011-06-28")+c(1:100))
#Add 1, since floor_date appears to round down to Sundays
floor_date(datset$date,"week") + 1
I'm not sure about how to do bi-weekly binning, but monthly and quarterly are easily handled with the respective base functions:
quarters(datset$date)
months(datset$date)
EDIT: Interestingly, floor_date from lubridate does not appear to be able to round down to the nearest quarter, but the function of the same name in ggplot2 does.
Look at ?strftime. In particular, the following formats:
%b: Abbreviated month name in the
current locale. (Also matches full
name on input.)
%B: Full month name
in the current locale. (Also matches
abbreviated name on input.)
%m: Month as decimal number (01–12).
%W: Week of the year as decimal number
(00–53) using Monday as the first day
of week (and typically with the first
Monday of the year as day 1 of week
1). The UK convention.
eg:
> strftime("2011-07-28","Month: %B, Week: %W")
[1] "Month: July, Week: 30"
> paste("Quarter:",ceiling(as.integer(strftime("2011-07-28","%m"))/3))
[1] "Quarter: 3"

Resources