Ruby On Rails, Design, Simplicity, Web 2.0, Ajax, Mac and Tons of Pizza.

Jan 30

Calculate the number of working days between two dates

Posted by Sandro Paganotti in Ruby on Rails - comments are closed digg this add to delicious

The Ruby api documentation is really useful, not only to find and understand Ruby methods and classes, but also for the amazing examples that sometimes you can find there. Yesterday I was looking for a method inside the Date class and I found a really useful piece of code in this page. With just a little effort I created a method that let you find the number of working days between two dates:

  
   # wdays is an array with the days of the week
   # to exclude (eg: [0,6] for sunday and saturday )

   def calculate_working_days(d1,d2,wdays)
        diff = d2 - d1
        holidays = 0
        ret = (d2-d1).divmod(7)
        holidays =  ret[0].truncate * wdays.length
        d1 = d2 - ret[1]
        while(d1 <= d2)
                if wdays.include?(d1.wday)
                        holidays += 1
                end
                d1 += 1
        end
        diff - holidays
   end

Comments

  • Edoc

    Posted on January 30

    Nice example. Coincidentally I was recently doing something similar in REBOL (www.rebol.com), and came up with following function: calculate-workdays: func [date1 [date!] date2 [date!] holidays [date! block!] /non /local d1 d2 days op act][ set [d1 d2] sort reduce [date1 date2] diff: d2 - d1 either non [op: 'greater-or-equal? act: 'union][op: 'lesser-or-equal? act: 'exclude] days: copy [] loop diff [ d1: d1 + 1 if (do op d1/weekday 5) [append days d1] ] return length? (do act days holidays) ] This code allows you to calculate the working days, or the non-working days, as follows: >> calculate-workdays now/date 31-dec-2007 [25-dec-2007 1-Jan-2008] == 238 >> calculate-workdays/non now/date 31-dec-2007 [25-dec-2007 1-Jan-2008] == 146 Luckily, to accomplish this, I didn't have to study any API or classes.
  • Russell Tracey

    Posted on January 31

    I believe you can accomplish the same thing with the following stolen and modified from: http://www.ruby-forum.com/topic/93938#190402 require 'date' d1 = Date.new( 2006, 12, 1 ) d2 = Date.new( 2007, 1, 15 ) weekdays = (d1..d2).reject { |d| [0,6].include? d.wday } weekdays.length Of course this is weekdays (mon-fri), work days are not so straight forward. Dubai for instance has in the past had the weekend as Thursday afternoon + Friday but I believe even this has now changed and is dependant on which company you ask. Also all this doesn't even consider holidays. Looks like someone was looking into this recently: http://www.ruby-forum.com/topic/92844
  • Eric I.

    Posted on January 31

    That's a nice solution -- much better than those that iterate over every day in the range.

    But it's not obvious to me what purpose sortding the wday array serves. And the block passed to the sort method seems redundant, as it implements the behavior sort would use if no block were passed, no?

    Best,

    Eric

  • Sandro Paganotti

    Posted on January 31

    Thank you for all the comments; Eric, you are absolutely right, I don't know why I left the sort method in the code :) I've now updated the code removing that useless line. Russell Tracey: WOW, this is a really impressive piece of code, thank you ! Edoc: this is the first time i heard about REBOL,it looks a quite intresting language! I'm going to look in wikipedia :) For everyone. I'm now searching a way to improve the look of railsonwave comments. Sandro
  • Edoc

    Posted on February 01

    Sandro-- My apologies for the formatting of the REBOL example, which also strayed from the central subject, Ruby. Thanks.

Post a comment

Categories:

Tags:

Powered by Mephisto, Valid XHTML 1.1, Valid CSS - Supported by Wave Factory