在 rails 我需要根据日期范围获取所有记录,忽略年份

in rails i need to get all records based on a date range, ignoring the year

我正在尝试获取 rails 日期范围内的所有记录,这些记录在给定开始日期之后和给定结束日期之前,忽略年份。开始日期只有一个月。日期范围的结尾是月份和日期。 以下示例是获取雇用日期月份等于或大于一月但小于 2(二月)/ 28(天)的用户。 我正在尝试这个,但它不起作用:

users.where('extract(month from hire_date) >= ?', 1).where('extract(month from hire_date) <= ? AND extract(day from hire_date) <= ?', 2, 28)

这不起作用的原因是它会排除用户,例如 1/29 的用户,因为他们在 1 月的一天不少于 28。

有没有什么好方法可以忽略日期字段中的年份来完成这项工作?

首先让我说一下,我不熟悉 ruby-on-railssqlactiverecord,但这个问题确实激起了我的兴趣,因为它包含许多复杂的问题我从来没有处理过。最值得注意的是:

  • 如何在测试范围和目标日期可能出现的情况下适应闰年 有不同的闰年状态。
  • 如何处理 2 月 29 日的聘用日期。这似乎是 与我列表中的第一项相同,但它有自己的独特之处 细微差别。
  • 如何处理从一年开始然后重叠到下一年的范围。

我自己做了一些搜索,关于这个主题的信息似乎很少,尤其是任何似乎能正确处理上面列出的各种复杂性的信息,所以我决定看看我是否能想出一个我自己的逻辑方法。这似乎是一种新颖的方法,但最终我决定将 monthday 值转换为 float 值将允许一种简单的方法来解决闰年问题以及问题2 月 29 日,并且使用 if/else 语句和相反的布尔运算测试日期范围将解决重叠年份的范围。

您可能需要根据您的特定需求进行推断和重新配置,但这里是用纯 ruby 写出的总体思路。它相当冗长,但我这样做只是为了更清楚地说明我在做什么。我可以做得更紧凑:

hire_date = Time.new(2004, 1, 22)

provided_start_date = Time.new(2008, 12, 22)

day_value = (60*60*24)  #60 seconds * 60 minutes * 24 hours = 1 day
num_days = 30

calculated_end_date =  provided_start_date + num_days*day_value

start_range = provided_start_date.month + provided_start_date.day/100.0
end_range = calculated_end_date.month + calculated_end_date.day/100.0
day_float = hire_date.month + hire_date.day/100.0

if start_range < end_range
  result = day_float >= start_range and day_float <= end_range
else
  result = day_float >= start_range or day_float <= end_range
end

result

我会使用 to_char 将日期转换为仅包含月份和日期的字符串。例如 2021-12-31 可以翻译成 "12-31"。然后可以将该字符串与您感兴趣的日期字符串范围进行比较。

users.where("to_char(hire_date, 'MM-DD') BETWEEN '01-01' AND '02-29'")

请注意,从理论上讲,这也会匹配无效的日期字符串,例如“01-40”。但我想可以安全地假设具有有效日期的 to_char 永远不会 return 这样的无效日期字符串。

所以我想出了一些对此有用的东西。 给定以下内容:

start_date = 01 Jan 2021
end_date = 02 Feb 2021

Users.where("(extract(month from hire_date) * 100 + extract(day from hire_date)) BETWEEN ? AND ?", ((start_date.month * 100) + start_date.day), ((end_date.month * 100) + end_date.day))

开始日期和结束日期可以是任何日期,这应该可以让所有用户介于两者之间,因为 SQL 介于两者之间是包容性的,它也会让结束和开始日期落在开始/结束日期之间的用户日期,忽略年份。