trabajados habiles fechas entre dias calendario calcular ruby-on-rails ruby date

ruby-on-rails - fechas - dias habiles 2019



Calcular el número de días hábiles entre dos días. (8)

Aquí está mi ejemplo de recuento de días de semana (sin gemas ni días festivos):

first_date = Date.new(2016,1,5) second_date = Date.new(2016,1,12) count = 0 (first_date...second_date).each{|d| count+=1 if (1..5).include?(d.wday)} count

Necesito calcular el número de días hábiles entre dos fechas. ¿Cómo puedo lograr eso usando Ruby (o Rails ... si hay ayudantes específicos de Rails)?

Asimismo, me gustaría poder agregar días hábiles a una fecha determinada.

Entonces, si una fecha cae en un jueves y agregué 3 días hábiles, regresaría el próximo martes.


Basado en la respuesta de @mikej. Pero esto también tiene en cuenta los días festivos y devuelve una fracción de un día (hasta la precisión de la hora):

def num_days hi, lo num_hours = 0 while hi > lo num_hours += 1 if hi.workday? and !hi.holiday? hi -= 1.hour end num_hours.to_f / 24 end

Esto utiliza las holidays y gemas business_time .


Como señaló una persona diferente, la solución ganadora es realmente fácil de entender pero tiene un problema. Se tarda más en ejecutarse a medida que aumenta la distancia entre las dos fechas que se comparan. Eso es un tipo de problema feo.

Es de esperar que el código a continuación sea casi tan fácil de entender, pero lleva aproximadamente la misma cantidad de tiempo, independientemente del número de días entre las dos fechas. Aprovecha el hecho de que cada semana completa de 7 días tendrá 5 días hábiles.

require ''date'' def weekdays_between(earlier_date,later_date) days_diff = (later_date - earlier_date).to_i weekdays = 0 if days_diff >= 7 whole_weeks = (days_diff/7).to_i later_date -= whole_weeks*7 weekdays += whole_weeks*5 end if later_date > earlier_date dates_between = earlier_date..(later_date-1) weekdays += dates_between.count{|d| ![0,6].include?(d.wday)} end return weekdays end

Para que quede claro, este método cuenta el número de días de la semana EXCLUYENDO la fecha de finalización para que, por ejemplo:

  • 0 = número de días de la semana entre lunes y lunes
  • 1 = número de días de la semana entre viernes y sábado
  • 1 = número de días de la semana entre viernes y lunes
  • 0 = número de días de la semana entre domingo y lunes
  • 1 = Número de días de semana entre miércoles y jueves

Echa un vistazo a business_time . Puede ser usado tanto para las cosas que pides.

Cálculo de días hábiles entre dos fechas:

wednesday = Date.parse("October 17, 2018") monday = Date.parse("October 22, 2018") wednesday.business_days_until(monday) # => 3

Agregando días hábiles a una fecha determinada:

4.business_days.from_now 8.business_days.after(some_date)

Respuesta historica

Cuando se hizo esta pregunta originalmente, business_time no proporcionó el método business_days_until , por lo que se proporcionó el siguiente método para responder la primera parte de la pregunta.

Esto aún podría ser útil para alguien que no necesitaba ninguna otra funcionalidad de business_time y quería evitar agregar una dependencia adicional.

def business_days_between(date1, date2) business_days = 0 date = date2 while date > date1 business_days = business_days + 1 unless date.saturday? or date.sunday? date = date - 1.day end business_days end

Esto también puede ajustarse para manejar los casos que Tipx menciona de la manera que usted quisiera.


Echa un vistazo a Workpattern . Le permite especificar períodos de trabajo y de descanso y puede agregar / restar duraciones a / de una fecha, así como calcular los minutos entre dos fechas.

Puede configurar patrones de trabajo para diferentes escenarios como trabajo de lunes a viernes o domingos y puede tener días festivos y días completos o parciales.

Escribí esto lejos para aprender a Ruby. Todavía tengo que hacerlo más rubí-ish.


Sencillo script para calcular el número total de días laborables.

require ''date'' (DateTime.parse(''2016-01-01'')...DateTime.parse(''2017-01-01'')). inject({}) do |s,e| s[e.month]||=0 if((1..5).include?(e.wday)) s[e.month]+=1 end s end # => {1=>21, 2=>21, 3=>23, 4=>21, 5=>22, 6=>22, 7=>21, 8=>23, 9=>22, 10=>21, 11=>22, 12=>22}


Solíamos usar el algoritmo sugerido en la respuesta de mikej y descubrimos que calcular 25,000 rangos de varios años toma 340 segundos cada uno.

Aquí hay otro algoritmo con complejidad asintótica O (1). Hace los mismos cálculos en 0.41 segundos.

# Calculates the number of business days in range (start_date, end_date] # # @param start_date [Date] # @param end_date [Date] # # @return [Fixnum] def business_days_between(start_date, end_date) days_between = (end_date - start_date).to_i return 0 unless days_between > 0 # Assuming we need to calculate days from 9th to 25th, 10-23 are covered # by whole weeks, and 24-25 are extra days. # # Su Mo Tu We Th Fr Sa # Su Mo Tu We Th Fr Sa # 1 2 3 4 5 # 1 2 3 4 5 # 6 7 8 9 10 11 12 # 6 7 8 9 ww ww ww # 13 14 15 16 17 18 19 # ww ww ww ww ww ww ww # 20 21 22 23 24 25 26 # ww ww ww ww ed ed 26 # 27 28 29 30 31 # 27 28 29 30 31 whole_weeks, extra_days = days_between.divmod(7) unless extra_days.zero? # Extra days start from the week day next to start_day, # and end on end_date''s week date. The position of the # start date in a week can be either before (the left calendar) # or after (the right one) the end date. # # Su Mo Tu We Th Fr Sa # Su Mo Tu We Th Fr Sa # 1 2 3 4 5 # 1 2 3 4 5 # 6 7 8 9 10 11 12 # 6 7 8 9 10 11 12 # ## ## ## ## 17 18 19 # 13 14 15 16 ## ## ## # 20 21 22 23 24 25 26 # ## 21 22 23 24 25 26 # 27 28 29 30 31 # 27 28 29 30 31 # # If some of the extra_days fall on a weekend, they need to be subtracted. # In the first case only corner days can be days off, # and in the second case there are indeed two such days. extra_days -= if start_date.tomorrow.wday <= end_date.wday [start_date.tomorrow.sunday?, end_date.saturday?].count(true) else 2 end end (whole_weeks * 5) + extra_days end


business_time tiene toda la funcionalidad que deseas.

Desde el readme:

#también puedes calcular la duración del negocio entre dos fechas

friday = Date.parse("December 24, 2010") monday = Date.parse("December 27, 2010") friday.business_days_until(monday) #=> 1

Agregando días hábiles a una fecha determinada:

some_date = Date.parse("August 4th, 1969") 8.business_days.after(some_date) #=> 14 Aug 1969