Создание формата года/недели для текущей даты в R

Я пишу этот пост, потому что я не мог найти другую тему, где уже был дан ответ на этот вопрос.

Какой код лучше всего подходит для создания формата "y/w" (г – год из двух цифр, а w – номер недели из двух цифр) в R?
Пока что я использую следующее:

require(lubridate)
paste(substr(year(Sys.Date()),3,4),sprintf("%02d", isoweek(Sys.Date())), sep="/")

Но, конечно, это могло потерпеть неудачу в последние дни года или в первые; например, он может дать результат «16/53» на 1 января 2016 года (а должен быть «16/01»).

Я думаю о некоторой конструкции if-else, основанной на том, что Sys.Date выше или ниже, чем 1 января, и комбинирую ее с функцией wday, но я уверен, что должно быть более элегантное и лаконичное решение.

У вас есть какие-нибудь идеи по этому поводу?
Спасибо,
MZ


person MaZe    schedule 16.02.2015    source источник
comment
А как насчет format(Sys.Date(), "%Y-%U")?   -  person lukeA    schedule 16.02.2015
comment
почти прекрасно. Изменил его на format(Sys.Date(), "%y/%U", но он показывает, что сегодня все еще w7, а должен быть w8... Вот почему я использую isoweek вместо week в пакете смазки.   -  person MaZe    schedule 16.02.2015
comment
Я понимаю. Хм, однако, isoweek(as.Date("2016-01-01")) это 53, а не 1. Это то, что вы хотите? Потому что в этом случае я бы просто изменил функцию isoweek, чтобы она тоже возвращала год.   -  person lukeA    schedule 16.02.2015
comment
Я хочу 15/53, потому что это 53-я неделя 2015 года. Если вы попробуете с isoweek(as.Date(2015-01-01)), вы увидите, что в этом случае это 1-я неделя, поэтому мой может работать нормально (точно так же, как и до 31 декабря 2015 года).   -  person MaZe    schedule 16.02.2015


Ответы (4)


Возможно, вы захотите настроить lubridate::isoweek, чтобы вернуть нужную строку:

isodate <- function (x = Sys.Date()) {
  xday <- ISOdate(year(x), month(x), day(x), tz = tz(x))
  dn <- 1 + (wday(x) + 5)%%7
  nth <- xday + ddays(4 - dn)
  jan1 <- ISOdate(year(nth), 1, 1, tz = tz(x))
  return(sprintf("%s/%02d", format(nth, "%y"), 1 + (nth - jan1)%/%ddays(7)))
}
isodate(as.Date("2016-01-01"))
# [1] "15/53"
isodate(as.Date("2015-01-01"))
# [1] "15/01"
isodate(Sys.Date())
# [1] "15/08"
person lukeA    schedule 16.02.2015
comment
wow lukeA, это немного превышает мои навыки кодирования, и я потрачу несколько минут, чтобы узнать больше о вашем решении; тем не менее, это более или менее мое предполагаемое решение для резервного копирования (работает в будний день 1 января), но до сих пор я действительно озадачен тем, почему такая распространенная (?) полезная функция еще не решена в каком-то пакете или нет уже не спрашивали. Меня одного интересует ISO-версия года и недели? - person MaZe; 17.02.2015
comment
Что хорошо в R: введите имя функции — в данном случае isoweek — и вы получите ее исходный код. Затем я просто немного изменил его, чтобы он возвращал желаемый результат. Сам код превосходит мои навыки кодирования, вероятно, больше, чем ваши.... ;-) - person lukeA; 17.02.2015
comment
лол, верно. Я не думал взглянуть на функцию !!! :-) Большое спасибо, Люк! - person MaZe; 17.02.2015

Если вы находитесь здесь в 2018 году, попробуйте yearweek из чашка

library(tsibble)
library(tidyverse)

my_date <- "2018-01-01"

yearweek(my_date) %>% 
  str_replace(" W", "/") %>% 
  str_replace("^20", "")

#> [1] 17/52
person Vlad    schedule 03.10.2018
comment
Хотя эта ссылка может предоставить некоторую ограниченную немедленную помощь, ответ должен включать достаточный контекст вокруг ссылки, чтобы ваши коллеги-пользователи имели некоторое представление что это такое и почему оно там. Всегда цитируйте наиболее релевантную часть важной ссылки, чтобы сделать ее более полезной для будущих читателей с другими похожими вопросами. Кроме того, другие пользователи, как правило, отрицательно реагируют на ответы, которые не более чем ссылка на внешний сайт, и они может быть удален. - person Machavity♦; 03.10.2018
comment
альтернативно используя format.yearweek, например format(tsibble::yearweek("20180101"), "%V/%y") - person Earo Wang; 16.10.2018

Используя пакетную функцию lubridate isoyear() в сочетании с isoweek(), можно получить однострочный ответ на ваш вопрос.

library(stringr)
library(lubridate)

dates <- ymd(c("2016-01-01", "2015-12-31", "2015-01-01"))

# check dates[1] and dates[2] are in the same week
wday(dates)
#> [1] 6 5 5

str_c(
  formatC(isoweek(dates), format = "f", digits = 0, width = 2, flag = "0"), 
  "/", 
  str_sub(isoyear(dates), 3, 4))
#> [1] "53/15" "53/15" "01/15"

Создано 12 февраля 2021 г. с помощью пакета reprex (v0.3.0)

person josep maria porrà    schedule 12.02.2021

Замените isoweek() на week(), функцию от lubridate.

> paste(substr(year(x),3,4),sprintf("%02d", week(x)), sep="/")
[1] "16/01"
person Rahul Premraj    schedule 16.02.2015
comment
Спасибо, Рахул, но мне действительно нужно isoweek. Как я прокомментировал выше, week дал бы мне 7 за сегодняшнюю дату, но этот понедельник - первый день 8-й недели ISO... - person MaZe; 16.02.2015