在日期中添加一个月

Vin*_*han 54 r date date-arithmetic

我想把一个月添加到我拥有的日期.但到目前为止它不可能以直接的方式进行.以下是我试过的.

d <- as.Date("2004-01-31")
d + 60
# [1] "2004-03-31"
Run Code Online (Sandbox Code Playgroud)

添加不会有帮助,因为月份不会重叠.

seq(as.Date("2004-01-31"), by = "month", length = 2) 
# [1] "2004-01-31" "2004-03-02"
Run Code Online (Sandbox Code Playgroud)

以上可能有用,但同样不是直截了当.此外它还增加了30天或某些东西到日期,如下所示的问题

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"
Run Code Online (Sandbox Code Playgroud)

在上面,对于前2个日期,月份没有变化.

以下方法也在一个月内失败,但是一年的成功

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
Run Code Online (Sandbox Code Playgroud)

错误format.POSIXlt(x, usetz = TRUE):无效'x'参数

这样做的正确方法是什么?

Woj*_*ala 110

%m+%来自lubridate的功能增加一个月而不超过新月的最后一天.

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"
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案,因为它正确地避免了超过新月份的最后一天。+1 (3认同)

ant*_*nio 53

当你说"为一个日期添加一个月"时,这是不明确的.

你的意思是

  1. 加30天?
  2. 将月份的一部分增加1?

在这两种情况下,简单添加的整个包装似乎有点夸张.

当然,对于第一点,简单的+运算符将执行:

d=as.Date('2010-01-01') 
d + 30 
#[1] "2010-01-31"
Run Code Online (Sandbox Code Playgroud)

至于第二个,我只会创建一个简单的单行函数(并且具有更通用的范围):

add.months= function(date,n) seq(date, by = paste (n, "months"), length = 2)[2]
Run Code Online (Sandbox Code Playgroud)

您可以使用任意月份,包括否定:

add.months(d, 3)
#[1] "2010-04-01"
add.months(d, -3)
#[1] "2009-10-01"
Run Code Online (Sandbox Code Playgroud)

当然,如果您只想添加,通常只需一个月:

add.month=function(date) add.months(date,1)
add.month(d)
#[1] "2010-02-01"
Run Code Online (Sandbox Code Playgroud)

如果你在1月31日增加一个月,那么从2月31日开始就没有意义了,最好完成工作就是将缺少的3天添加到下个月,即3月.如此正确:

add.month(as.Date("2010-01-31"))
#[1] "2010-03-03"
Run Code Online (Sandbox Code Playgroud)

如果由于一些非常特殊的原因,你需要在一个月的最后一天提供一个上限,它会更长一些:

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)
}
Run Code Online (Sandbox Code Playgroud)

像往常一样,你可以添加一个月的版本:

add.month.ceil=function(date) add.months.ceil(date,1)    
Run Code Online (Sandbox Code Playgroud)

所以:

  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"
Run Code Online (Sandbox Code Playgroud)

随着减少:

  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"
Run Code Online (Sandbox Code Playgroud)

此外,您没有告诉您是否对标量或矢量解决方案感兴趣.至于后者:

add.months.v= function(date,n) as.Date(sapply(date, add.months, n), origin="1970-01-01")
Run Code Online (Sandbox Code Playgroud)

注意:*applyfamily会破坏类数据,这就是为什么必须重建它.矢量版本带来:

d=c(as.Date('2010/01/01'), as.Date('2010/01/31'))
add.months.v(d,1)
[1] "2010-02-01" "2010-03-03"
Run Code Online (Sandbox Code Playgroud)

希望你喜欢它))

  • IMO 如果您必须考虑这么多事情只是为了增加一个月并且专家已经考虑过它,那么使用该软件包是值得的 (2认同)
  • @AshishSinghal。要使用 lubridate 添加 3 个月至今的“d”:“ymd(d)%m+%months(3)”;上面的单行代码很简单:`add.months(d, 3)`。因此,在第一个实例中,您必须学习三个函数“ymd”、“%m+%”、“months()”,以及如何粘合它们的语法,而后者早于标准 R“months()”。当然,对于复杂的日期操作,lubridate 的复杂性是有意义的。 (2认同)

hd1*_*hd1 27

Vanilla R有一个天真的difftime类,但Lubridate CRAN包让你做你想要的:

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

希望有所帮助.

  • (-1)如@MattParker所述,此解决方案不适用于2004-01-31等情况,而Wojciech Sobala提供的解决方案确实可以正常工作,是lubridate推荐的方法. (5认同)
  • 但这并不总是有效:`d < - as.Date("2004-01-31")`返回`NA`.[下面这个答案](http://stackoverflow.com/a/14182326/143319)给出了该情况的预期答案. (4认同)
  • 对不起,我不清楚.如果用"2004-01-31"替换第二行中的日期,然后运行其余的代码,你将获得"NA".在这种情况下,当你增加月份时,它会尝试将其设置为"2004-02-31",它返回一个"NA",因为它不是一个有效的日期.当你在下一行代码中设置`day(d)`时,`d`已经是'NA`. (3认同)

G. *_*eck 7

"mondate"有点类似于"Date"添加n添加n月而不是n天:

> library(mondate)
> d <- as.Date("2004-01-31")
> as.mondate(d) + 1
mondate: timeunits="months"
[1] 2004-02-29
Run Code Online (Sandbox Code Playgroud)


Ste*_*hau 7

最简单的方法是将Date转换为POSIXlt格式.然后执行如下算术运算:

date_1m_fwd     <- as.POSIXlt("2010-01-01")
date_1m_fwd$mon <- date_1m_fwd$mon +1
Run Code Online (Sandbox Code Playgroud)

此外,如果您想要处理data.table中的Date列,不幸的是,不支持POSIXlt格式.

您仍然可以使用基本R代码执行添加月份,如下所示:

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))]
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你.


Jac*_*mos 5

这是一个不需要安装任何软件包的函数。您为它提供一个Date对象(或character它可以转换为的对象Date),它会n向该日期添加月份,而不会更改该月的某天除非您所登陆的月份没有足够的天数,在这种情况下,默认为返回月份的最后一天)。以防万一没有意义的阅读,下面有一些示例。

功能定义

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 = '')))
}
Run Code Online (Sandbox Code Playgroud)

一些例子

加数个月

> 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
Run Code Online (Sandbox Code Playgroud)

减去月份

> 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"
Run Code Online (Sandbox Code Playgroud)


小智 5

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]
Run Code Online (Sandbox Code Playgroud)