Add with_year option in lubridate::month

I was wondering if it is possible to add a with_year option to the month function in lubridate.

The quarter and semester functions both have a with_year option, for example:

require(lubridate)
x <- ymd(c("2012-03-26", "2012-05-04", "2012-09-23", "2012-12-31"))
quarter(x, with_year = TRUE)

would get me:

[1] 2012.1 2012.2 2012.3 2012.4

which is very nice to use in terms of merging purpose

I wish the month function have this feature so I do not have to resort to the yearmon function in zoo. It is really an important feature for financial data analysis, and I prefer to use packages in the Hadleyverse.

2 Likes

Your request should probably rather go as a ticket on the issue tracker for lubridate.

Also self push: You can also look into my package dint which I wrote to deal with year-quarter and year-month dates. It's currently only on github and still a bit experimental, but I plan putting it on CRAN soon. It has no external dependencies, and I use it for production code at work, so I kinda have to keep it stable.

format_date_ym_short(Sys.Date()) and format_date_yq_short(Sys.Date()) are one-stop-shops to get you where you want to be

2 Likes

You could also do:

paste(year(x), month(x), sep = ".")

But @hoelk is correct, if you wish this to be an argument of the month function then you should probably create an issue here

3 Likes

I have to confess I also found it kinda weird that that option is lacking from lubridate::month(), especially since lubridate::month() already comes with some pretty weird options that I think shoudl rather have gone in a separate format() style function.

Are you referring to the label and abbr arguments? I personally think that they make sense as it is probably not uncommon to want to extract the month name and/or abbreviation rather than the numeric value. wday has similar arguments and I don't know that any of the other functions that do similar tasks have obvious alias' that are regularly used.

Yeah the options are useful for sure. I would just have expected them to be in separate functions. In general Tidyverse packages seem to care about type stability, and those arguments change the return type of the function.

Especiall if I have month() and month<-() I would expect them to be symmetric.
So why can I do

month(Sys.Date(), label = TRUE)

but not

month(x) <- "Jan"

This is just nitpicking though

(im also ranting because I wrote a method for lubridate::month() in my package and thus I have to support those weird arguments as well :wink: )

I am aware of this solution. However, if we make year-month a string, then there will lack computational flexibility. The zoo::yearmon and lubridate::quarter solve this issue in a very different way.

For example,

as.numeric(zoo::as.yearmon(ymd("2001-05-01")))

would be 2001+((5-1)/12) = 2001.3333, and the scale is 12 which makes sense

while

lubridate::quarter(ymd("2001-05-01"), with_year = TRUE)

would be 2001 + (2/10) = 2001.2, and the scale is 10 instead of 4 which is kind of counter-intuitive.

Alternatively, you might consider using floor_date and/or decimal_date to get you a date or decimal number to merge data from within months. The decimal will be ACTUAL/ACTUAL days, versus the zoo option you mentioned which gives decimals assuming a 30/360 day count.

require(lubridate)
x <- ymd(c("2012-03-26", "2012-05-04", "2012-09-23", "2012-12-31"))

floor_date(x, "1 month") 
[1] "2012-03-01" "2012-05-01" "2012-09-01" "2012-12-01"

floor_date(x, "1 month") %>% decimal_date()
[1] 2012.164 2012.331 2012.667 2012.915
2 Likes

I guess this should be the best feasible alternative in lubridate. I will open an issue in Github.

I use integers to represent year-month and year-quarter dates.
201203 would be march 2013, 20124 would be 4th quarter 2014.
Looks kinda scary, but thats why made dint with custom s3 classes and support for arithmetic operations
(so 20144 + 1 = 20151)

you can wrap the paste function with as.numeric to convert back to a numeric value

its probably more efficient to just do year(x) + month(x) / 100 if thats what you want