Ich versuche, einem Datum, das ich habe, einen Monat hinzuzufügen. Aber dann ist es noch nicht direkt möglich. Folgendes habe ich versucht.
d <- as.Date("2004-01-31")
d + 60
# [1] "2004-03-31"
Das Hinzufügen hilft nicht, da sich der Monat nicht überschneidet.
seq(as.Date("2004-01-31"), by = "month", length = 2)
# [1] "2004-01-31" "2004-03-02"
Oben könnte funktionieren, aber wieder ist es nicht einfach. Außerdem werden dem Datum 30 Tage oder so etwas hinzugefügt, was Probleme wie die folgenden hat
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"
In den ersten beiden oben genannten Daten hat sich der Monat nicht geändert.
Der folgende Ansatz schlug ebenfalls monatelang fehl, war jedoch jahrelang erfolgreich
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
Fehler in
format.POSIXlt(x, usetz = TRUE)
: ungültiges 'x' Argument
Was ist die richtige Methode, um dies zu tun?
Funktion %m+%
von lubridate fügt einen Monat hinzu, ohne den letzten Tag des neuen Monats zu überschreiten.
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"
Es ist mehrdeutig, wenn Sie "einem Datum einen Monat hinzufügen" sagen.
Meinst du
In beiden Fällen erscheint ein ganzes Paket für eine einfache Addition etwas übertrieben.
Für den ersten Punkt ist natürlich das einfache +
Operator erledigt:
d=as.Date('2010-01-01')
d + 30
#[1] "2010-01-31"
Was die zweite betrifft, würde ich einfach eine einzeilige Funktion erstellen (und mit einem allgemeineren Geltungsbereich):
add.months= function(date,n) seq(date, by = paste (n, "months"), length = 2)[2]
Sie können es mit beliebigen Monaten verwenden, einschließlich negativ:
add.months(d, 3)
#[1] "2010-04-01"
add.months(d, -3)
#[1] "2009-10-01"
Natürlich, wenn Sie nur und oft einen einzelnen Monat hinzufügen möchten:
add.month=function(date) add.months(date,1)
add.month(d)
#[1] "2010-02-01"
Wenn Sie den 31. Januar um einen Monat verlängern, da der 31. Februar bedeutungslos ist, sollten Sie die fehlenden 3 Tage zum folgenden Monat, dem März, addieren, um die Aufgabe zu erledigen. Also richtig:
add.month(as.Date("2010-01-31"))
#[1] "2010-03-03"
Falls Sie aus einem ganz besonderen Grund eine Obergrenze für den letzten verfügbaren Tag des Monats festlegen müssen, ist diese etwas länger:
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)
}
Wie üblich können Sie eine einmonatige Version hinzufügen:
add.month.ceil=function(date) add.months.ceil(date,1)
So:
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"
Und mit Dekrementen:
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"
Außerdem haben Sie nicht gesagt, ob Sie sich für eine Skalar- oder Vektorlösung interessieren. Letzteres:
add.months.v= function(date,n) as.Date(sapply(date, add.months, n), Origin="1970-01-01")
Hinweis: *apply
Familie zerstört die Klassendaten, deshalb muss sie neu erstellt werden. Die Vektorversion bringt:
d=c(as.Date('2010/01/01'), as.Date('2010/01/31'))
add.months.v(d,1)
[1] "2010-02-01" "2010-03-03"
Hoffe es hat euch gefallen))
"mondate"
ist etwas ähnlich zu "Date"
mit der Ausnahme, dass durch Hinzufügen von n
n
Monate anstelle von n
Tagen hinzugefügt werden:
> library(mondate)
> d <- as.Date("2004-01-31")
> as.mondate(d) + 1
mondate: timeunits="months"
[1] 2004-02-29
Der einfachste Weg ist die Konvertierung von Date in das POSIXlt-Format. Führen Sie dann die arithmetische Operation wie folgt aus:
date_1m_fwd <- as.POSIXlt("2010-01-01")
date_1m_fwd$mon <- date_1m_fwd$mon +1
Außerdem wird das POSIXlt-Format leider nicht unterstützt, wenn Sie sich mit Datumsspalten in data.table befassen möchten.
Trotzdem können Sie den Monat hinzufügen, indem Sie die grundlegenden R-Codes wie folgt verwenden:
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))]
Ich hoffe es hilft.
Hier ist eine Funktion, für die keine Pakete installiert werden müssen. Sie geben ihm ein Date
-Objekt (oder ein character
, das er in ein Date
konvertieren kann) und fügt diesem Datum n
Monate hinzu ohne den Tag des Monats zu ändern ( es sei denn der Monat, auf dem Sie landen, enthält nicht genügend Tage. In diesem Fall ist die Standardeinstellung aktiviert bis zum letzten Tag des zurückgegebenen Monats). Nur für den Fall, dass es keinen Sinn macht, es zu lesen, gibt es einige Beispiele unten.
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's 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"
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]
Ich habe Antonios Gedanken in eine bestimmte Funktion verwandelt:
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"