roll也存在于Java ....我记得在任何一种语言中使用它的唯一一次虽然实现了一个小的日期选择器小部件.每个事物都有单独的字段:月,日,年,并且您希望用户能够在不增加月份的情况下旋转数天,因为它们是单独的字段.(假设它设置为30,他们想选择第1个.最快的方法可能就是点击向上箭头让它翻转.)
可能还有其他用途,我现在就不记得了.即使我刚刚实施ical支持(遗憾的是,专有),我从未使用过roll方法,但在那里可能存在潜力.ical是日历上重复发生的事件的标准,并且那里有一些棘手的事情,以及一些不同的方法可以实现它.
在评论中,你也问为什么你不能add天.原因是添加天数非常简单,并且包括opBinary:
datetime += 5.days; // works
Run Code Online (Sandbox Code Playgroud)
但这几个月不起作用,因为月份的持续时间可变.这就是add方法提供帮助的地方:假设它是1月30日并且你添加了一个月.您可能只需添加31天,因为1月份有31天.这会让你在3月2日降落(我想,在我的脑海里这样做)......但是1月30日+ 1个月可能也需要是2月28日.或者也许是2月29日.假设你要支付每月到期的账单当月,这些截止日期之间的天数将发生变化.
该add方法处理此问题,并为您提供在最后一天或在下个月溢出的选项.
虽然,我有点争辩说天也没有静态长度....考虑DST过渡.(或者闰秒,但处理它们会很疯狂).也许我们可以问JMD.
所以,简短的回答是亚当是正确的,并且roll专门用于处理拣选日期和类似用例,并且add专门用于处理数月Duration和数年,因为不能(因为数月和数年不会转换为百万 -在不知道起点的情况下纳秒.但是,如果澄清事情的话,我会更深入地回答它.
DateTime,, Date和TimeOfDay专为基于日历的操作而设计.它们与系统时钟无关,它们没有时区概念,它们将日期/时间的各个部分作为单独的单位(年,月,日,小时等)保存在内部.因此,当您hour在a上设置字段时DateTime,您实际上只是调整其中一个DateTime成员变量.当你Duration向它们添加一个时,必须将它分开以单独添加到每个单元,因此做一些像Duration7小时的添加可能会增加更多的hour字段.例如
auto dt = DateTime(2015, 8, 2, 20, 0, 0);
dt += hours(7);
assert(dt == DateTime(2015, 8, 3, 3, 0, 0));
Run Code Online (Sandbox Code Playgroud)
而且由于Duration在内部以百纳秒为单位保持其值,因此无论如何您都不一定要添加到特定单位.即它不是+= hours(7)特意添加到该hour领域.它在整体上增加了几百纳秒,DateTime并且必须弄清楚它是如何影响每个单元而不是影响特定单元的.例如
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));
Run Code Online (Sandbox Code Playgroud)
roll另一方面,专门用于添加到特定单元而不影响任何其他单元.正如亚当正确确定的那样,它的主要用例是日期选择器对话框中的旋转控件等,你最终会调整一定数量的特定时间单位,而你不想影响其他单位,只有那个单位.你在调整.所以,如果你增加7个小时,你最终只会增加一天,只有几个小时.
auto dt = DateTime(2015, 8, 2, 20, 0, 0);
dt.roll!"hours"(7);
assert(dt == DateTime(2015, 8, 2, 3, 0, 0));
Run Code Online (Sandbox Code Playgroud)
现在,事情确实变得有点数月和年有趣,因为它们没有固定的长度.这就是为什么Duration不支持他们.你不能说x百纳秒相当于y几个月或z几年.但是,虽然Duration几个月或几年没有意义,但我们仍然希望能够将数月和数年添加到Date或DateTime.所以,我们已经add!"years"并且add!"months"处理了这个问题,并且它允许你控制一些奇怪的事情,例如在1月31日加1个月是否应该在2月底或3月初结束(因为没有2月31日).
这些都不考虑任何类型的时区.它纯粹处理日历时间.add与roll纯粹基于日历的操作,以及+=为实施了DateTime,Date以及TimeOfDay是基于日历的操作.它在计算时会考虑年,月,日等等(在其情况下不能做其他情况,因为单位在其成员变量中被分开).
然后我们有SysTime.它旨在表示系统的时间(这意味着考虑时区).但是,避免与DST相关的问题的唯一方法是始终将时间保持为UTC.因此,SysTime始终在UTC内部(以百纳秒为单位)保持其时间并使用TimeZone对象(LocalTime默认情况下)仅在需要时将其转换为特定时区.这避免了各种烦人的与时间相关的错误.和任何人对系统的运行时间应使用SysTime而不是DateTime,Date或TimeOfDay.
因此,当您添加到SysTime使用时+=,您实际上只是将内部使用Duration的百纳秒增加到百纳秒SysTime.没有日历操作发生(如果他们这样做,你最终会得到许多与DST相关的错误).SysTime根本不是基于日历的.为了进行任何日历操作,SysTime它在内部持有的百纳秒必须转换为格里高利历上日期表示的任何日期(使用该TimeZone对象来考虑时区).
然而,为了方便用户,SysTime提供了许多使基于日历的性质和功能的DateTime不(例如year,month,day,hour,等特性和add和roll功能).为了支持这一点,它基本上最终转换为Date或DateTime内部执行它们,这意味着考虑时区,如果它们没有正确使用,可能意味着引入DST错误.在某些情况下,这是非常低效的.例如,如果您有一个SysTime名为的变量st
auto year = st.year;
auto month = st.month;
auto day = st.day;
Run Code Online (Sandbox Code Playgroud)
转换st为Date三次,而只是Date明确地转换为a 并从那里获取单位会更有效.所以,这种用户友好性是一把双刃剑.
此外,它提出了亚当提出的关于如何添加和滚动处理夏令时的问题.roll并且add在SysTime处理a Date或DateTime内部时,将DST考虑在内,因为从UTC 转换SysTime为Date或DateTime将其从UTC转换为其TimeZone对象所代表的任何内容.所以,roll和add运营上SysTime,他们会究竟是如何运作的DateTime-因为他们转换为DateTime,然后再返回.
但正如我已经说过,+=在SysTime刚刚增加了Duration它的UTC时间.因此,没有办法在其SysTime上添加小于月的单位并将DST考虑在内.你已经明确地转换为a DateTime,使用+=它,然后将其转换回a SysTime,这有点难看,但它不是你通常想要的东西.我想我们可以SysTime.add用小于几个月的单位进行工作,但是你最终会得到那些使用它并最终得到与DST相关的错误的人,当他们本应该使用+=但却不理解差异时.
实际上,在这一点上,我质疑添加这些日历功能SysTime是明智的,并且它实际上最终会损害可用性而不是按预期帮助.但我怀疑我们是否可以在这一点上改变它 - 或者更确切地说,虽然我们可以改变它,但我怀疑弃用这些函数SysTime并强迫人们改变他们的代码将是值得的,它会造成的痛苦.如果我可以重做它,我会认真考虑不要进行任何基于日历的操作SysTime.
在任何情况下,希望文本墙充满启发性,值得你花时间.