[R] Truncating dates (and other date-time manipulations)

Jeffrey J. Hallman jhallman at frb.gov
Fri Sep 12 15:44:50 CEST 2008


"hadley wickham" <h.wickham at gmail.com> writes:

> dates <- structure(c(8516, 8544, 8568, 8596, 8609, 8666, 8701, 8750, 8754,
> 8798, 8811, 8817, 8860, 8873, 8918, 8931, 8966, 9020, 9034, 9056
> ), class = "Date")
>
>> range(dates)
> [1] "1993-04-26" "1994-10-18"
>> as.Date(ti(range(dates), "monthly"))
> [1] "1993-04-30" "1994-10-31"
>> as.Date(ti(range(dates), "annual"))
> [1] "1993-12-31" "1994-12-31"
>
> What's the easiest way to control whether the dates are rounded up or
> down?  

> dates
 [1] "1993-04-26" "1993-05-24" "1993-06-17" "1993-07-15" "1993-07-28"
 [6] "1993-09-23" "1993-10-28" "1993-12-16" "1993-12-20" "1994-02-02"
[11] "1994-02-15" "1994-02-21" "1994-04-05" "1994-04-18" "1994-06-02"
[16] "1994-06-15" "1994-07-20" "1994-09-12" "1994-09-26" "1994-10-18"

A ti represents a period, not a date. So 

> ti(dates, "monthly")
 [1] 19930430 19930531 19930630 19930731 19930731 19930930 19931031 19931231
 [9] 19931231 19940228 19940228 19940228 19940430 19940430 19940630 19940630
[17] 19940731 19940930 19940930 19941031
class: ti

is giving you ti's for the months.  The print method for ti shows the last
yyyymmdd date for the period, but the ti's actually represent the months, not
their last days.  You can see this if you do this:

> format(ti(dates, "monthly"), "%b %Y")
 [1] "Apr 1993" "May 1993" "Jun 1993" "Jul 1993" "Jul 1993" "Sep 1993"
 [7] "Oct 1993" "Dec 1993" "Dec 1993" "Feb 1994" "Feb 1994" "Feb 1994"
[13] "Apr 1994" "Apr 1994" "Jun 1994" "Jun 1994" "Jul 1994" "Sep 1994"
[19] "Sep 1994" "Oct 1994"

When you convert the months to Dates with as.Date(), then you get the dates
for the ends of the months. 

If you want ti's for the months just before the months your dates fell into,
just subtract 1., i.e.,

> ti(dates, "monthly") - 1
 [1] 19930331 19930430 19930531 19930630 19930630 19930831 19930930 19931130
 [9] 19931130 19940131 19940131 19940131 19940331 19940331 19940531 19940531
[17] 19940630 19940831 19940831 19940930
class: ti

> And to get the starting period I just subtract one from the ti
> object and then add one to the Date object?
That will work, or you can do

firstDayOf(ti(dates, "monthly"))

to get a vector with "daily" ti's for the first days of the months that
'dates' fell into, and you can use as.Date() on that, if you want to convert
them to a Date object.

> Is there any standard way to do multiples of periods?  (e.g. 3 weeks,
> 4 days).  

If you want this week and every third week after that, you can do this:

> seq(ti(today(), "wsaturday"), by = 3, len = 4)
[1] 20080913 20081004 20081025 20081115
class: ti

which is equivalent to;

> ti(today(), "wsaturday") + 3*(0:3)
[1] 20080913 20081004 20081025 20081115
class: ti

> And is the finest resolution of a ti object a day?  I don't
> think I see any periods less than that in the output of tif()

The output of tif() does not show all the hourly, minutely, and secondly
frequencies because there are so many possibilities.  Here is the help page
that 

? hourly

shows you:
-------------------------------------------------------------------------
R support for FAME-style Intraday frequencies

Description:

     create 'tif' (TimeIndexFrequency) codes for hourly, minutely, and
     secondly 'ti''s.

Usage:

       hourly(n = 0)
     minutely(n = 0)
     secondly(n = 0)

Arguments:

       n: number of base periods to skip.  That is, 'hourly(2)' gives a
          'tif' code for a series observed every 2nd hour, while both
          'minutely()' and 'minutely(1)' are for a series observed once
          per minute, 'secondly(30)' means every 30 seconds, and so on.

Details:

     The current implementation has hourly(n) -> 2000 + n, minutely(n)
     -> 3000 + n, and secondly(n) -> 4000 + n.  If 'n' divides evenly
     into 3600 for 'secondly(n)', the return code will be the same as
     'hourly(n/3600)'.  For 'secondly(n)' and 'minutely(n)', if 'n'
     divides evenly into 60, the return code will be as if
     'minutely(n/60)' or 'hourly(n/60)' had been called, respectively.

     For 'hourly(n)', 'n' must evenly divide into 24 and be less than
     24, i.e., 'n' is one of 1, 2, 3, 4, 6, 8, 12.  For 'minutely(n)',
     'n' must be an even divisor of 1440, and less than 720.  For
     'secondly(n)', 'n' must divide evenly into 86400, and be no larger
     than 960.

Value:

     An integer 'tif' code.
-------------------------------------------------------------------------

So to create a ti object for every quarter-hour starting right now, I could
do:

> seq(ti(Sys.time(), minutely(15)), by = 1, len = 12)
 [1] 20080912:09:30:00 20080912:09:45:00 20080912:10:00:00 20080912:10:15:00
 [5] 20080912:10:30:00 20080912:10:45:00 20080912:11:00:00 20080912:11:15:00
 [9] 20080912:11:30:00 20080912:11:45:00 20080912:12:00:00 20080912:12:15:00
class: ti

and if I wanted one every 45 minutes, I could do this:

> seq(ti(Sys.time(), minutely(15)), by = 3, len = 12)
 [1] 20080912:09:30:00 20080912:10:15:00 20080912:11:00:00 20080912:11:45:00
 [5] 20080912:12:30:00 20080912:13:15:00 20080912:14:00:00 20080912:14:45:00
 [9] 20080912:15:30:00 20080912:16:15:00 20080912:17:00:00 20080912:17:45:00
class: ti

There's really a lot you can do with a ti.

-- 
Jeff



More information about the R-help mailing list