【问题标题】:Dealing with numeric (decimal) dates in R?在 R 中处理数字(十进制)日期?
【发布时间】:2016-09-30 19:27:31
【问题描述】:

我有一些来自 Excel 的数字日期数据:

> df <- data.frame(c(42613, 42612, 42614), c(42614.61, 42613.97, 42612.12))
> names(df) <- c("Closetime", "Opentime")

ClosetimeOpentime 都是 numeric。我想保留OpenTime 中的小时/分钟/秒数据,并将时间'00:00:00' 添加到Closetime 中的每个日期:

> df$Closetime <- paste(as.Date(df$Closetime, origin = '1900-01-01'), c('00:00:00'))

很容易做到Closetime,但是当我尝试在Opentime 上使用lubridate::date_decimal 时,一切都变糟了。

> df$Opentime <- date_decimal(df$Opentime)
> df
            Closetime             Opentime
1 2016-09-02 00:00:00 42614-08-11 15:36:00
2 2016-09-01 00:00:00 42613-12-21 01:12:00
3 2016-09-03 00:00:00 42612-02-13 22:04:48

如何使OpentimeClosetime 具有相同的类型/格式?我最终希望能够获得每列中时间之间的差异(以小时为单位),以供参考。

【问题讨论】:

    标签: r date datetime lubridate


    【解决方案1】:

    如果你可以使用 POSIXct,你可以这样做

    df$Opentime <- as.POSIXct( df$Opentime*24*60*60, 
                    origin="1900-01-01", 
                    tz="UTC")
    

    推理:POSIXct 只是自起源以来的秒数

    【讨论】:

    • 嗯,这是将天缩放到秒的最糟糕的方法,因为您的 松散 例如调整几秒。其他答案显示了如何使用 R 的类型正确执行此操作。
    • @DirkEddelbuettel 公平点,但也许如果你做了所有的中间转换,你应该指出它的用途。
    • 再来一次?是指我下面的答案吗?你会读吗?
    • @DirkEddelbuettel 是的,我指的是您在下面的回答
    • 三个步骤,三个块,每个注释。如果你有问题,我建议你问他们。我在这里告诉过你,你的方法有缺陷;得到了两个赞成票。剩下的就交给你了。
    【解决方案2】:

    首先,我们遵循help("as.Date") 中有关 Excel 日期的建议。我假设这里是 Windows Excel:

    df$Closetime_p <- as.Date(df$Closetime, origin = "1899-12-30")
    df$Opentime_p <- as.Date(floor(df$Opentime), origin = "1899-12-30")
    

    然后我们转换成POSIXct:

    df$Closetime_p <- as.POSIXct(as.POSIXlt(df$Closetime_p, tz = "GMT"), tz = "GMT")
    df$Opentime_p <- as.POSIXct(as.POSIXlt(df$Opentime_p, tz = "GMT"), tz = "GMT")
    

    现在我们添加时间:

    df$Opentime_p <- df$Opentime_p + (df$Opentime - floor(df$Opentime)) * 24 * 3600
    #  Closetime Opentime Closetime_p          Opentime_p
    #1     42613 42614.61  2016-08-31 2016-09-01 14:38:24
    #2     42612 42613.97  2016-08-30 2016-08-31 23:16:48
    #3     42614 42612.12  2016-09-01 2016-08-30 02:52:48
    

    【讨论】:

      【解决方案3】:

      像你一样转换为日期,然后转换为POSIXct

      首先,创建 data.frame(并注意我们如何设置列名):

      R> df <- data.frame(CloseT=c(42613, 42612, 42614), OpenT=c(42614.61, 42613.97, 42612.12))
      R> df
        CloseT   OpenT
      1  42613 42614.6
      2  42612 42614.0
      3  42614 42612.1
      R> 
      

      然后转换为日期:

      R> df$CloseT <- as.Date(df$CloseT, origin="1900-01-01")
      R> df$OpenT <- as.Date(df$OpenT, origin="1900-01-01")
      R> df
            CloseT      OpenT
      1 2016-09-02 2016-09-03
      2 2016-09-01 2016-09-02
      3 2016-09-03 2016-09-01
      R>
      

      最后,转换成POSIXct

      R> df$OpenT <- as.POSIXct(df$OpenT)
      R> df$CloseT <- as.POSIXct(df$CloseT)
      R> df
                     CloseT               OpenT
      1 2016-09-01 19:00:00 2016-09-03 09:38:24
      2 2016-08-31 19:00:00 2016-09-02 18:16:48
      3 2016-09-02 19:00:00 2016-08-31 21:52:48
      R> 
      

      如 Roland 所示,通过POSIXlt 可以设置时区。

      【讨论】:

        【解决方案4】:

        查看有关 date_decimal 的文档:

        一个 POSIXct 对象,其年份对应小数的整数部分。

        date <- ymd("2009-02-10")
        decimal <- decimal_date(date)  # 2009.11
        date_decimal(decimal) # "2009-02-10 UTC"
        

        因此,在您的示例中,它将 42614 解释为年份。

        尝试使用as.POSIXct。您可能必须指定时区,但如果您只需要增量,则不需要。下面我计算了时差:

        df <- data.frame(c(42613, 42612, 42614), c(42614.61, 42613.97, 42612.12))
        names(df) <- c("Closetime", "Opentime")
        df$Closetime <- as.POSIXct(as.Date(df$Closetime, origin = '1900-01-01'))
        df$Opentime <- as.POSIXct(as.Date(df$Opentime, origin = '1900-01-01'))
        df$delta <- df$Opentime - df$Closetime
        df
                    Closetime            Opentime      delta
        1 2016-09-01 20:00:00 2016-09-03 10:38:24  1.61 days
        2 2016-08-31 20:00:00 2016-09-02 19:16:48  1.97 days
        3 2016-09-02 20:00:00 2016-08-31 22:52:48 -1.88 days
        

        根据评论,如果您想确保显示的时间正确,则需要正确匹配时区。您可以在转换为as.POSIXct 后通过设置tzone 属性来执行此操作。

        df <- data.frame(c(42613, 42612, 42614), c(42614.61, 42613.97, 42612.12))
        names(df) <- c("Closetime", "Opentime")
        df$Closetime <- as.POSIXct(as.Date(df$Closetime, origin = '1900-01-01'))
        df$Opentime <- as.POSIXct(as.Date(df$Opentime, origin = '1900-01-01'))
        attr(df$Closetime, "tzone") <- "GMT"
        attr(df$Opentime, "tzone") <- "GMT"
        df$delta <- df$Opentime - df$Closetime
        df
        
           Closetime            Opentime      delta
        1 2016-09-02 2016-09-03 14:38:24  1.61 days
        2 2016-09-01 2016-09-02 23:16:48  1.97 days
        3 2016-09-03 2016-09-01 02:52:48 -1.88 days
        

        【讨论】:

        • 如果我想让Closetime 有时间00:00:00 处理所有值,我该怎么做?有没有我需要指定的参数?
        • 没关系,我可以使用lubridate::hour 和设置hour(df$Closetime) &lt;- 0 来实现。
        • 如果您的目标是计算两者之间的差异,这可能会影响您的计算。我将进行编辑以展示如何将其强制为 GMT 时区,以便 Closetime 保持没有一个小时。
        • @not_a_robot:如果您与对象处于同一时区,并且如果 h/m/d 都为零,则格式会删除它们,您只会看到日期。这是一个特性,而不是一个错误。
        猜你喜欢
        • 2018-05-11
        • 1970-01-01
        • 1970-01-01
        • 2020-05-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-07
        • 1970-01-01
        相关资源
        最近更新 更多