R subtracting 1 month from today's date gives NA
Solution 1
The calculation of months is indeed perfomed by base R but not the way your think. Months is used to get the month of a date object.
#Example
today <- Sys.Date()
months(today)
[1] "March"
To add or substract months, you should use %m+%
from lubridate
:
today <- Sys.Date()
today %m+% months(-1)
[1] "2017-02-28"
Solution 2
One month ago is non-defined in this context. February 29th only exists in leap years.
See the lubridate
documentation:
Note: Arithmetic with periods can results in undefined behavior when non-existent dates are involved (such as February 29th in non-leap years). Please see Period-class for more details and %m+% and add_with_rollback for alternative operations.
The lubridate
package can handle what you are doing, but you need to perform the operaton using %m+%
.
Amy M
Software and programming languages: R, STATA, Python Area of expertise: infectious disease epidemiology and microbiology Programming interests: automation of routine analyses and reporting, big data, automated data cleaning, probabilistic machine learning algorithms.
Updated on August 04, 2022Comments
-
Amy M almost 2 years
I have a script in which I subset my data according to some set time periods and wanted to subset all the records that had occurred in the last month.
However if I try to subtract one month from today's date it yields an NA:
> today <- Sys.Date() > today [1] "2017-03-29" > today - months(1) [1] NA
I do have lubridate loaded but I think this calculation is being performed with base R. If I subtract 2 or more months it works fine:
> today - months(2) [1] "2017-01-29" > today - months(3) [1] "2016-12-29"
Does anyone have any ideas about what might be going on?
UPDATE: I think this is something to do with simple date subtraction not handling leap year cases (2017 is not a leap year so
"2017-02-29"
does not exist).Are there other packages / functions that take into account leap years? For the above example I would expect the answer to revert to the last day of the previous month, i.e.:
today - months(1) # Should yield: "2017-02-28"
Would it make sense for this calculation to give the same results for both today and yesterday (or what is the ISO convention for this)?
> sessionInfo() R version 3.3.2 (2016-10-31) Platform: x86_64-w64-mingw32/x64 (64-bit) Running under: Windows 7 x64 (build 7601) Service Pack 1 locale: [1] LC_COLLATE=English_United Kingdom.1252 LC_CTYPE=English_United Kingdom.1252 [3] LC_MONETARY=English_United Kingdom.1252 LC_NUMERIC=C [5] LC_TIME=English_United Kingdom.1252 attached base packages: [1] stats graphics grDevices utils datasets methods base other attached packages: [1] xlsx_0.5.7 xlsxjars_0.6.1 rJava_0.9-8 MRAtools_0.6.8 stringdist_0.9.4.4 stringr_1.2.0 [7] stringi_1.1.3 lubridate_1.6.0 data.table_1.10.4 PKI_0.1-3 base64enc_0.1-3 digest_0.6.12 [13] getPass_0.1-1 RPostgreSQL_0.5-1 DBI_0.5-1 loaded via a namespace (and not attached): [1] magrittr_1.5 rstudioapi_0.6 tools_3.3.2 parallel_3.3.2
-
TARehman about 7 yearsWhen using
lubridate
, themonths
function is overwritten and does not function like base R. -
Pierre Lapointe about 7 years@TARehman No, the lubridate function is
month
with no "s". Base R hasmonths
-
TARehman about 7 yearsBase R's
months
function won't take a number, but when I loadlubridate
, I can givemonths
a number. Why is that? See also in the documentation: rdocumentation.org/packages/lubridate/versions/1.6.0/topics/… which seems to suggest it is overriding the base R function. -
Amy M about 7 yearsHave accepted @P Lapointe's worked answer but +1 for pointing me towards the specific help on this topic in lubridate.
-
Pierre Lapointe about 7 yearsI think it's the
%m+%
function that accepts more inputs becauselubridate::months(Sys.Date())
gives an error saying thatmonths
is not part of lubridate. -
TARehman about 7 yearsThat's genuinely weird, because when
lubridate
is loaded,months(1)
returns "1m 0d 0H 0M 0S". I'm not a big user oflubridate
, so really just more for my own information than anything. :) -
Pierre Lapointe about 7 years@TARehman I agree. Not sure why months(1) works after lubridate is loaded.
-
M.Viking over 2 yearsUpdated link - lubridate.tidyverse.org/reference/mplus.html