J'essaie d'ajouter un mois à une date que j'ai. Mais alors ce n'est pas possible de manière simple jusqu'à présent. Voici ce que j'ai essayé.
d <- as.Date("2004-01-31")
d + 60
# [1] "2004-03-31"
Ajout ne va pas aider que le mois ne sera pas superposé.
seq(as.Date("2004-01-31"), by = "month", length = 2)
# [1] "2004-01-31" "2004-03-02"
Ci-dessus pourrait fonctionner, mais encore une fois ce n'est pas simple. Aussi, il ajoute également 30 jours ou quelque chose à la date qui a des problèmes comme le ci-dessous
seq(as.Date("2004-01-31"), by = "month", length = 10)
# [1] "2004-01-31" "2004-03-02" "2004-03-31" "2004-05-01" "2004-05-31" "2004-07-01" "2004-07-31" "2004-08-31" "2004-10-01" "2004-10-31"
Dans ce qui précède, pour les 2 premières dates, le mois n’a pas changé.
L’approche suivante a également échoué pendant un mois, mais a été un succès pour l’année.
d <- as.POSIXlt(as.Date("2010-01-01"))
d$year <- d$year +1
d
# [1] "2011-01-01 UTC"
d <- as.POSIXlt(as.Date("2010-01-01"))
d$month <- d$month +1
d
Erreur dans l'argument
format.POSIXlt(x, usetz = TRUE)
: 'x' non valide
Quelle est la bonne méthode pour faire cela?
Une fonction %m+%
de lubridate ajoute un mois sans dépasser le dernier jour du nouveau mois.
library(lubridate)
(d <- ymd("2012-01-31"))
1 parsed with %Y-%m-%d
[1] "2012-01-31 UTC"
d %m+% months(1)
[1] "2012-02-29 UTC"
C'est ambigu quand vous dites "ajoutez un mois à une date".
Tu veux dire
Dans les deux cas, tout un paquet pour une simple addition semble un peu exagéré.
Pour le premier point, bien sûr, le simple +
l'opérateur fera:
d=as.Date('2010-01-01')
d + 30
#[1] "2010-01-31"
Quant à la seconde, je créerais simplement une fonction d’une ligne aussi simple que cela (et avec une portée plus générale):
add.months= function(date,n) seq(date, by = paste (n, "months"), length = 2)[2]
Vous pouvez l'utiliser avec des mois arbitraires, y compris négatifs:
add.months(d, 3)
#[1] "2010-04-01"
add.months(d, -3)
#[1] "2009-10-01"
Bien sûr, si vous voulez ajouter seulement et souvent un seul mois:
add.month=function(date) add.months(date,1)
add.month(d)
#[1] "2010-02-01"
Si vous ajoutez un mois au 31 janvier, puisque le 31 février n'a pas de sens, la meilleure chose à faire est d'ajouter les 3 jours manquants au mois de mars. Si correctement:
add.month(as.Date("2010-01-31"))
#[1] "2010-03-03"
Au cas où, pour une raison très spéciale, vous auriez besoin de fixer un plafond au dernier jour disponible du mois, il est un peu plus long:
add.months.ceil=function (date, n){
#no ceiling
nC=add.months(date, n)
#ceiling
day(date)=01
C=add.months(date, n+1)-1
#use ceiling in case of overlapping
if(nC>C) return(C)
return(nC)
}
Comme d'habitude, vous pouvez ajouter une version pour un mois:
add.month.ceil=function(date) add.months.ceil(date,1)
Alors:
d=as.Date('2010-01-31')
add.month.ceil(d)
#[1] "2010-02-28"
d=as.Date('2010-01-21')
add.month.ceil(d)
#[1] "2010-02-21"
Et avec des diminutions:
d=as.Date('2010-03-31')
add.months.ceil(d, -1)
#[1] "2010-02-28"
d=as.Date('2010-03-21')
add.months.ceil(d, -1)
#[1] "2010-02-21"
En outre, vous n'avez pas indiqué si une solution scalaire ou vectorielle vous intéressait. Quant à ce dernier:
add.months.v= function(date,n) as.Date(sapply(date, add.months, n), Origin="1970-01-01")
Remarque: *apply
_ family détruit les données de classe, c’est pourquoi elles doivent être reconstruites. La version vectorielle apporte:
d=c(as.Date('2010/01/01'), as.Date('2010/01/31'))
add.months.v(d,1)
[1] "2010-02-01" "2010-03-03"
J'espère que tu l'as aimé))
"mondate"
est un peu similaire à "Date"
sauf que l'ajout de n
ajoute n
mois plutôt que n
jours:
> library(mondate)
> d <- as.Date("2004-01-31")
> as.mondate(d) + 1
mondate: timeunits="months"
[1] 2004-02-29
Le moyen le plus simple est de convertir Date au format POSIXlt. Effectuez ensuite l'opération arithmétique comme suit:
date_1m_fwd <- as.POSIXlt("2010-01-01")
date_1m_fwd$mon <- date_1m_fwd$mon +1
De plus, si vous voulez traiter les colonnes Date dans data.table, malheureusement, le format POSIXlt n'est pas pris en charge.
Vous pouvez toujours effectuer le mois d’ajout à l’aide des codes R de base, comme suit:
library(data.table)
dt <- as.data.table(seq(as.Date("2010-01-01"), length.out=5, by="month"))
dt[,shifted_month:=tail(seq(V1[1], length.out=length(V1)+3, by="month"),length(V1))]
J'espère que ça aide.
Voici une fonction qui ne nécessite l'installation d'aucun paquet. Vous lui donnez un objet Date
(ou un objet character
qu'il peut convertir en un Date
) et il ajoute n
mois à cette date sans changer le jour du mois ( sauf si le mois où vous arrivez n'a pas assez de jours, auquel cas il est utilisé par défaut jusqu'au dernier jour du mois de retour). Juste au cas où cela n'aurait pas de sens de le lire, voici quelques exemples.
addMonth <- function(date, n = 1){
if (n == 0){return(date)}
if (n %% 1 != 0){stop("Input Error: argument 'n' must be an integer.")}
# Check to make sure we have a standard Date format
if (class(date) == "character"){date = as.Date(date)}
# Turn the year, month, and day into numbers so we can play with them
y = as.numeric(substr(as.character(date),1,4))
m = as.numeric(substr(as.character(date),6,7))
d = as.numeric(substr(as.character(date),9,10))
# Run through the computation
i = 0
# Adding months
if (n > 0){
while (i < n){
m = m + 1
if (m == 13){
m = 1
y = y + 1
}
i = i + 1
}
}
# Subtracting months
else if (n < 0){
while (i > n){
m = m - 1
if (m == 0){
m = 12
y = y - 1
}
i = i - 1
}
}
# If past 28th day in base month, make adjustments for February
if (d > 28 & m == 2){
# If it's a leap year, return the 29th day
if ((y %% 4 == 0 & y %% 100 != 0) | y %% 400 == 0){d = 29}
# Otherwise, return the 28th day
else{d = 28}
}
# If 31st day in base month but only 30 days in end month, return 30th day
else if (d == 31){if (m %in% c(1, 3, 5, 7, 8, 10, 12) == FALSE){d = 30}}
# Turn year, month, and day into strings and put them together to make a Date
y = as.character(y)
# If month is single digit, add a leading 0, otherwise leave it alone
if (m < 10){m = paste('0', as.character(m), sep = '')}
else{m = as.character(m)}
# If day is single digit, add a leading 0, otherwise leave it alone
if (d < 10){d = paste('0', as.character(d), sep = '')}
else{d = as.character(d)}
# Put them together and convert return the result as a Date
return(as.Date(paste(y,'-',m,'-',d, sep = '')))
}
> addMonth('2014-01-31', n = 1)
[1] "2014-02-28" # February, non-leap year
> addMonth('2014-01-31', n = 5)
[1] "2014-06-30" # June only has 30 days, so day of month dropped to 30
> addMonth('2014-01-31', n = 24)
[1] "2016-01-31" # Increments years when n is a multiple of 12
> addMonth('2014-01-31', n = 25)
[1] "2016-02-29" # February, leap year
> addMonth('2014-01-31', n = -1)
[1] "2013-12-31"
> addMonth('2014-01-31', n = -7)
[1] "2013-06-30"
> addMonth('2014-01-31', n = -12)
[1] "2013-01-31"
> addMonth('2014-01-31', n = -23)
[1] "2012-02-29"
addedMonth <- seq(as.Date('2004-01-01'), length=2, by='1 month')[2]
addedQuarter <- seq(as.Date('2004-01-01'), length=2, by='1 quarter')[2]
J'ai transformé les pensées d'Antonio en une fonction spécifique:
library(DescTools)
> AddMonths(as.Date('2004-01-01'), 1)
[1] "2004-02-01"
> AddMonths(as.Date('2004-01-31'), 1)
[1] "2004-02-29"
> AddMonths(as.Date('2004-03-30'), -1)
[1] "2004-02-29"