Why does TimeSeriesShift is just adding a fixed number of days?

I'd like to shift all contents of a TimeSeries object by one month. By shifting Feb. 1st I would expect to receive Mar. 1st.

However it's not the case for Mathematica:

dr = DateRange[{2012, 1, 1}, {2013, 1, 1}, {1, "Month"}];
ts = TimeSeries[{dr, RandomReal[{0, 1}, Length@dr]}\[Transpose]];
tss = TimeSeriesShift[ts, {1, "Month"}]
tss["Dates"] - ts["Dates"]
// {31 days,31 days,31 days,31 days,31 days,31 days,31 days,31 days,31 days,31 days,31 days,31 days,31 days}


So Mathematica just adds a fixed number of days which is a very different behavior from most of other software (MS Excel for one).

I'm asking for any tips on implementing a function that would: 1. shift a time series in a way that it will always return the same day of month in a shifted series; 2. or first/last day of month in case it is a first/last day of month in the original series.

• What should it do for January 29th? Jan 15 '15 at 23:10
• @AndyRoss, I would expect it to behave in the same way as DatePlus[{2014, 1, 29}, {1, "Month"}] which produces Feb. 28. The critical thing is that the function should return a date in the following month not the month after that month.
– iav
Jan 16 '15 at 13:09
• That's probably why TimeSeriesShift does what it does. Both TimeSeries and TemporalData require unique time stamps. Also many algorithms are particular About uniform vs irregular spacing which is only preserved by a uniform shift. Jan 16 '15 at 13:13
• I see the point. Yet in many application with more developed time series analysis packages (EViews or even in matlab packages) uniform spacing is defined a bit more naturally (fuzzy?). If the series is of monthly frequency it usually just means that there are no two observations for the same month. I mean it should be sufficient for most of the usual time series models. I might be mistaken though. ))
– iav
Jan 16 '15 at 13:24

To me this looks like an ambiguity in the docs when "Month" is specified as a possible shift because everything else implies a fixed shifting increment. If you really want to shift your data by a calendar month then try this:

monthShift[timeSeries_, months_] :=
Module[{ts = timeSeries},
ts[[2, 2, 1, 1]] = (DatePlus[#1, {months, "Month"}] &) /@
ts[[2, 2, 1, 1]]; ts]


Edit

Just to explain the use of Part, while TimeSeries returns a panelled object, with appearance controlled by the option:

SetSystemOptions["TypesetOptions" -> "IconicElidedForms" -> True/False]


the underlying stored data and other information can be obtained by reverting to InputForm (or programmatically by applying FullForm) which gives:

TemporalData[TimeSeries, {{{0.7949834094555914, 0.4347500722147044,
0.10713327154725061, 0.25342805865761253, 0.7948229764103827, 0.2102978027596214,
0.42632147952029165, 0.2416091155261224, 0.4974007836596186, 0.5213253136688505,
0.8890068839125953, 0.45179928777848866, 0.31725637968735665}},
{{{3537043200, 3539548800, 3542227200, 3544819200, 3547497600, 3550089600,
3552768000, 3555446400, 3558038400, 3560716800, 3563308800, 3565987200,
3568665600}}}, 1, {Continuous, 1}, {Discrete, 1}, 1,
{ValueDimensions -> 1, ResamplingMethod -> {Interpolation,
InterpolationOrder -> 1}}}, True, 10.]


From the above we can see that the dates (in absolute time) are part 2,2,1,1.

• It's rather strange that TimeSeriesShift would produce different results from DatePlus, isn't it? @Mike, thanks for your solution.
– iav
Jan 15 '15 at 22:27
• @iav As I said in the answer I think the intention is to have fixed increment shifts so therefore "Month" as a shift is a kind of documentation ambiguity -- it obviously cannot be a calendar month if the shift is a fixed increment. Jan 15 '15 at 22:34
• @iav someone else might have some other solution or explanation so I suggest wait a day and see what eventuates and then close this question off Jan 15 '15 at 22:35