我需要计算“多少x
单位” POSIX日期向量中的每个元素都来自给定的参考日期,其中
x
是“典型”时间单位,例如月,周,季度等。numeric
向量我有一些东西,但它不是一种可以推广的一致方法(月和周的两种不同方法)。
可能一文不值:我一般都在寻找符合ISO 8601
的解决方案“一致”在某种意义上说,我理想地说,一个解决方案总是在as.numeric(dates)
之后利用一些聪明的“时间单位分箱”。但是对于月我不会看到如何实现这一点,因为每个月包含不同的天数(工作数周,因为我们总能安全地说“一周包含7天”)。
换句话说:对于月我想使用(as.numeric(.x) / (<something>))
之类的内容,就像我使用(as.numeric(.x) / (60 * 60 * 24 * 7))
周一样。这就是 <something>
,我正在寻找一种通用的方法来区分日期差异。
功能定义:
library(magrittr)
library(purrr)
normalize_time_distance_month <- function(dates) {
dates %>%
as.POSIXct() %>%
purrr::map_dbl(function(.x)
as.numeric(format(.x, "%y")) * 12 + as.numeric(format(.x, "%m")))
}
normalize_time_distance_week <- function(dates) {
dates %>%
as.POSIXct() %>%
purrr::map_dbl(function(.x)
(as.numeric(.x) / (60 * 60 * 24 * 7)) %>%
round())
}
个月:
# Months ------------------------------------------------------------------
dates <- seq(as.POSIXct("2018-03-01"), length.out = 24, by = "month")
origin <- as.POSIXct("2018-05-01")
dates_norm <- normalize_time_distance_month(dates)
origin_norm <- normalize_time_distance_month(origin)
(time_diffs <- dates_norm - origin_norm)
#> [1] -2 -1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
#> [24] 21
周:
# Weeks -------------------------------------------------------------------
dates <- seq(as.POSIXct("2018-05-07"), length.out = 104, by = "week")
origin <- as.POSIXct("2018-05-21")
dates_norm <- normalize_time_distance_week(dates)
origin_norm <- normalize_time_distance_week(origin)
(time_diffs <- dates_norm - origin_norm)
#> [1] -2 -1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
#> [18] 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
#> [35] 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
#> [52] 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
#> [69] 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
#> [86] 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
#> [103] 100 101
由reprex package(v0.2.0)创建于2018-05-25。
答案 0 :(得分:1)
一种选择是将表达式作为参数传递,然后解析它
library(tidyverse)
library(rlang)
normalize_time_distance <- function(dates, expr) {
dates %>%
as_tibble %>%
mutate(value = as.POSIXct(value)) %>%
mutate(value = !! parse_expr(expr)) %>%
pull(value)
}
expr1 <- 'as.numeric(format(value, "%y")) * 12 + as.numeric(format(value, "%m"))'
normalize_time_distance(dates, expr1)
#[1] 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
#[20] 238 239 240 241 242
expr2 <- 'round((as.numeric(value) / (60 * 60 * 24 * 7)))'
normalize_time_distance(dates, expr2)
#[1] 2513 2517 2522 2526 2530 2535 2539 2544 2548 2552 2557 2561 2565 2570 2574
#[16] 2578 2583 2587 2591 2596 2600 2604 2609 2613
答案 1 :(得分:1)
如果您对一天的倍数间隔感兴趣,那么使用POSIXt类是没有意义的。它只会产生时区错误的可能性,你可以通过使用Date类完全阻止它,所以从这里我们将假设Date类。 as.Date可用于将POSIXct对象转换为Date对象。
您的问题中有两个不同的案例。间隔为一天(天,周)的倍数,间隔是一个月的倍数(月,季,年)。这些必须单独处理,因为一个月内没有固定的天数。
如果间隔长度是d天,那么如果x和y是Date类对象的话 间隔数是
# x and y are Date class
(as.numeric(y) - as.numeric(x)) / d
其中d为1天,7周为。
如果间隔长度是m个月,那么如果x和y是Date类对象:
library(zoo)
date2ym <- function(x) {
ym <- as.yearmon(x)
b <- as.numeric(as.Date(ym))
e <- as.numeric(as.Date(ym, frac = 1))
12 * as.numeric(ym) + (as.numeric(x) - b) / (e - b + 1)
}
# x and y are Date class
(date2ym(y) - date2ym(x)) / m
其中m
为1个月,3个为季度,12个为年。
修复(2)。