Отформатировать половину года, содержащуюся в тексте, как даты - PullRequest
0 голосов
/ 17 сентября 2018

У меня есть значения даты, содержащиеся в тексте, каждое из которых содержит половину года:

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"

Сейчас моя работа заключается в том, чтобы заменить H2 на Q3:

lubridate::yq(stringr::str_replace(date_by_half,"H2", "Q3"))
#[1] "2016-01-01" "2017-07-01" "2018-01-01"

Однако мне интересно, есть ли более красноречивое решение, использующее lubridate (или другой быстрый и многократно используемый метод).

Ответы [ 3 ]

0 голосов
/ 17 сентября 2018

Мы можем использовать функцию 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"
0 голосов
/ 17 сентября 2018

Один лайнер

Эти однострочники используют только базу 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

Другой подход заключается в создании класса 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"
0 голосов
/ 17 сентября 2018

Вы можете сделать свою собственную функцию, чтобы сделать трюк.

# 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" 
...