Подсчет дней, исключая выходные - PullRequest
12 голосов
/ 04 января 2010

Я создаю библиотечную систему в Ruby on Rails и пытаюсь найти способ рассчитать просроченные дни, исключая выходные дни, когда возвращен заемный элемент. Сейчас я просто вычисляю «дневную шкалу» как разницу между сроком исполнения и датой, когда товар был фактически возвращен, но я хочу исключить выходные, поскольку товары можно вернуть только в рабочие дни.

Это мой первый реальный опыт работы с Ruby и Rails, поэтому приношу свои извинения, если я упустил что-то очевидное. Спасибо за любую помощь, которую вы все можете предоставить.

Вот код, который у меня есть для функции «return»:

   def return
     @product = Product.find(params[:id])
     today = Date.today
     dayslate = today - @product.due_date
     if @product.due_date >= today
       @product.borrower = @product.check_out = @product.due_date = @product.extended_checkout = nil
       @product.save!
       flash[:notice] = "Okay, it's checked in!"
       redirect_to(products_url)
     else
       @product.borrower = @product.check_out = @product.due_date = @product.extended_checkout = nil
       @product.save!
       flash[:notice] = "Checked in, but it was #{dayslate} days late!"
       redirect_to(products_url)
     end
 end 

Ответы [ 11 ]

24 голосов
/ 05 января 2010

Вот фрагмент кода для определения количества дней недели в объектах Range of Date

require 'date'
# Calculate the number of weekdays since 14 days ago
p ( (Date.today - 14)..(Date.today) ).select {|d| (1..5).include?(d.wday) }.size

Вот как бы я использовал это в вашем случае.

class Product
  def days_late
    weekdays_in_date_range( self.due_date..(Date.today) )
  end

  protected
  def weekdays_in_date_range(range)
    # You could modify the select block to also check for holidays
    range.select { |d| (1..5).include?(d.wday) }.size
  end
end
2 голосов
/ 09 января 2015
sunday, saturday = 0, 6
weekend = [sunday, saturday]
((start_date..end_date).collect(&:wday) - weekend).count
2 голосов
/ 04 января 2010

Гм ... еще одна вещь, которая может быть полезна, поскольку это ваш первый опыт работы с рельсами - обратите внимание на эту бизнес-логику в контроллере. Ваша модель, вот где она принадлежит.

2 голосов
/ 04 января 2010

Если для вас важны праздники (т.е. вы не хотите считать день рабочим днем, если это выходной), вы можете рассмотреть http://rubyforge.org/projects/holidays/. Если вы объедините цикл, упомянутый @ md5sum с проверкой, чтобы увидеть, если будний день выходной, вы можете быть золотым.

1 голос
/ 12 декабря 2017

Я нашел более быстрый способ подсчета выходных дней, вы можете получить количество дней, исключая выходные, на (start_date..end_date).size - weekend_count:

def weekend_count(start_date, end_date)
  size = (end_date - start_date).to_i
  count = 0
  if start_date.wday != 0
    size -= (7 - start_date.wday).to_i
    count += 1
  end

  left_over  = size % 7
  if left_over == 0
    count = (count / 7) * 2
  else
    size -=  left_over
    count += (size / 7) * 2 + 1
  end
  count
end

Сравните с [0, 6].include? date.wday, посмотрите мой тест Результат:

Distance 10
Optimized result:  4
Normal result:     4
                                                  user     system      total        real
Optimized                                     0.000000   0.000000   0.000000 (  0.000018)
Normal                                        0.000000   0.000000   0.000000 (  0.000032)
Distance 100
Optimized result:  29
Normal result:     29
                                                  user     system      total        real
Optimized                                     0.000000   0.000000   0.000000 (  0.000006)
Normal                                        0.000000   0.000000   0.000000 (  0.000094)
Distance 1000
Optimized result:  286
Normal result:     286
                                                  user     system      total        real
Optimized                                     0.000000   0.000000   0.000000 (  0.000010)
Normal                                        0.000000   0.000000   0.000000 (  0.000650)
Distance 10000
Optimized result:  2858
Normal result:     2858
                                                  user     system      total        real
Optimized                                     0.000000   0.000000   0.000000 (  0.000013)
Normal                                        0.000000   0.000000   0.000000 (  0.004995)
Distance 100000
Optimized result:  28572
Normal result:     28572
                                                  user     system      total        real
Optimized                                     0.000000   0.000000   0.000000 (  0.000011)
Normal                                        0.060000   0.000000   0.060000 (  0.064223)
1 голос
/ 02 февраля 2017

Я думаю, что это проще и более читабельно, чем принятый ответ:

require 'date'
to = Date.parse('2017-02-02')
from = to - 14
(from..to).count { |d| !d.sunday? && !d.saturday? }
#=> 11
1 голос
/ 28 января 2014

рассчитать дни недели текущего месяца

start_date = Date.today.beginning_of_month
end_date = Date.today.end_of_month

(start_date..end_date).select{|a| a.wday < 6 && a.wday > 0}.count
1 голос
/ 25 февраля 2013

Относительно поста @ Marini можно устранить накладные расходы на генерацию диапазона дат:

def weekdays(date1, date2)
  wday = date1.wday
  (0..(date2-date1)).count {|offset| ((wday + offset) % 7 % 6) > 0}
end

% 7 превращает каждое смещение в день недели, а % 6 возвращает 0 для субботы (6) или воскресенья (0)

1 голос
/ 04 января 2010

Вы можете проверить эту страницу и посмотреть, сможете ли вы добавить счетчик в цикл и проверить текущую дату на каждой итерации.

0 голосов
/ 05 декабря 2015

Лучшее решение в порядке, и я знаю, что не стоит беспокоиться о производительности, но есть часть меня, которая обеспокоена подсчетом количества дней недели путем генерации коллекции и повторения по ней, потому что время для вычисления является линейной функцией разницы между двумя датами.

Ответ может быть математически рассчитан в фиксированное время, если вы обдумаете его. Вы можете думать об этом в двух частях:

ЧАСТЬ 1 - ЧИСЛО НЕДЕЛЕЙ МЕЖДУ

Если разница в днях превышает неделю, вы можете считать каждую 7-дневную неделю как имеющую 5 рабочих дней и «убирать» полные недели из рассмотрения.

ЧАСТЬ 2 - ДНИ В ЧАСТИЧНОЙ НЕДЕЛЕ

Вычитая полные недели, вы можете посмотреть на упрощенную задачу о том, сколько рабочих дней лежит между двумя днями в 7-дневном промежутке. Если вы построите таблицу, вы увидите, что есть довольно простое правило, или вы можете повторить логику, использованную в выигрышном решении, но только с интервалом не более 7 дней.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...