Skip to content

Instantly share code, notes, and snippets.

@verticonaut
Created December 14, 2011 20:00
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save verticonaut/1478218 to your computer and use it in GitHub Desktop.
Save verticonaut/1478218 to your computer and use it in GitHub Desktop.
Add the concept of workdays to Rails
# encoding: utf-8
require 'active_support/basic_object'
require 'active_support/core_ext/array/conversions'
require 'active_support/core_ext/object/acts_like'
class Date
def workday?
workdays = ::I18n.t!('definitions.workday.days', :default => (1..5))
none_workdays = ::I18n.t!('definitions.workday.public_holidays', :default => [[]]) # Returns first elememnt within array if translatio is missing (I18n principle)
workdays.include?(wday) && !none_workdays.include?(self)
end
end
class Time
def workday?
to_date.workday?
end
end
module ActiveSupport
class Duration < BasicObject
protected
def sum(sign, time = ::Time.current) #:nodoc:
parts.inject(time) do |t,(type,number)|
if t.acts_like?(:time) || t.acts_like?(:date)
if type == :seconds
t.since(sign * number)
# NEW-START: added concept of workday - there is a better way to do it ---------- START
elsif type == :workdays
return t if number.zero?
# if we are NOT on a workday right now, we move to the beginning of the next workday
if !t.workday?
while !t.workday? do
t += 1.day
end
t = t.beginning_of_day
end
workdays_count = number.abs.floor
delta = number > 0 ? 1 : -1
count = 0
while count < workdays_count do
t = t.advance(:days => delta)
count += 1 if t.workday?
end
# handle fractions
if (number.abs - workdays_count > 0)
t = t.advance(:days => delta * (number.abs - workdays_count))
while !t.workday?
t = t.advance(:days => delta)
end
end
t
# NEW-END ------------------------------------------------------------------------- END
else
t.advance(type => sign * number)
end
else
raise ::ArgumentError, "expected a time or date, got #{time.inspect}"
end
end
end
end
end
# *** Numeric extension ***********************************************************************************************
require 'active_support/duration'
class Numeric
# Adds the concept of workdays to the other rails date extensions (day, weeks ,year etc))
def workdays
ActiveSupport::Duration.new(self * 24.hours, [[:workdays, self]])
end
alias :workday :workdays
end
@verticonaut
Copy link
Author

# sample locale file that defines workdays and public holidays
en:
  definitions:
    workday:
      days:
        - 1
        - 2
        - 3
        - 4
        - 5
      public_holidays:
        - 2011-12-15

@verticonaut
Copy link
Author

### Usage samples
5.workdays.from_now
1.5.workdays.from_now
1.workday.since(Date.new(2011,1,1))
Date.today.workday?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment