我正在寻找一种优雅的方式来制作一系列日期时间,例如:
def DateRange(start_time, end_time, period)
...
end
>> results = DateRange(DateTime.new(2013,10,10,12), DateTime.new(2013,10,10,14), :hourly)
>> puts results
2013-10-10:12:00:00
2013-10-10:13:00:00
2013-10-10:14:00:00
该步骤应该是可配置的,例如每小时、每天、每月。
我希望times
是包含性的,即包含end_time
。
其他要求包括:
- 应保留原始时区,即如果它与本地时区不同,则仍应保留。
- 应该使用适当的高级方法,例如Rails
:advance
,来处理诸如月份中的可变天数之类的事情。 - 理想情况下,性能会很好,但这不是主要要求。
是否有一个优雅的解决方案?
9条答案
按热度按时间r1wp621o1#
使用@CaptainPete的base,我将其修改为使用
ActiveSupport::DateTime#advance
调用。当时间间隔不一致时,如“:month”和“:year”,差异将生效。我的方法也返回一个
Array
,为了便于比较,我修改了@CaptainPete的答案,也返回一个数组:按小时
按月
按年份
h7appiyu2#
没有舍入错误,一个
Range
调用.succ
方法来枚举序列,这不是您想要的。不是一行程序,而是一个简短的helper函数就足够了:
但是,请注意,对于大范围来说,这可能是非常低效的内存方式。
或者,您可以使用自纪元以来的秒数:
你会有一个整数范围,但你可以很容易地转换回
DateTime
:2j4z5cfb3#
向
Range#step
添加持续时间支持此方法提供
Range#step
方法添加持续时间支持(不需要子类,也不需要Object
上的方便方法,尽管这仍然很有趣)1.hour + 3.seconds
和step_size
这增加了对使用现有API的Range的持续时间的支持。它允许您以我们期望的简单“只是工作”的风格使用常规范围。
之前的方法
...是在
Object
上使用DateRange < Range
类+DateRange
“构造函数”添加#every
,然后在内部将时间转换为整数,在step
秒内单步执行它们。这最初不适用于时区。添加了对时区的支持,但后来发现另一个问题,即某些步骤持续时间是动态的(例如1.month
)。阅读了Rubinius'
Range
implementation之后,我们就明白了如何添加对ActiveSupport::Duration
的支持;非常感谢DanNguyen的#advance
技巧和调试,感谢Rubinius对Range#step
的实现,因为它编写得非常漂亮:D更新2015-08-14
#advance
来循环for
。如果你得到can't iterate from Time
或者类似的东西,那么就使用这个补丁,或者避免使用Range
。prepend
风格而不是alias_method_chain
。7nbnzgx94#
另一种解决方案是使用
uniq
方法。考虑以下示例:请注意,此方法考虑范围min和max
2vuwiymt5#
一小时是一天的二十四分之一,所以你可以
1/24r
是一个Rational,比Float更精确。zzlelutf6#
如果希望
n
值在两个日期之间均匀分布,可以它给出了
p8ekf7hl7#
您可以在开始和结束时间上使用
DateTime.parse
来锁定填充数组所需的迭代。等等。一旦你有了这些值,你就可以在任何你想要的时间片上循环填充数组。虽然我同意@fotanus,你可能不需要为此物化一个数组,但我不知道你这样做的目的是什么,所以我真的不能说。
kdfy810k8#
Ice Cube - Ruby Date Recurrence Library会在这里有所帮助,还是看看它们的实现?它已经成功地涵盖了RFC 5545规范中的每一个示例。
yqhsw0fo9#
Ruby标准库
date
有一个内置的方法step
,我们可以使用它来实现这一点:我们把它分解一下,这样更容易阅读
puts array_of_datetime
的输出**P.S.**原始问题是2013年的,所以我用docker镜像
ruby:2.0.0-slim
测试了一下。Ruby 2.0.0是2012年发布的,运行得很好。