Where is the date tossing useful?
I am reading Phobos docs. Sometimes I cannot understand the logic of some methods.
Adds the specified number of years or months to this date. A negative number will be subtracted. The difference between rolling and adding is that rolling does not affect larger units.
Maybe Phobos doesn't understand well, maybe I don't understand where this can be useful.
If I add, for example, 200 days to 2013-07-01, I expect to get 2014, but not 2013.
Can anyone explain the logic?
source to share
roll
also present in Java ... The only time I remember ever using it in any language but using a little date picker widget. There are separate fields for each thing: month, day, year, and you want the user to be able to scroll through the days without increasing the month as they are separate fields. (Suppose it's set to 30 and they want to select 1st. The fastest way is to just press the up arrow and let it flip.)
There may be other uses, I just don't remember them right now. Even when I was doing tech support some time ago (patented unfortunately), I never used the roll method, but there might be potential. ical is the standard for recurring events in calendars and there are some tricky things and a few different ways to implement it.
In the comment, you also ask why you can't add
days. The reason is that adding days is pretty trivial and covered opBinary
:
datetime += 5.days; // works
This does NOT work for months because months are of variable duration. This is when the method add
comes in to help: let's say it's January 30th and you add one month. You can only add 31 days as there are 31 days in January. That would land you on March 2nd (I think I'm doing it in my head) ... but January 30th + 1 month might also take February 28th. Or maybe February 29th. Suppose you pay your monthly bill at the end of the month, the number of days between these periods will change.
The method add
handles this and gives you the option to fall on the last day or spill over into the next month.
Although, I would say that days have no static length .... consider a DST transition. (Or leap seconds, but handling them would be a nut). Maybe we can ask JMD.
source to share
So the short answer is that Adam is right , and roll
there is specifically for handling date pickers and similar use cases , and add
there is especially for handling months and years, because he Duration
can't (since months and years are not converted to hecto-nanoseconds, not knowing the starting point). But I will attach a more detailed answer to it if that clarifies the situation.
DateTime
, Date
and TimeOfDay
are intended for calendar operations. They are not related to the system clock, they have no concept of time zone, and they contain the date / time parts as separate units (year, month, day, hour, etc.) internally. So, when you set a field hour
to DateTime
, you are literally just adjusting one of the member variables DateTime
. And when you add to them Duration
, it needs to be split to add to each module individually, and so doing something like adding Duration
from 7 hours can increase more than just the field hour
. eg.
auto dt = DateTime(2015, 8, 2, 20, 0, 0); dt += hours(7); assert(dt == DateTime(2015, 8, 3, 3, 0, 0));
And since it Duration
stores its value inside hecto-nanoseconds, you don't necessarily add to a specific unit anyway. those. it doesn't look like the += hours(7)
one that specifically adds to the field hour
. He adds a certain amount of hecto-nanoseconds in general DateTime
and needs to figure out how this affects each of the units, rather than affecting a specific unit. eg.
auto dt = DateTime(2015, 8, 2, 20, 0, 0); dt += hours(7) + minutes(5) + seconds(22); assert(dt == DateTime(2015, 8, 3, 3, 5, 22));
roll
on the other hand, specifically to add to a specific unit, without affecting any of the others. As Adam correctly identified, its main use case was for spin control and the like. In the date picker dialog, where you end up adjusting a specific unit of time by some amount, and you don't want to influence other units, you are adjusting. So, if you add 7 hours, you don't get a day gain, just hours.
auto dt = DateTime(2015, 8, 2, 20, 0, 0);
dt.roll!"hours"(7);
assert(dt == DateTime(2015, 8, 2, 3, 0, 0));
Now things get a little funnier with months and years, because they don't have a fixed length. And therefore Duration
does not support them. You cannot say that x
hecto-nanoseconds is equivalent to y
months or z
years. But while it Duration
doesn't make sense for months or years, we still want to be able to add months and years to Date
or DateTime
. So we have add!"years"
and add!"months"
to deal with this, and it allows you to control some oddities, such as adding 1 month to January 31st should end in late February or early March (since there is no February 31st).
None of this takes into account any time zone. This is purely a matter of calendar time. add
and roll
are purely calendar operations, but +=
implemented in DateTime
, Date
and TimeOfDay
is a calendar-based operation. It takes years, months, days, etc. into account when it does its calculations (and cannot do otherwise in its case, since the units are shared between their member variables).
And then we have SysTime
. It is designed to represent the system time (which means taking into account the time zone). However, the only way to avoid problems with DST and the like is to always keep the time in UTC. This way it SysTime
always stores its time inside UTC (in hectoniseconds) and uses the object TimeZone
( LocalTime
by default) to convert it to a specific timezone only when needed. This avoids all sorts of annoying time-related errors. And anyone who works at system time should use SysTime
, not DateTime
, Date
or TimeOfDay
.
So when you add in SysTime
with +=
, you are really adding hecto-nanoseconds from Duration
to hecto-nanoseconds that it SysTime
uses internally. No calendaring is happening (and if they did, you would have a lot of DST related errors). SysTime
is not calendar at all. In order to perform any calendar operations, the SysTime
hecto-nanoseconds it contains internally must be converted to whatever it represents in terms of a date in the Gregorian calendar (using an object TimeZone
to account for the time zone).
However, to be user-friendly, SysTime
it provides a lot of calendar properties and functions performed DateTime
(eg, year
, month
, day
, hour
,, etc. and functions add
, and roll
). To support this, it basically finishes converting to Date
or DateTime
internally to execute them, which means considering the time zone and which potentially means introducing DST errors if not used correctly. And in some cases, it's annoyingly ineffective. For example, if you have a variable SysTime
calledst
auto year = st.year;
auto month = st.month;
auto day = st.day;
converts st
to Date
three times, while it would be more efficient to simply convert to Date
clearly and get units there. So this user-friendliness is a bit of a double-edged sword.
It also begs the question that Adam raised the issue of how to add and roll with DST. roll
and add
on SysTime
interact with Date
or DateTime
internally, and this takes DST into account as converting from SysTime
to Date
or DateTime
converting it from UTC to regardless of its object TimeZone
. So, roll
u add
work on SysTime
exactly how they work on DateTime
- because they get converted to DateTime
and from.
But, as I said, +=
to SysTime
simply adds Duration
to its UTC time. Thus, it is SysTime
not possible to add units of measure less than months and take into account DST. You would explicitly convert to DateTime
, use +=
, and then convert it back to SysTime
, which is a little ugly, but that's not what you would normally want. I suppose we could make the SysTime.add
units work in less than months, but then you just end up with people using that and end up with DST related errors when they should have used +=
but didn't understand the difference.
Indeed, at this point I am asking the question that adding these calendar features to SysTime
it was smart and that it actually ends up hurting usability rather than helping as intended. But I doubt that we could change it at this point - or more accurately, while we could change it, I doubt that giving up those features to SysTime
and forcing people to change their code would be worth the pain it can call. If I could repeat it, I would seriously consider not doing calendar operations on SysTime
.
Either way, we hope the wall of text was illuminating enough to be worth your time.
source to share