Estoy tratando de obtener todos los registros dentro de un rango de fechas en rieles que caen después de una fecha de inicio determinada y antes de una fecha de finalización determinada, ignorando el año. la fecha de inicio será sólo un mes. el final del intervalo de fechas es un mes y una fecha. el siguiente ejemplo es para obtener usuarios con un mes de fecha de contratación igual a enero o mayor, pero menor a 2(febrero) / 28(día). estaba intentando esto pero no funciona:
users.where('extract(month from hire_date) >= ?', 1).where('extract(month from hire_date) <= ? AND extract(day from hire_date) <= ?', 2, 28)la razón por la que esto no funciona es que excluirá a los usuarios, por ejemplo, que caigan el 29/1, porque su día en enero no es inferior al 28.
¿Hay una buena manera de hacer que esto funcione, ignorando el año en el campo de fecha?
Permítanme comenzar diciendo que no estoy familiarizado con ruby-on-rails , sql o activerecord , pero esta pregunta realmente despertó mi interés porque contiene una serie de complejidades con las que nunca tuve que lidiar. Más destacado:
Investigué un poco por mi cuenta y parece que hay muy poca información sobre el tema, en particular cualquiera que parezca tratar adecuadamente las diversas complejidades enumeradas anteriormente, así que decidí ver si podía encontrar un enfoque lógico propio. . Parece que puede ser un enfoque novedoso, pero finalmente decidí que convertir el month y el day en valores float permitiría una manera fácil de abordar el problema del año bisiesto, así como el problema del 29 de febrero, y que probar los rangos de fechas usando un La instrucción if/else junto con operaciones booleanas opuestas resolvería los rangos que se superponen en años.
Puede que tenga que extrapolar y reconfigurar para sus necesidades específicas, pero esta es la idea general escrita en ruby puro. Es bastante detallado, pero lo hice solo para tratar de dejar más claro lo que estoy haciendo. Podría hacerse mucho más compacto:
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 resultto_char para transformar las fechas en cadenas que incluyan solo el mes y el día. Por ejemplo, 2021-12-31 podría traducirse como "12-31" . Esa cadena se puede comparar con el rango de cadenas de fechas que le interesan.
users.where("to_char(hire_date, 'MM-DD') BETWEEN '01-01' AND '02-29'") Tenga en cuenta que esto, en teoría, también coincidiría con cadenas de fecha no válidas como '01-40'. Pero supongo que es seguro asumir que to_char con una fecha válida nunca devolverá tales cadenas de fecha no válidas.
Así que descubrí algo que funcionó para esto. dado lo siguiente:
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))la fecha de inicio y la fecha de finalización pueden ser cualquier fecha y esto debería funcionar para que todos los usuarios estén en medio, ya que SQL entre es inclusivo, también obtendrá usuarios cuyas fechas de finalización e inicio caen en la fecha de inicio/finalización, ignorando el año.