计算不包括周末的天数

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

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

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

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 

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

 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 

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

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

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

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

关于@Marini的post,可以消除生成一系列日期的开销:

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

% 7将每个偏移量变为工作日, % 6为星期六(6)或星期日(0)返回0

计算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 

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

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

neutrino非常适合将显示/渲染/重定向中涉及的所有逻辑移动到模型中。

例如

 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 

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

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

第1部分 – 周之间的数量

如果天数差异大于一周,您可以将每个7天工作周计为5个工作日,并“考虑”整周。

第2部分 – 部分周的日子

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

我找到了一个更快的方法来计算周末的日子,你可以通过(start_date..end_date).size - weekend_count获取天数(不包括周末(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 [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)