关于datetime:按月计算时间点,但不在Rails中引用年份

Evaluating points in time by months, but without referencing years in Rails

仅供参考,这个问题的最初描述与我昨天问的一个问题有些重叠,但问题是不同的。

我的应用程序有季节性产品的用户。当用户选择产品时,我们允许他也选择产品的季节。我们通过让他为每个产品选择一个开始日期和结束日期来实现这一点。

我们使用date_select生成两组下拉列表:一组用于开始日期,另一组用于结束日期。

包括年份对我们的模型来说没有意义。所以我们使用的选项是:discard_year => true

当您使用discard_year => true时,rails在数据库中设置了一年,但它不会出现在视图中。Rails在我们的应用程序中将所有年份设置为0001或0002。是的,我们可以在2009年和2010年或其他任何一对。但关键是,我们希望月和日独立于某一年发挥作用。如果我们使用2009年和2010年,那么这些日期明年将是错误的,因为我们不希望这些记录每年都更新。

我的问题是,我们需要根据产品与当月的关系动态评估产品的可用性。例如,假设是3月15日。不管是哪一年,我都需要一种方法来告诉我,从10月到1月的产品现在都不可用。

如果我们使用的是实际年份,这将非常容易。

例如,在产品模型中,我可以这样做:

1
2
3
def is_available?
  (season_start.past? && season_end.future?)
end

我还可以对start_dateend_datecurrent_date进行评估。

然而,在我上面描述的设置中,我们有任意的年份,它们彼此之间只有意义,这些方法不起作用。例如,对于我的所有产品,is_available?将返回false,因为它们的结束日期在0001或0002年。

我需要的是一个方法,就像我上面作为例子使用的方法一样,除了它们对current_month而不是current_date进行评估,以及过去的方法?未来的几个月而不是几年。

我不知道如何做到这一点,也不知道Rails是否有任何内置的功能可以提供帮助。我已经完成了API文档中所有的日期和时间方法/帮助器,但是我没有看到任何与我描述的内容相同的东西。

谢谢。


将当前日期的年份设置为1000,并与开始日期和结束日期进行范围比较。

1
2
3
4
5
6
def is_available?
  t = Date.today
  d = Date.new(1000, t.month, t.day)
  (season_start..season_end).include?(d) or
     (season_start..season_end).include?(d+1.year)
end

上面的第二个比较是解决以下情况:

假设今天是1月15日,这个季节是从10月到2月。按照我们的逻辑,我们把日期定在1000年1月15日。此日期不在1000年10月1日至1001年3月1日之间。因此,我们进行第二次比较,将日期提前一年至1001年1月15日,这在范围内。


您可能会考虑不使用日期对象。如果赛季开始月份和赛季结束月份都是一个整数1-12,用你的下拉列表设置呢?那你什么时候有空?相比之下,您可以动态地创建赛季开始的完整日期,为12月到1月的过渡做一些数学计算。这可能需要一些重构,并且没有经过测试,但应该可以做到这一点。假设季节开始月份和季节结束月份是此模型中存储的整数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Product < ActiveRecord::Base
  def is_available?
    now = Time.now
    season_start < now && now < season_end
  end

  def season_start
    now = Time.now
    current_month = now.month
    season_start_year = season_start_month < current_month ? now.year : now.year - 1
    Time.local(season_start_year, season_start_month)
  end

  def season_end
    now = Time.now
    current_month = now.month
    season_end_year = season_end_month > current_month ? now.year : now.year + 1
    Time.local(season_end_year, season_end_month)
  end
end