计算不包括周末的天数

时间:2010-01-04 19:54:19

标签: ruby-on-rails ruby

我正在Ruby on Rails中创建一个库式系统,我正在尝试计算过期天数,同时排除借用项目时的周末。现在我只计算“dayslate”作为截止日期和项目实际返回日期之间的差异,但我想排除周末,因为项目只能在工作日返回。

这是我第一次使用Ruby和Rails的真实体验,所以如果我遗漏了一些明显的东西,我很抱歉。感谢您提供的任何帮助。

这是我对“返回”功能的代码:

   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 个答案:

答案 0 :(得分:24)

这是一段代码,用于查找日期范围对象中工作日的数量

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

答案 1 :(得分:2)

如果假期对您很重要(例如,如果假期是您不希望将某一天计为工作日),您可能需要查看http://rubyforge.org/projects/holidays/。如果你将@ md5sum提到的循环与支票结合起来,看看工作日是否是假日,那么你可能是金色的。

答案 2 :(得分:2)

嗯..还有一件事可能有用,因为它是你的第一次铁路体验 - 注意控制器中的业务逻辑。你的模型,它就属于它。

答案 3 :(得分:2)

sunday, saturday = 0, 6
weekend = [sunday, saturday]
((start_date..end_date).collect(&:wday) - weekend).count

答案 4 :(得分:1)

您可以查看this页面,看看是否可以在循环中添加计数器并检查每次迭代的当前日期。

答案 5 :(得分:1)

关于@Marini的帖子,可以消除产生一系列日期的开销:

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

% 7将每个偏移量转换为工作日,% 6为周六(6)或周日(0)返回0

答案 6 :(得分:1)

计算current_month的工作日

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

答案 7 :(得分:1)

我认为这比接受的答案更简单,更易读:

require 'date'
to = Date.parse('2017-02-02')
from = to - 14
(from..to).count { |d| !d.sunday? && !d.saturday? }
#=> 11

答案 8 :(得分:1)

我找到了一种更快的周末计算方法,你可以按(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比较,请参阅我的benchmark结果:

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)

答案 9 :(得分:0)

中微子非常正确地将显示/渲染/重定向中涉及的所有逻辑移动到模型中。

E.g。

class ProductLoan
  def due_date_passed?
    days_late > 0
  end

  def days_late
    Date.today - due_date
  end

  def complete!
    self.borrower = self.check_out = self.due_date = self.extended_checkout = nil
    save
  end
end

class ReturnsController
  def create
    @product = ProductLoan.find(params[:id])

    if @product.due_date_passed?
      flash[:notice] = "Okay, it's checked in!"
    else
      flash[:notice] = "Checked in, but it was #{@product.days_late} days late!"
    end
    @product.complete!

    redirect_to products_url
  end
end

我只是在没有测试的情况下输入了这个,但是,这些行中的某些内容可以计算出不包括周末的日子:

class DateOffsetCalculator
  DAYS_IN_A_WEEK = 7
  DAYS_IN_A_WEEKEND = 2

  def initialize(date)
    @date = date
  end

  def compute
    days_passed - weekend_days_passed
  end

  def days_passed
    (Date.today - @date).to_i
  end

  def weekend_days_passed
    weekends_passed * DAYS_IN_A_WEEKEND
  end

  def weekends_passed
    rounded_up_week_days / DAYS_IN_A_WEEK
  end

  def rounded_up_week_days
    days_passed + commercial_working_day_correction
  end

  def commercial_working_day_correction
    @date.cwday - 1
  end
end

答案 10 :(得分:0)

顶级解决方案很好,我知道我不应该担心性能,但是我有一部分因为通过生成集合并迭代计算工作日的数量而烦恼,因为计算时间是线性函数两个日期之间的差异。

如果您仔细考虑,答案可以在固定时间内以数学方式计算。你可以分两个部分来考虑它:

第1部分 -

之间的周数

如果天数差异超过一周,您可以将每个7天工作周计为5个工作日,并“删除”整整几周。

第2部分 - 部分周的日子

减去整整一周后,您可以查看7天跨越两天之间有多少个工作日的简化问题。如果您构建一个表,您将看到一个非常简单的规则,或者您可以重复获胜解决方案中使用的逻辑,但只能在最多7天的时间间隔内。