Добавить месяц к дате
Я пытаюсь добавить месяц к дате, которую у меня есть. Но тогда это невозможно в прямой форме. Вот что я пробовал.
d <- as.Date("2004-01-31")
d + 60
# [1] "2004-03-31"
Добавление wont help, поскольку месяц не будет перекрываться.
seq(as.Date("2004-01-31"), by = "month", length = 2)
# [1] "2004-01-31" "2004-03-02"
Выше может работать, но опять же это не прямо.
Кроме того, он также добавляет 30 дней или что-то еще до даты, которая имеет такие проблемы, как ниже
seq(as.Date("2004-01-31"), by = "month", length = 10)
# [1] "2004-01-31" "2004-03-02" "2004-03-31" "2004-05-01" "2004-05-31" "2004-07-01" "2004-07-31" "2004-08-31" "2004-10-01" "2004-10-31"
В приведенном выше примере, для первых двух дат, месяц havent изменен.
Также следующий подход также не удался в течение месяца, но был успешным в течение года
d <- as.POSIXlt(as.Date("2010-01-01"))
d$year <- d$year +1
d
# [1] "2011-01-01 UTC"
d <- as.POSIXlt(as.Date("2010-01-01"))
d$month <- d$month +1
d
Ошибка в format.POSIXlt(x, usetz = TRUE)
: неверный аргумент "x"
Каков правильный способ сделать это?
Ответы
Ответ 1
Vanilla R имеет наивный класс difftime, но Lubridate CRAN позволяет делать то, что вы просите:
require(lubridate)
d <- as.Date('2004-01-01')
month(d) <- month(d) + 1
day(d) <- days_in_month(d)
d
[1] "2004-02-29"
Надеюсь, что это поможет.
Ответ 2
Функция %m+%
от lubridate добавляет один месяц без превышения последнего дня нового месяца.
library(lubridate)
(d <- ymd("2012-01-31"))
1 parsed with %Y-%m-%d
[1] "2012-01-31 UTC"
d %m+% months(1)
[1] "2012-02-29 UTC"
Ответ 3
Это неоднозначно, когда вы говорите "добавить месяц к дате".
Вы имеете в виду
- добавить 30 дней?
- увеличить месячную часть даты на 1?
В обоих случаях целый пакет для простого добавления кажется немного преувеличенным.
Для первой точки, конечно, простой оператор +
будет делать:
d=as.Date('2010-01-01')
d + 30
#[1] "2010-01-31"
Что касается второго, я бы просто создал одну линию так же просто, как и (и с более общей областью):
add.months= function(date,n) seq(date, by = paste (n, "months"), length = 2)[2]
Вы можете использовать его с произвольными месяцами, включая отрицательные:
add.months(d, 3)
#[1] "2010-04-01"
add.months(d, -3)
#[1] "2009-10-01"
Конечно, если вы хотите добавить только и часто один месяц:
add.month=function(date) add.months(date,1)
add.month(d)
#[1] "2010-02-01"
Если вы добавите один месяц до 31 января, с 31 февраля не имеет смысла, лучше всего выполнить задание - добавить отсутствующие 3 дня в следующий месяц, в марте. Итак, правильно:
add.month(as.Date("2010-01-31"))
#[1] "2010-03-03"
Если по какой-то особой причине вам нужно установить потолок в последний доступный день месяца, это немного дольше:
add.months.ceil=function (date, n){
#no ceiling
nC=add.months(date, n)
#ceiling
day(date)=01
C=add.months(date, n+1)-1
#use ceiling in case of overlapping
if(nC>C) return(C)
return(nC)
}
Как обычно, вы можете добавить одномесячную версию:
add.month.ceil=function(date) add.months.ceil(date,1)
Итак:
d=as.Date('2010-01-31')
add.month.ceil(d)
#[1] "2010-02-28"
d=as.Date('2010-01-21')
add.month.ceil(d)
#[1] "2010-02-21"
И с декрементами:
d=as.Date('2010-03-31')
add.months.ceil(d, -1)
#[1] "2010-02-28"
d=as.Date('2010-03-21')
add.months.ceil(d, -1)
#[1] "2010-02-21"
Кроме того, вы не указали, интересовали ли вы скалярное или векторное решение. Что касается последнего:
add.months.v= function(date,n) as.Date(sapply(date, add.months, n), origin="1970-01-01")
Примечание: *apply
семейство уничтожает данные класса, поэтому его необходимо перестроить.
В векторной версии:
d=c(as.Date('2010/01/01'), as.Date('2010/01/31'))
add.months.v(d,1)
[1] "2010-02-01" "2010-03-03"
Надеюсь, вам понравилось))
Ответ 4
"mondate"
несколько похож на "Date"
, за исключением того, что добавление n
добавляет n
месяцев, а не n
дней:
> library(mondate)
> d <- as.Date("2004-01-31")
> as.mondate(d) + 1
mondate: timeunits="months"
[1] 2004-02-29
Ответ 5
Здесь функция, которая не требует установки каких-либо пакетов. Вы даете ему объект Date
(или character
, который он может преобразовать в Date
), и он добавляет n
месяцев к этой дате без изменения дня месяца ( если на месяц, на который вы приземлились, в нем не хватает дней, и в этом случае он по умолчанию относится к последнему дню возвращенного месяца). На всякий случай это не имеет смысла читать его, есть несколько примеров ниже.
Определение функции
addMonth <- function(date, n = 1){
if (n == 0){return(date)}
if (n %% 1 != 0){stop("Input Error: argument 'n' must be an integer.")}
# Check to make sure we have a standard Date format
if (class(date) == "character"){date = as.Date(date)}
# Turn the year, month, and day into numbers so we can play with them
y = as.numeric(substr(as.character(date),1,4))
m = as.numeric(substr(as.character(date),6,7))
d = as.numeric(substr(as.character(date),9,10))
# Run through the computation
i = 0
# Adding months
if (n > 0){
while (i < n){
m = m + 1
if (m == 13){
m = 1
y = y + 1
}
i = i + 1
}
}
# Subtracting months
else if (n < 0){
while (i > n){
m = m - 1
if (m == 0){
m = 12
y = y - 1
}
i = i - 1
}
}
# If past 28th day in base month, make adjustments for February
if (d > 28 & m == 2){
# If it a leap year, return the 29th day
if ((y %% 4 == 0 & y %% 100 != 0) | y %% 400 == 0){d = 29}
# Otherwise, return the 28th day
else{d = 28}
}
# If 31st day in base month but only 30 days in end month, return 30th day
else if (d == 31){if (m %in% c(1, 3, 5, 7, 8, 10, 12) == FALSE){d = 30}}
# Turn year, month, and day into strings and put them together to make a Date
y = as.character(y)
# If month is single digit, add a leading 0, otherwise leave it alone
if (m < 10){m = paste('0', as.character(m), sep = '')}
else{m = as.character(m)}
# If day is single digit, add a leading 0, otherwise leave it alone
if (d < 10){d = paste('0', as.character(d), sep = '')}
else{d = as.character(d)}
# Put them together and convert return the result as a Date
return(as.Date(paste(y,'-',m,'-',d, sep = '')))
}
Некоторые примеры
Добавление месяцев
> addMonth('2014-01-31', n = 1)
[1] "2014-02-28" # February, non-leap year
> addMonth('2014-01-31', n = 5)
[1] "2014-06-30" # June only has 30 days, so day of month dropped to 30
> addMonth('2014-01-31', n = 24)
[1] "2016-01-31" # Increments years when n is a multiple of 12
> addMonth('2014-01-31', n = 25)
[1] "2016-02-29" # February, leap year
Вычитание месяцев
> addMonth('2014-01-31', n = -1)
[1] "2013-12-31"
> addMonth('2014-01-31', n = -7)
[1] "2013-06-30"
> addMonth('2014-01-31', n = -12)
[1] "2013-01-31"
> addMonth('2014-01-31', n = -23)
[1] "2012-02-29"
Ответ 6
addedMonth <- seq(as.Date('2004-01-01'), length=2, by='1 month')[2]
addedQuarter <- seq(as.Date('2004-01-01'), length=2, by='1 quarter')[2]
Ответ 7
Самый простой способ - преобразовать Date в формат POSIXlt.
Затем выполните арифметическую операцию следующим образом:
date_1m_fwd <- as.POSIXlt("2010-01-01")
date_1m_fwd$mon <- date_1m_fwd$mon +1
Кроме того, если вы хотите иметь дело с столбцами Date в data.table, к сожалению, формат POSIXlt не поддерживается.
Тем не менее вы можете выполнить месяц добавления с использованием основных R-кодов следующим образом:
library(data.table)
dt <- as.data.table(seq(as.Date("2010-01-01"), length.out=5, by="month"))
dt[,shifted_month:=tail(seq(V1[1], length.out=length(V1)+3, by="month"),length(V1))]
Надеюсь, что это поможет.
Ответ 8
Я превратил antonio мысли в определенную функцию:
library(DescTools)
> AddMonths(as.Date('2004-01-01'), 1)
[1] "2004-02-01"
> AddMonths(as.Date('2004-01-31'), 1)
[1] "2004-02-29"
> AddMonths(as.Date('2004-03-30'), -1)
[1] "2004-02-29"