60

The title has it: how do you convert a POSIX date to day-of-year?

M--
  • 25,431
  • 8
  • 61
  • 93
Gregor Thomas
  • 136,190
  • 20
  • 167
  • 294

5 Answers5

74

An alternative is to format the "POSIXt" object using strftime():

R> today <- Sys.time()
R> today
[1] "2012-10-19 19:12:04 BST"
R> doy <- strftime(today, format = "%j")
R> doy
[1] "293"
R> as.numeric(doy)
[1] 293

which is preferable to remembering that the day of the years is zero-based in the POSIX standard.

Gavin Simpson
  • 170,508
  • 25
  • 396
  • 453
  • Just ran into my first data set with a `POSIXct` column. Seemed like time to mark yours as the accepted answer. – Gregor Thomas Dec 04 '12 at 19:38
  • @Gavin, is it also possible to convert a date to days since a specified data, e.g.number of days since March 1st 2015? I can also post as a new question... – B. Davis Aug 11 '15 at 12:06
  • 2
    @B.Davis You can do something like `as.numeric(Sys.Date()-as.Date('2015-03-01',format='%Y-%m-%d'))` – Henry Jan 05 '16 at 15:32
38

As ?POSIXlt reveals, a $yday suffix to a POSIXlt date (or even a vector of such) will convert to day of year. Beware that POSIX counts Jan 1 as day 0, so you might want to add 1 to the result.

It took me embarrassingly long to find this, so I thought I'd ask and answer my own question.

Alternatively, the excellent lubridate package provides the yday function, which is just a wrapper for the above method. It conveniently defines similar functions for other units (month, year, hour, ...).

today <- Sys.time()
yday(today)
Community
  • 1
  • 1
Gregor Thomas
  • 136,190
  • 20
  • 167
  • 294
  • Part of why it took me so long is that if `d` is a POSIXlt object, `str(d)` gives no indication that `d` has any further attributes. This, and that the `$` operator works element-wise on a vector of POSIXlt objects means more than just a usual extraction is going on. I'd be interested in reading a bit more about that if anyone can recommend a nice place to start. – Gregor Thomas Oct 31 '11 at 20:43
  • And, to respond to my own comment, `attributes` is the command I was looking for, `attributes(d)` provides all the ways of displaying `d`. – Gregor Thomas Dec 15 '11 at 22:30
  • Heh, I was struggling with this question too. Seems that you answered it yourself (as opposed to just doing it without posting it here). Thanks for that! – Mikko Jul 03 '12 at 10:07
  • 3
    Note that this will only work with an object of class `"POSIXlt"`. The other major class is `"POSIXct"` and that is stored internally in a very different way. Try your method on the output of `Sys.time()` for example. The `strftime()` approach works with both types. – Gavin Simpson Oct 19 '12 at 19:02
  • A warning from my side. Remember to use `yday` on POSIXct object only! `yday` runs on character without any error message, moreover giving reasonable doy number. However, these doy will be wrong. – FraNut Nov 07 '22 at 16:21
  • @FraNut I'm not sure really what you're saying. Lubridate's `yday()` works very well on `POSIXct`, `POSIXlt` and `Date` class. It also works on `character` in standard formats, e.g., `yday("2020-01-10")` gives 10, and `yday("2020-12-10")` gives 345, both are correct. If you have an example of running `yday` on a character and getting reasonable but wrong doy numbers, please show an example and consider filing a bug on `lubridate` github. – Gregor Thomas Nov 07 '22 at 17:57
  • @GregorThomas, if I run `yday("15/06/2021")` on my Rstudio I get `171`, while the correct answer is `166`. No error message is showed. Thanks for the hint on character in standard formats. Maybe slash is the issue. The absence of an error message and the fact the result seems reasonable is really tricky tough. – FraNut Nov 08 '22 at 09:34
  • @FraNut The not-YMD format is the issue. Internally, lubridate will run `as.Date("15/06/2021")`, which happily returns "0015-06-20", assuming year, month, day (with some extra). You're right that you shouldn't just assume date conversions on character strings work, but "only POSIXct" is much too far in the opposite direction. – Gregor Thomas Nov 08 '22 at 13:54
4

I realize it isn't quite what the poster was looking for, but I needed to convert POSIX date-times into a fractional day of the year for time series analysis and ended up doing this:

today <- Sys.time()

doy2015f<-difftime(today,as.POSIXct(as.Date("2015-01-01 00:00", tzone="GMT")),units='days')
Dave X
  • 4,831
  • 4
  • 31
  • 42
2

The data.table package also provides a yday() function.

require(data.table)
today <- Sys.time()
yday(today)
andschar
  • 3,504
  • 2
  • 27
  • 35
1

This is the way how I do it:

as.POSIXlt(c("15.4", "10.5", "15.5", "10.6"), format = "%d.%m")$yday
# [1] 104 129 134 160
Tomas
  • 57,621
  • 49
  • 238
  • 373
  • Works well for `POSIXlt` (as mentioned in my answer), but not for `POSIXct` objects. E.g., `Sys.time()$yday` doesn't work. – Gregor Thomas Nov 04 '15 at 18:09