web-dev-qa-db-fra.com

Ajouter un mois à une date

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?

52
Vineeth Mohan

Vanilla R a une classe difftime naïve, mais le paquet Lubridate CRAN vous permet de faire ce que vous demandez:

require(lubridate)
d <- as.Date('2004-01-01')
month(d) <- month(d) + 1
day(d) <- days_in_month(d)
d
[1] "2004-02-29"

J'espère que ça t'as aidé.

24
hd1

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"
104
Wojciech Sobala

C'est ambigu quand vous dites "ajoutez un mois à une date".

Tu veux dire

  1. ajouter 30 jours?
  2. augmenter le mois de la date de 1?

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é))

53
antonio

"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
7
G. Grothendieck

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.

6
Steven Chau

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.

Définition de la fonction

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 = '')))
}

Quelques exemples

Ajout de mois

> 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

Soustraction mois

> 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"
5
Jacob Amos
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]
3
Tung Nguyen

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"
1
Andri Signorell