Format date-time as seasons in R?
as.POSIXlt
returns a named list (which makes it unsuitable for data.frame columns). The list columns can be individually accessed and include "year" (1900-based, unlike 1970 used for default) and "mon" (0-based). Best place to see this list in hte help system is ?DateTimeClasses
:
First just a Seasons calculation, then a Year-Seasons calculation
c('DJF', 'MAM', 'JJA', 'SON')[ # select from character vector with numeric vector
1+((as.POSIXlt(dates)$mon+1) %/% 3)%%4]
[1] "JJA" "JJA" "SON" "SON" "DJF" "DJF" "DJF" "MAM" "MAM" "JJA"
[11] "JJA"
paste( 1900 + # this is the base year for POSIXlt year numbering
as.POSIXlt( dates )$year +
1*(as.POSIXlt( dates )$year==12) , # offset needed for December
c('DJF', 'MAM', 'JJA', 'SON')[ # indexing from 0-based-mon
1+((as.POSIXlt(dates)$mon+1) %/% 3)%%4]
, sep="-")
[1] "2014-JJA" "2014-JJA" "2014-SON" "2014-SON" "2014-DJF"
[6] "2015-DJF" "2015-DJF" "2015-MAM" "2015-MAM" "2015-JJA"
[11] "2015-JJA"
Shouldn't be that difficult to make a function that constructs the formatting you expect. This is just modulo arithmetic on the POSIXlt values for month and year.
Find which season a particular date belongs to
How about using something like this:
getSeason <- function(DATES) {
WS <- as.Date("2012-12-15", format = "%Y-%m-%d") # Winter Solstice
SE <- as.Date("2012-3-15", format = "%Y-%m-%d") # Spring Equinox
SS <- as.Date("2012-6-15", format = "%Y-%m-%d") # Summer Solstice
FE <- as.Date("2012-9-15", format = "%Y-%m-%d") # Fall Equinox
# Convert dates from any year to 2012 dates
d <- as.Date(strftime(DATES, format="2012-%m-%d"))
ifelse (d >= WS | d < SE, "Winter",
ifelse (d >= SE & d < SS, "Spring",
ifelse (d >= SS & d < FE, "Summer", "Fall")))
}
my.dates <- as.Date("2011-12-01", format = "%Y-%m-%d") + 0:60
head(getSeason(my.dates), 24)
# [1] "Fall" "Fall" "Fall" "Fall" "Fall" "Fall" "Fall"
# [8] "Fall" "Fall" "Fall" "Fall" "Fall" "Fall" "Fall"
# [15] "Winter" "Winter" "Winter" "Winter" "Winter" "Winter"
One note: 2012 is a good year to which to convert all of the dates; since it is a leap year, any February 29ths in your data set will be handled smoothly.
R Need to extract month and assign season
Regarding the subject/title of the question, its actually possible to do this without extracting the month. The first two solutions below do not extract the month. There is also a third solution which does extract the month but only to increment it.
1) as.yearqtr/as.yearmon Convert the dates to year/month and add one month (1/12). Then the calendar quarters correspond to the seasons so convert to year/quarter, yq
, and label the quarters as shown:
library(zoo)
yq <- as.yearqtr(as.yearmon(DF$dates, "%m/%d/%Y") + 1/12)
DF$Season <- factor(format(yq, "%q"), levels = 1:4,
labels = c("winter", "spring", "summer", "fall"))
giving:
dates Season
1 7/28/2010 summer
2 4/21/2011 spring
3 7/23/2010 summer
4 6/14/2011 summer
5 12/3/2010 winter
6 11/18/2010 fall
7 11/6/2010 fall
8 7/23/2010 summer
9 6/14/2011 summer
1a) A variation of this is to use chron's quarters
which produces a factor so that levels=1:4
does not have to be specified. To use chron replace the last line in (1) with:
library(chron)
DF$Season <- factor(quarters(as.chron(yq)),
labels = c("winter", "spring", "summer", "fall"))
chron could also be used in conjunction with the remaining solutions.
2) cut. This solution only uses the base of R. First convert the dates to the first of the month using cut
and add 32 to get a date in the next month, d
. The quarters corresponding to d
are the seasons so compute the quarters using quarters
and construct the labels in the same fashion as the first answser:
d <- as.Date(cut(as.Date(DF$dates, "%m/%d/%Y"), "month")) + 32
DF$Season <- factor(quarters(d), levels = c("Q1", "Q2", "Q3", "Q4"),
labels = c("winter", "spring", "summer", "fall"))
giving the same answer.
3) POSIXlt This solution also uses only the base of R:
p <- as.POSIXlt(as.Date(DF$dates, "%m/%d/%Y"))
p$day <- 1
p$mo <- p$mo+1
DF$Season <- factor(quarters(p), levels = c("Q1", "Q2", "Q3", "Q4"),
labels = c("winter", "spring", "summer", "fall"))
Note 1: We could optionally omit levels=
in all these solutions if we knew that every season appears.
Note 2: We used this data frame:
DF <- data.frame(dates = c('7/28/2010', '4/21/2011', '7/23/2010',
'6/14/2011', '12/3/2010', '11/18/2010', '11/6/2010', '7/23/2010',
'6/14/2011'))
Convert dates to season year
lubridate
package is your friend:
library(lubridate)
date <- c("08/08/15", "08/09/16")
# extract year information
year <- year(mdy(date))
# paste season
season <- paste0(year, "/", year + 1)
season
How to classify a given date/time by the season (e.g. summer, autumn)
Here are three possibilities, one using cut
, as suggested by @Spacedman in the comments, a second using findInterval
, and a third which uses a rolling join in data.table
. As discussed in the comments above, solstice and equinox dates are defined as onset of a Season. This may explain the difference between my output and OP:s (not yet edited) desired result. I leave the mapping of 'seas' to more sensible season names to you.
1. cut
Date.time$seastime <- as.POSIXct(cut(Date.time$datetime, seasonality$seastime))
Date.time <- merge(Date.time, seasonality)
Date.time[ , c("datetime", "seas")]
# datetime seas
# 1 2012-12-20 19:28:00 September Equinox
# 2 2012-12-25 21:08:00 December Solstice
# 3 2012-12-29 02:50:00 December Solstice
# snip
# 12 2013-03-12 02:24:00 December Solstice
# 13 2013-03-18 21:54:00 December Solstice
# 14 2013-03-24 04:50:00 March Equinox
# 15 2013-03-31 05:54:06 March Equinox
# 16 2013-04-01 03:52:00 March Equinox
# 17 2013-04-04 12:34:00 March Equinox
2. findInterval
seasonality <- seasonality[order(seasonality$seastime), ]
Date.time$seas <- seasonality$seas[findInterval(x = Date.time$datetime, vec = seasonality$seastime)]
Date.time
# datetime seas
# 1 2012-12-20 19:28:00 September Equinox
# 2 2012-12-25 21:08:00 December Solstice
# 3 2012-12-29 02:50:00 December Solstice
# snip
# 12 2013-03-12 02:24:00 December Solstice
# 13 2013-03-18 21:54:00 December Solstice
# 14 2013-03-24 04:50:00 March Equinox
# 15 2013-03-31 05:54:06 March Equinox
# 16 2013-04-01 03:52:00 March Equinox
# 17 2013-04-04 12:34:00 March Equinox
3. data.table
rolling join
library(data.table)
setDT(Date.time)
setDT(seasonality)
setkey(Date.time, datetime)
setkey(seasonality, seastime)
seasonality[Date.time, roll = Inf]
# seastime seas
# 1: 2012-12-20 19:28:00 September Equinox
# 2: 2012-12-25 21:08:00 December Solstice
# 3: 2012-12-29 02:50:00 December Solstice
# snip
# 12: 2013-03-12 02:24:00 December Solstice
# 13: 2013-03-18 21:54:00 December Solstice
# 14: 2013-03-24 04:50:00 March Equinox
# 15: 2013-03-31 05:54:06 March Equinox
# 16: 2013-04-01 03:52:00 March Equinox
# 17: 2013-04-04 12:34:00 March Equinox
# possibly rename 'seastime' here.
'Date.time' used here:
structure(list(datetime = structure(c(1356028080, 1356466080,
1356745800, 1357039920, 1357878240, 1360560720, 1360703160, 1361011320,
1361268360, 1361535000, 1361853000, 1363051440, 1363640040, 1364097000,
1364702046, 1364781120, 1365071640), class = c("POSIXct", "POSIXt"
), tzone = "")), .Names = "datetime", class = "data.frame", row.names = c(NA,
-17L))
Changing months to seasons
Here is an option where we create a named vector and use that to match and replace the 'Month' to create new column
library(dplyr)
nm1 <- setNames(rep(c("Winter", "Spring", "Summer", "Fall"),
each = 3), month.name)
df1 %>%
mutate(Season = nm1[Month])
-output
# Date Month Temperature Season
#1 2016-07-01 July 13 Summer
#2 2017-01-08 January 5 Winter
#3 2018-09-19 September 11 Summer
#4 2019-10-24 October 9 Fall
Or it can be done in base R
df1$Season = nm1[df1$Month]
data
df1 <- structure(list(Date = c("2016-07-01", "2017-01-08", "2018-09-19",
"2019-10-24"), Month = c("July", "January", "September", "October"
), Temperature = c(13L, 5L, 11L, 9L)), class = "data.frame",
row.names = c(NA,
-4L))
Convert Date String in Format Mon Day, Year Time am/pm to POSIXlt format in R?
You will want to use the format "%b %d, %Y %I:%M %p"
in as.POSIXlt()
%b
for the abbreviated month (in the current locale)%d
for the day%Y
for the full four-digit year%I
for the hour (when using%p
a.k.a am/pm)%M
for the minutes%p
for am/pm
So for a POSIXlt date-time, you can do
(x <- as.POSIXlt("Aug 19, 2015 07:09 am", format = "%b %d, %Y %I:%M %p"))
# [1] "2015-08-19 07:09:00 PDT"
As mentioned in the comments, you must have created the entire POSIX object in order to extract its parts (well, to formally extract them anyway).
months(x)
# [1] "August"
months(x, abbreviate = TRUE)
# [1] "Aug"
Additionally, in order to use strptime()
, you must plan on creating the entire date-time object as you cannot just create a month and have it classed as such. See help(strptime)
and help(as.POSIXlt)
for more.
Determine season from Date using lubridate in R
I packaged @Lars Arne Jordanger's much more elegant approach into a function:
getTwoSeasons <- function(input.date){
numeric.date <- 100*month(input.date)+day(input.date)
## input Seasons upper limits in the form MMDD in the "break =" option:
cuts <- base::cut(numeric.date, breaks = c(0,415,1015,1231))
# rename the resulting groups (could've been done within cut(...levels=) if "Winter" wasn't double
levels(cuts) <- c("Winter", "Summer","Winter")
return(cuts)
}
Testing it on some sample data seems to work fine:
getTwoSeasons(as.POSIXct("2016-01-01 12:00:00")+(0:365)*(60*60*24))
Related Topics
How to Split an Igraph into Connected Subgraphs
Is There a Predict Function for Plm in R
How to Plot a Heat Map on a Spatial Map
How to Read the Source Code for an R Function
Fitting a Curve to Specific Data
Calculating Percentile of Dataset Column
Count the Number of Non-Zero Elements of Each Column
Plotting a "Sequence Logo" Using Ggplot2
How to Extend Letters Past 26 Characters E.G., Aa, Ab, Ac...
How to Merge Two Data Frames on Common Columns in R with Sum of Others
Annotate Values Above Bars (Ggplot Faceted)
How to Produce a Heatmap with Ggplot2
As.Numeric() Removes Decimal Places in R, How to Change
Correct Number of Decimal Places Reading in a .Csv
Different Axis Limits Per Facet in Ggplot2
How to Write Contents of Help to a File from Within R
Convert a Dataframe to an Object of Class "Dist" Without Actually Calculating Distances in R