【问题标题】:Subtract exactly one year from a POSIXct object从 POSIXct 对象中减去正好一年
【发布时间】:2014-12-18 15:40:18
【问题描述】:

假设我们有这个日期“2014-05-11 14:45:00 UTC”。我想在“2013-05-11 14:45:00 UTC”之前获得 1 年的确切 POSIXct 对象。

我的第一个想法是创建一个全新的 POSIXct 对象,方法是从年份位中减去一个并将其与字符串的其余部分一起粘贴,然后使用该字符串创建一个新的 POSIXct 对象,如下所示:

time <- as.POSIXct("2014-05-11 14:45:00 UTC",tz="UTC",origin="1970-01-01")
newTime <- as.POSIXct(paste(as.character(as.numeric(substr(time,1,4)) - 1),substr(time,5,19),sep=""),tz="UTC",origin="1970-01-01")

这很好用(闰年除外!)但问题是我需要在一个大的 data.table 中为每一行执行此操作,最好将结果放回 data.table 中。 有没有其他方法可以从这样的对象中减去一年?

我需要将它应用到像这样的 data.table 中:

          Time
 1: 1349206200
 2: 1349207100
 3: 1349208000
 4: 1349208900
 5: 1349209800
 6: 1349210700
 7: 1349211600
 8: 1349212500
 9: 1349213400
10: 1349214300
11: 1349215200

但是当我这样做时会发生这种情况:

SOdata[,Time:=as.numeric(as.POSIXct(paste(as.character(as.numeric(substr(Time,1,4)) - 1),substr(Time,5,19),sep=""),tz="UTC",origin="1970-01-01"))]
Error in as.POSIXlt.character(x, tz, ...) : 
  character string is not in a standard unambiguous format

我猜我需要使用类似 lapply 的东西,但是在使用该函数时我总是弄乱语法。那么有人知道怎么做吗?

【问题讨论】:

    标签: r date data.table


    【解决方案1】:

    lubridate 是你的朋友。

    library(lubridate)
    time <- as.POSIXct("2014-05-11 14:45:00 UTC",tz="UTC",origin="1970-01-01")
    time-dyears(1)
    #[1] "2013-05-11 14:45:00 UTC"
    time+dyears(1)
    #[1] "2015-05-11 14:45:00 UTC"
    

    闰年

    > x <- as.POSIXct(c("2012-02-28", "2012-02-29"), tz="UTC",origin="1970-01-01")
    > x - dyears(1)
    [1] "2011-02-28 UTC" "2011-03-01 UTC"
    

    【讨论】:

    • 在我的系统上,lubridate 方法使用 Gabor 回答 (2012-02-29) 中的闰年日期返回 NA。你能让它工作吗?
    • 'dyears()' 似乎比 'years()' 更稳定。
    【解决方案2】:

    我尚未测试其他答案,但无论闰年如何,以下内容都应按要求工作:

    time <- as.POSIXct("2014-05-11 14:45:00 UTC",tz="UTC",origin="1970-01-01")
    time <- as.POSIXlt(time)
    time$year <- time$year - 1
    time <- as.POSIXct(time)
    #[1] "2013-05-11 14:45:00 UTC"
    

    以 Gabor 的闰年为例:

    time <- as.POSIXct("2012-02-29 14:45:00 UTC",tz="UTC",origin="1970-01-01")
    time <- as.POSIXlt(time)
    time$year <- time$year - 1
    time <- as.POSIXct(time)
    #[1] "2011-03-01 14:45:00 UTC"
    

    【讨论】:

      【解决方案3】:

      seq in base 可以使用:

      LastYr <- function(x) seq(x, length = 2, by = "-1 year")[2]
      toPOSIXct <- function(x) as.POSIXct(x, origin = "1970-01-01")
      
      # example 1
      
      LastYr(as.POSIXct("2012-02-28"))
      ## [1] "2011-02-28 EST"
      
      # example 2 - leap year
      
      LastYr(as.POSIXct("2012-02-29"))
      ## [1] "2011-03-01 EST"
      
      # example 3 - vector case
      
      x <- as.POSIXct(c("2012-02-28", "2012-02-29")) # test data
      toPOSIXct(sapply(x, LastYr))
      ## [1] "2011-02-28 EST" "2011-03-01 EST"
      
      # example 4 - data.table shown in question
      
      DT[, Time := sapply(toPOSIXct(Time), LastYr)]
      

      修订使用函数LastYrtoPOSIXct 进行了简化。

      【讨论】:

        【解决方案4】:

        或者你可以尝试,在基础 R 中:

        > time + as.difftime(52*7+1,units="days")
        [1] "2015-05-11 14:45:00 UTC"
        
        > time - as.difftime(52*7+1,units="days")
        [1] "2013-05-11 14:45:00 UTC"
        

        当然,如果单位可以是年会更容易...

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-12
          • 1970-01-01
          • 1970-01-01
          • 2017-07-24
          相关资源
          最近更新 更多