我在文本中包含日期值,每个日期值包含半年的时间:
date_by_half <- c("2016 H1", "2017 H2", "2018 H1")
我想从文本中提取日期并将其存储为每半或“学期”的第一天。因此,类似:
ysemester(date_by_half)
#[1] "2016-01-01" "2017-07-01" "2018-01-01"
我熟悉lubridate::yq()
函数,但是我发现它仅适用于四分之一。
lubridate::yq(date_by_half)
#[1] "2016-01-01" "2017-04-01" "2018-01-01"
现在我的解决方法是用Q3替换H2:
lubridate::yq(stringr::str_replace(date_by_half,"H2", "Q3"))
#[1] "2016-01-01" "2017-07-01" "2018-01-01"
但是,我想知道是否有使用lubridate
(或其他一些快速且可重用的方法)更雄辩的解决方案。
答案 0 :(得分:2)
这些单线仅使用基数R:
1)read.table / ISOdate
with(read.table(text = date_by_half), as.Date(ISOdate(V1, ifelse(V2=="H1",1,7), 1)))
## [1] "2016-01-01" "2017-07-01" "2018-01-01"
2)sub 更短的是:
as.Date(sub(" H2", "-7-1", sub(" H1", "-1-1", date_by_half)))
## [1] "2016-01-01" "2017-07-01" "2018-01-01"
另一种方法是为半年日期创建一个S3类"half"
。我们只会实现所需的方法。
as.half <- function(x, ...) UseMethod("as.half")
as.half.character <- function(x, ...) {
year <- as.numeric(sub("\\D.*", "", x))
half <- as.numeric(sub(".*\\D", "", x))
structure(year + (half - 1)/2, class = "half")
}
as.Date.half <- function(x, ...) {
as.Date(ISOdate(as.integer(x), 12 * (x - as.integer(x)) + 1, 1))
}
# test
as.Date(as.half(date_by_half))
## [1] "2016-01-01" "2017-07-01" "2018-01-01"
答案 1 :(得分:0)
您可以创建自己的函数来完成技巧。
# Your data
date_by_half <- c("2016 H1", "2017 H2", "2018 H1")
# Function to do the work
year_dater <- function(dates) {
year <- substr(dates, 1, 4)
quarter <- substr(dates, 6, 7)
month <- ifelse(quarter=="H1", 1, 7)
dates <- paste0(year, "-", month, "-", rep(1, length(month)))
return(dates)
}
# Running the function
dates <- year_dater(date_by_half)
# As date format
as.POSIXct(dates)
"2016-01-01 CET" "2017-07-01 CEST" "2018-01-01 CET"
答案 2 :(得分:0)
我们可以使用ceiling_date
中的lubridate
函数,单位为“半年”,并将change_on_boundary
参数设置为FALSE
,以便边界日期(2018-01-01 ,2017-07-01等)永远不会与yq
函数一起四舍五入。
library(lubridate)
ceiling_date(yq(date_by_half), unit = "halfyear", change_on_boundary = FALSE)
#[1] "2016-01-01" "2017-07-01" "2018-01-01"