business_time 0.6.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +36 -41
- data/lib/business_time/business_days.rb +2 -2
- data/lib/business_time/business_hours.rb +8 -2
- data/lib/business_time/config.rb +122 -91
- data/lib/business_time/core_ext/date.rb +4 -4
- data/lib/business_time/core_ext/fixnum.rb +5 -7
- data/lib/business_time/core_ext/time.rb +12 -20
- data/lib/business_time/version.rb +1 -1
- data/rails_generators/business_time_config/templates/business_time.rb +3 -3
- metadata +58 -23
- checksums.yaml +0 -7
    
        data/README.rdoc
    CHANGED
    
    | @@ -18,23 +18,15 @@ I needed this, but taking into account business hours/days and holidays. | |
| 18 18 | 
             
            * install the gem
         | 
| 19 19 |  | 
| 20 20 | 
             
                gem install business_time
         | 
| 21 | 
            -
             | 
| 22 | 
            -
              or
         | 
| 23 | 
            -
              
         | 
| 24 | 
            -
                sudo gem install business_time
         | 
| 25 | 
            -
                
         | 
| 26 | 
            -
              if you require sudo to install gems
         | 
| 27 | 
            -
              
         | 
| 21 | 
            +
             | 
| 28 22 | 
             
            * open up your console
         | 
| 29 23 |  | 
| 30 24 | 
             
                # if in irb, add these lines:
         | 
| 31 | 
            -
             | 
| 32 | 
            -
                require 'rubygems'
         | 
| 33 | 
            -
                require 'active_support'
         | 
| 25 | 
            +
             | 
| 34 26 | 
             
                require 'business_time'
         | 
| 35 27 |  | 
| 36 28 | 
             
                # try these examples, using the current time:
         | 
| 37 | 
            -
             | 
| 29 | 
            +
             | 
| 38 30 | 
             
                1.business_hour.from_now
         | 
| 39 31 | 
             
                4.business_hours.from_now
         | 
| 40 32 | 
             
                8.business_hours.from_now
         | 
| @@ -71,7 +63,7 @@ I needed this, but taking into account business hours/days and holidays. | |
| 71 63 | 
             
                BusinessTime::Config.holidays << three_day_weekend
         | 
| 72 64 | 
             
                friday_afternoon = Time.parse("July 2nd, 2010, 4:50 pm")
         | 
| 73 65 | 
             
                tuesday_morning = 1.business_hour.after(friday_afternoon)
         | 
| 74 | 
            -
             | 
| 66 | 
            +
             | 
| 75 67 | 
             
                # plus, we can change the work week:
         | 
| 76 68 | 
             
                # July 9th in 2010 is a Friday.
         | 
| 77 69 | 
             
                BusinessTime::Config.work_week = [:sun, :mon, :tue, :wed, :thu]
         | 
| @@ -92,7 +84,7 @@ I needed this, but taking into account business hours/days and holidays. | |
| 92 84 | 
             
                friday = Date.parse("December 24, 2010")
         | 
| 93 85 | 
             
                monday = Date.parse("December 27, 2010")
         | 
| 94 86 | 
             
                friday.business_days_until(monday) #=> 1
         | 
| 95 | 
            -
             | 
| 87 | 
            +
             | 
| 96 88 | 
             
                # or you can calculate business duration between two Time objects
         | 
| 97 89 | 
             
                ticket_reported = Time.parse("February 3, 2012, 10:40 am")
         | 
| 98 90 | 
             
                ticket_resolved = Time.parse("February 4, 2012, 10:50 am")
         | 
| @@ -108,44 +100,46 @@ I needed this, but taking into account business hours/days and holidays. | |
| 108 100 | 
             
                # Monday, Feb 6th 2012, 9:00am.  The business time between 10:40am friday and 9am monday is
         | 
| 109 101 | 
             
                # 6 hours and 20 minutes. From a quick inspection of the code, it looks like it should be 8 hours.
         | 
| 110 102 |  | 
| 111 | 
            -
            ==  | 
| 112 | 
            -
            The code above should work on a rails console without any issue.  You will want to add a line something like:
         | 
| 113 | 
            -
             | 
| 114 | 
            -
                config.gem "business_time"
         | 
| 115 | 
            -
             | 
| 116 | 
            -
            to your environment.rb file. Or if you're using bundler, add this line to your Gemfile:
         | 
| 103 | 
            +
            == Rails generator
         | 
| 117 104 |  | 
| 118 | 
            -
                 | 
| 105 | 
            +
                rails generate business_time:config
         | 
| 119 106 |  | 
| 120 | 
            -
             | 
| 107 | 
            +
            The generator will add a ./config/business_time.yml and a ./config/initializers/business_time.rb
         | 
| 108 | 
            +
            file that will cause the start of business day, the end of business day, and your holidays to be loaded from the yaml file.
         | 
| 121 109 |  | 
| 122 | 
            -
             | 
| 123 | 
            -
             | 
| 124 | 
            -
             | 
| 125 | 
            -
             | 
| 126 | 
            -
                script/rails generate business_time:config
         | 
| 127 | 
            -
                
         | 
| 128 | 
            -
            The generator will add a /config/business_time.yml and a /config/initializers/business_time.rb file that will cause the start of business day, the end of business day, and your holidays to be loaded from the yaml file.  You might want to programatically load your holidays from a database table, but you will want to pay attention to how the initializer works - you will want to make sure that the initializer sets stuff up appropriately so rails instances on mongrels or passenger will have the appropriate data as they come up and down.
         | 
| 129 | 
            -
             | 
| 130 | 
            -
            == Outside of Rails
         | 
| 131 | 
            -
            This code does depend on ActiveSupport, but nothing else within rails.  Even then, it would be pretty easy to break that dependency as well (but would add some code bloat and remove some clarity).  Feel free to use it on any ruby project you'd like!
         | 
| 110 | 
            +
            You might want to programatically load your holidays from a database table,
         | 
| 111 | 
            +
            but you will want to pay attention to how the initializer works -
         | 
| 112 | 
            +
            you will want to make sure that the initializer sets stuff up appropriately so
         | 
| 113 | 
            +
            rails instances on mongrels or passenger will have the appropriate data as they come up and down.
         | 
| 132 114 |  | 
| 133 115 | 
             
            == Timezone support
         | 
| 134 | 
            -
            This gem strives to be timezone-agnostic. | 
| 116 | 
            +
            This gem strives to be timezone-agnostic.
         | 
| 117 | 
            +
            Due to some complications in the handling of timezones in the built in Time class,
         | 
| 118 | 
            +
            and some complexities (bugs?) in the timeWithZone class, this was harder than expected... but here's the idea:
         | 
| 135 119 |  | 
| 136 120 | 
             
            * When you configure the gem with something like 9:00am as the start time,
         | 
| 137 121 | 
             
              this is agnostic of time zone.
         | 
| 138 122 | 
             
            * When you are dealing with a Time or TimeWithZone class, the timezone is
         | 
| 139 123 | 
             
              preserved and the beginning and end of times for the business day are
         | 
| 140 124 | 
             
              referenced in that time zone.
         | 
| 141 | 
            -
             | 
| 142 | 
            -
            This can lead to some wierd looking effects if, say, you are in the Eastern time zone but doing everything in UTC times... | 
| 125 | 
            +
             | 
| 126 | 
            +
            This can lead to some wierd looking effects if, say, you are in the Eastern time zone but doing everything in UTC times...
         | 
| 127 | 
            +
            Your business day will appear to start and end at 9:00 and 5:00 UTC.
         | 
| 128 | 
            +
            If this seems perplexing to you, I can almost guarantee you are in over your head with timezones in other ways too,
         | 
| 129 | 
            +
            this is just the first place you encountered it.
         | 
| 130 | 
            +
            Timezone relative date handling gets more and more complicated every time you look at it and takes a long time before it starts to seem simple again.
         | 
| 131 | 
            +
            I'm hoping Arild and I write some good blog entries on the subject at http://blog.codesherpas.com.
         | 
| 143 132 |  | 
| 144 133 | 
             
            == Integration with the Holidays gem
         | 
| 145 134 |  | 
| 146 | 
            -
            	Chris Wise wrote up a great article[http://murmurinfo.wordpress.com/2012/01/11/handling-holidays-and-business-hours/] | 
| 135 | 
            +
            	Chris Wise wrote up a great article[http://murmurinfo.wordpress.com/2012/01/11/handling-holidays-and-business-hours/]
         | 
| 136 | 
            +
            	on using the business_time gem with the holidays[https://github.com/alexdunae/holidays] gem. It boils down to this:
         | 
| 147 137 |  | 
| 148 | 
            -
              Holidays.between(Date.civil( | 
| 138 | 
            +
              Holidays.between(Date.civil(2013, 1, 1), 2.years.from_now, :ca_on, :observed).map do |holiday|
         | 
| 139 | 
            +
                BusinessTime::Config.holidays << holiday[:date]
         | 
| 140 | 
            +
                # Implement long weekends if they apply to the region, eg:
         | 
| 141 | 
            +
                # BusinessTime::Config.holidays << holiday[:date].next_week if !holiday[:date].weekday?
         | 
| 142 | 
            +
              end
         | 
| 149 143 |  | 
| 150 144 | 
             
            == Releases
         | 
| 151 145 | 
             
            0.6.2 - rchady pointed out that issue #14 didn't appear to be released.  This fixes that, as well as confirms that all tests run as expected on Ruby 2.0.0p195
         | 
| @@ -156,11 +150,12 @@ This can lead to some wierd looking effects if, say, you are in the Eastern time | |
| 156 150 | 
             
             * Arild Shirazi  http://github.com/ashirazi
         | 
| 157 151 | 
             
             * Piotr Jakubowski http://github.com/piotrj
         | 
| 158 152 | 
             
             * Glenn Vanderburg http://github.com/glv
         | 
| 159 | 
            -
             
         | 
| 153 | 
            +
             * Michael Grosser http://github.com/grosser
         | 
| 154 | 
            +
             | 
| 160 155 | 
             
             (Special thanks for Arild on the complexities of dealing with TimeWithZone)
         | 
| 161 | 
            -
             | 
| 156 | 
            +
             | 
| 162 157 | 
             
            == Note on Patches/Pull Requests
         | 
| 163 | 
            -
             | 
| 158 | 
            +
             | 
| 164 159 | 
             
            * Fork the project.
         | 
| 165 160 | 
             
            * Make your feature addition or bug fix.
         | 
| 166 161 | 
             
            * Add tests for it. This is important so I don't break it in a
         | 
| @@ -183,10 +178,10 @@ This can lead to some wierd looking effects if, say, you are in the Eastern time | |
| 183 178 | 
             
              always trying to give the developer-user ultimate flexibility at the expense of the 'surface area' of the api.
         | 
| 184 179 | 
             
              Never again - I will sooner limit functionality to 80% so that something stays usable and let people fork.
         | 
| 185 180 | 
             
            * While there have been requests to add 'business minutes' and even 'business seconds' to this gem, I won't
         | 
| 186 | 
            -
              entertain a  | 
| 181 | 
            +
              entertain a pull request with such things.  If you find it useful, great.  Most users won't, and they don't
         | 
| 187 182 | 
             
              need the baggage.
         | 
| 188 183 |  | 
| 189 | 
            -
             | 
| 184 | 
            +
             | 
| 190 185 | 
             
            == Copyright
         | 
| 191 186 |  | 
| 192 187 | 
             
            Copyright (c) 2010,2011,2012,2013 bokmann. See LICENSE for details.
         | 
| @@ -8,7 +8,7 @@ module BusinessTime | |
| 8 8 | 
             
                end
         | 
| 9 9 |  | 
| 10 10 | 
             
                def after(time = Time.now)
         | 
| 11 | 
            -
                  time = Time.zone ? Time.zone.parse(time. | 
| 11 | 
            +
                  time = Time.zone ? Time.zone.parse(time.strftime('%Y-%m-%d %H:%M:%S %z')) : Time.parse(time.strftime('%Y-%m-%d %H:%M:%S %z'))
         | 
| 12 12 | 
             
                  days = @days
         | 
| 13 13 | 
             
                  while days > 0 || !Time.workday?(time)
         | 
| 14 14 | 
             
                    days -= 1 if Time.workday?(time)
         | 
| @@ -21,7 +21,7 @@ module BusinessTime | |
| 21 21 | 
             
                alias_method :since, :after
         | 
| 22 22 |  | 
| 23 23 | 
             
                def before(time = Time.now)
         | 
| 24 | 
            -
                  time = Time.zone ? Time.zone.parse(time. | 
| 24 | 
            +
                  time = Time.zone ? Time.zone.parse(time.rfc822) : Time.parse(time.rfc822)
         | 
| 25 25 | 
             
                  days = @days
         | 
| 26 26 | 
             
                  while days > 0 || !Time.workday?(time)
         | 
| 27 27 | 
             
                    days -= 1 if Time.workday?(time)
         | 
| @@ -19,9 +19,15 @@ module BusinessTime | |
| 19 19 | 
             
                  @hours.times do
         | 
| 20 20 | 
             
                    after_time = after_time + 1.hour
         | 
| 21 21 |  | 
| 22 | 
            +
                    # Roll back a second if it is midnight so that we check end_of_workday for the right day
         | 
| 23 | 
            +
                    if after_time.hour == 0 && after_time.min == 0 && after_time.sec == 0
         | 
| 24 | 
            +
                      after_time = after_time - 1.second
         | 
| 25 | 
            +
                    end
         | 
| 26 | 
            +
             | 
| 22 27 | 
             
                    # Ignore hours before opening and after closing
         | 
| 23 | 
            -
                    if (after_time  | 
| 24 | 
            -
                       | 
| 28 | 
            +
                    if (after_time >= Time.end_of_workday(after_time))
         | 
| 29 | 
            +
                      delta = after_time - Time.end_of_workday(after_time)
         | 
| 30 | 
            +
                      after_time = Time.roll_forward(after_time) + delta
         | 
| 25 31 | 
             
                    end
         | 
| 26 32 |  | 
| 27 33 | 
             
                    # Ignore weekends and holidays
         | 
    
        data/lib/business_time/config.rb
    CHANGED
    
    | @@ -7,115 +7,146 @@ module BusinessTime | |
| 7 7 | 
             
              # manually, or with a yaml file and the load method.
         | 
| 8 8 | 
             
              class Config
         | 
| 9 9 | 
             
                class << self
         | 
| 10 | 
            -
                   | 
| 11 | 
            -
                  # by saying
         | 
| 12 | 
            -
                  #   BusinessTime::Config.beginning_of_workday = "8:30 am"
         | 
| 13 | 
            -
                  # someplace in the initializers of your application.
         | 
| 14 | 
            -
                  attr_accessor :beginning_of_workday
         | 
| 15 | 
            -
             | 
| 16 | 
            -
                  # You can set this yourself, either by the load method below, or
         | 
| 17 | 
            -
                  # by saying
         | 
| 18 | 
            -
                  #   BusinessTime::Config.end_of_workday = "5:30 pm"
         | 
| 19 | 
            -
                  # someplace in the initializers of your application.
         | 
| 20 | 
            -
                  attr_accessor :end_of_workday
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                  # You can set this yourself, either by the load method below, or
         | 
| 23 | 
            -
                  # by saying
         | 
| 24 | 
            -
                  #   BusinessTime::Config.work_week = [:sun, :mon, :tue, :wed, :thu]
         | 
| 25 | 
            -
                  # someplace in the initializers of your application.
         | 
| 26 | 
            -
                  attr_accessor :work_week
         | 
| 27 | 
            -
             | 
| 28 | 
            -
                  # You can set this yourself, either by the load method below, or
         | 
| 29 | 
            -
                  # by saying
         | 
| 30 | 
            -
                  #   BusinessTime::Config.holidays << my_holiday_date_object
         | 
| 31 | 
            -
                  # someplace in the initializers of your application.
         | 
| 32 | 
            -
                  attr_accessor :holidays
         | 
| 33 | 
            -
             | 
| 34 | 
            -
                  # working hours for each day - if not set using global variables :beginning_of_workday 
         | 
| 35 | 
            -
                  # and end_of_workday. Keys will be added ad weekdays.
         | 
| 36 | 
            -
                  # Example:
         | 
| 37 | 
            -
                  #    {:mon => ["9:00","17:00"],:tue => ["9:00","17:00"].....}
         | 
| 38 | 
            -
                  attr_accessor :work_hours
         | 
| 10 | 
            +
                  private
         | 
| 39 11 |  | 
| 40 | 
            -
             | 
| 12 | 
            +
                  def config
         | 
| 13 | 
            +
                    Thread.current[:business_time_config] ||= {}
         | 
| 14 | 
            +
                  end
         | 
| 41 15 |  | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
                    wday = @work_hours[self.int_to_wday(day.wday)]
         | 
| 45 | 
            -
                    wday ? (wday.last =~ /0{1,2}\:0{1,2}/ ? "23:59:59" : wday.last) : @end_of_workday
         | 
| 46 | 
            -
                  else
         | 
| 47 | 
            -
                    @end_of_workday
         | 
| 16 | 
            +
                  def config=(config)
         | 
| 17 | 
            +
                    Thread.current[:business_time_config] = config
         | 
| 48 18 | 
             
                  end
         | 
| 49 | 
            -
                end
         | 
| 50 19 |  | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 54 | 
            -
                     | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 20 | 
            +
                  def threadsafe_cattr_accessor(name)
         | 
| 21 | 
            +
                    define_singleton_method name do
         | 
| 22 | 
            +
                      config[name]
         | 
| 23 | 
            +
                    end
         | 
| 24 | 
            +
                    define_singleton_method "#{name}=" do |value|
         | 
| 25 | 
            +
                      config[name] = value
         | 
| 26 | 
            +
                    end
         | 
| 57 27 | 
             
                  end
         | 
| 58 28 | 
             
                end
         | 
| 59 29 |  | 
| 60 | 
            -
                 | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 63 | 
            -
                 | 
| 30 | 
            +
                # You can set this yourself, either by the load method below, or
         | 
| 31 | 
            +
                # by saying
         | 
| 32 | 
            +
                #   BusinessTime::Config.beginning_of_workday = "8:30 am"
         | 
| 33 | 
            +
                # someplace in the initializers of your application.
         | 
| 34 | 
            +
                threadsafe_cattr_accessor :beginning_of_workday
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                # You can set this yourself, either by the load method below, or
         | 
| 37 | 
            +
                # by saying
         | 
| 38 | 
            +
                #   BusinessTime::Config.end_of_workday = "5:30 pm"
         | 
| 39 | 
            +
                # someplace in the initializers of your application.
         | 
| 40 | 
            +
                threadsafe_cattr_accessor :end_of_workday
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                # You can set this yourself, either by the load method below, or
         | 
| 43 | 
            +
                # by saying
         | 
| 44 | 
            +
                #   BusinessTime::Config.work_week = [:sun, :mon, :tue, :wed, :thu]
         | 
| 45 | 
            +
                # someplace in the initializers of your application.
         | 
| 46 | 
            +
                threadsafe_cattr_accessor :work_week
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                # You can set this yourself, either by the load method below, or
         | 
| 49 | 
            +
                # by saying
         | 
| 50 | 
            +
                #   BusinessTime::Config.holidays << my_holiday_date_object
         | 
| 51 | 
            +
                # someplace in the initializers of your application.
         | 
| 52 | 
            +
                threadsafe_cattr_accessor :holidays
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                # working hours for each day - if not set using global variables :beginning_of_workday
         | 
| 55 | 
            +
                # and end_of_workday. Keys will be added ad weekdays.
         | 
| 56 | 
            +
                # Example:
         | 
| 57 | 
            +
                #    {:mon => ["9:00","17:00"],:tue => ["9:00","17:00"].....}
         | 
| 58 | 
            +
                threadsafe_cattr_accessor :work_hours
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                threadsafe_cattr_accessor :_weekdays # internal
         | 
| 64 61 |  | 
| 65 | 
            -
                 | 
| 66 | 
            -
                   | 
| 62 | 
            +
                class << self
         | 
| 63 | 
            +
                  def end_of_workday(day=nil)
         | 
| 64 | 
            +
                    if day
         | 
| 65 | 
            +
                      wday = work_hours[int_to_wday(day.wday)]
         | 
| 66 | 
            +
                      wday ? (wday.last =~ /0{1,2}\:0{1,2}/ ? "23:59:59" : wday.last) : config[:end_of_workday]
         | 
| 67 | 
            +
                    else
         | 
| 68 | 
            +
                      config[:end_of_workday]
         | 
| 69 | 
            +
                    end
         | 
| 70 | 
            +
                  end
         | 
| 67 71 |  | 
| 68 | 
            -
                   | 
| 69 | 
            -
                     | 
| 70 | 
            -
             | 
| 72 | 
            +
                  def beginning_of_workday(day=nil)
         | 
| 73 | 
            +
                    if day
         | 
| 74 | 
            +
                      wday = work_hours[int_to_wday(day.wday)]
         | 
| 75 | 
            +
                      wday ? wday.first : config[:beginning_of_workday]
         | 
| 76 | 
            +
                    else
         | 
| 77 | 
            +
                      config[:beginning_of_workday]
         | 
| 78 | 
            +
                    end
         | 
| 71 79 | 
             
                  end
         | 
| 72 | 
            -
                end
         | 
| 73 80 |  | 
| 74 | 
            -
             | 
| 75 | 
            -
             | 
| 76 | 
            -
             | 
| 77 | 
            -
             | 
| 81 | 
            +
                  def work_week=(days)
         | 
| 82 | 
            +
                    config[:work_week] = days
         | 
| 83 | 
            +
                    self._weekdays = nil
         | 
| 84 | 
            +
                  end
         | 
| 78 85 |  | 
| 79 | 
            -
             | 
| 80 | 
            -
             | 
| 81 | 
            -
                end
         | 
| 86 | 
            +
                  def weekdays
         | 
| 87 | 
            +
                    return _weekdays unless _weekdays.nil?
         | 
| 82 88 |  | 
| 83 | 
            -
             | 
| 84 | 
            -
             | 
| 85 | 
            -
             | 
| 86 | 
            -
             | 
| 87 | 
            -
                   | 
| 88 | 
            -
             | 
| 89 | 
            -
                   | 
| 90 | 
            -
             | 
| 89 | 
            +
                    self._weekdays = (!work_hours.empty? ? work_hours.keys : work_week).each_with_object([]) do |day_name, days|
         | 
| 90 | 
            +
                      day_num = wday_to_int(day_name)
         | 
| 91 | 
            +
                      days << day_num unless day_num.nil?
         | 
| 92 | 
            +
                    end
         | 
| 93 | 
            +
                  end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                  # loads the config data from a yaml file written as:
         | 
| 96 | 
            +
                  #
         | 
| 97 | 
            +
                  #   business_time:
         | 
| 98 | 
            +
                  #     beginning_od_workday: 8:30 am
         | 
| 99 | 
            +
                  #     end_of_workday: 5:30 pm
         | 
| 100 | 
            +
                  #     holidays:
         | 
| 101 | 
            +
                  #       - Jan 1st, 2010
         | 
| 102 | 
            +
                  #       - July 4th, 2010
         | 
| 103 | 
            +
                  #       - Dec 25th, 2010
         | 
| 104 | 
            +
                  def load(file)
         | 
| 105 | 
            +
                    reset
         | 
| 106 | 
            +
                    data = YAML::load(file.respond_to?(:read) ? file : File.open(file))
         | 
| 107 | 
            +
                    config = (data["business_time"] || {})
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                    # load each config variable from the file, if it's present and valid
         | 
| 110 | 
            +
                    config_vars = %w(beginning_of_workday end_of_workday work_week work_hours)
         | 
| 111 | 
            +
                    config_vars.each do |var|
         | 
| 112 | 
            +
                      send("#{var}=", config[var]) if config[var] && respond_to?("#{var}=")
         | 
| 113 | 
            +
                    end
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                    (config["holidays"] || []).each do |holiday|
         | 
| 116 | 
            +
                      holidays << Date.parse(holiday)
         | 
| 117 | 
            +
                    end
         | 
| 118 | 
            +
                  end
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                  def with(config)
         | 
| 121 | 
            +
                    old = config().dup
         | 
| 122 | 
            +
                    config.each { |k,v| send("#{k}=", v) } # calculations are done on setting
         | 
| 123 | 
            +
                    yield
         | 
| 124 | 
            +
                  ensure
         | 
| 125 | 
            +
                    self.config = old
         | 
| 126 | 
            +
                  end
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                  private
         | 
| 91 129 |  | 
| 92 | 
            -
             | 
| 93 | 
            -
             | 
| 94 | 
            -
             | 
| 95 | 
            -
                #     beginning_od_workday: 8:30 am
         | 
| 96 | 
            -
                #     end_of_workday: 5:30 pm
         | 
| 97 | 
            -
                #     holidays:
         | 
| 98 | 
            -
                #       - Jan 1st, 2010
         | 
| 99 | 
            -
                #       - July 4th, 2010
         | 
| 100 | 
            -
                #       - Dec 25th, 2010
         | 
| 101 | 
            -
                def self.load(file)
         | 
| 102 | 
            -
                  self.reset
         | 
| 103 | 
            -
                  data = YAML::load(file.respond_to?(:read) ? file : File.open(file))
         | 
| 104 | 
            -
                  config = (data["business_time"] || {})
         | 
| 105 | 
            -
             | 
| 106 | 
            -
                  # load each config variable from the file, if it's present and valid
         | 
| 107 | 
            -
                  config_vars = %w(beginning_of_workday end_of_workday work_week work_hours)
         | 
| 108 | 
            -
                  config_vars.each do |var|
         | 
| 109 | 
            -
                    send("#{var}=", config[var]) if config[var] && respond_to?("#{var}=")
         | 
| 130 | 
            +
                  def wday_to_int day_name
         | 
| 131 | 
            +
                    lowercase_day_names = ::Time::RFC2822_DAY_NAME.map(&:downcase)
         | 
| 132 | 
            +
                    lowercase_day_names.find_index(day_name.to_s.downcase)
         | 
| 110 133 | 
             
                  end
         | 
| 111 134 |  | 
| 112 | 
            -
                   | 
| 113 | 
            -
                     | 
| 135 | 
            +
                  def int_to_wday num
         | 
| 136 | 
            +
                    ::Time::RFC2822_DAY_NAME.map(&:downcase).map(&:to_sym)[num]
         | 
| 137 | 
            +
                  end
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                  def reset
         | 
| 140 | 
            +
                    self.holidays = []
         | 
| 141 | 
            +
                    self.beginning_of_workday = "9:00 am"
         | 
| 142 | 
            +
                    self.end_of_workday = "5:00 pm"
         | 
| 143 | 
            +
                    self.work_week = %w[mon tue wed thu fri]
         | 
| 144 | 
            +
                    self.work_hours = {}
         | 
| 145 | 
            +
                    self._weekdays = nil
         | 
| 114 146 | 
             
                  end
         | 
| 115 147 | 
             
                end
         | 
| 116 148 |  | 
| 117 | 
            -
                #reset the first time we are loaded.
         | 
| 118 | 
            -
                 | 
| 149 | 
            +
                # reset the first time we are loaded.
         | 
| 150 | 
            +
                reset
         | 
| 119 151 | 
             
              end
         | 
| 120 | 
            -
             | 
| 121 152 | 
             
            end
         | 
| @@ -1,13 +1,13 @@ | |
| 1 1 | 
             
            # Add workday and weekday concepts to the Date class
         | 
| 2 2 | 
             
            class Date
         | 
| 3 3 | 
             
              def workday?
         | 
| 4 | 
            -
                 | 
| 4 | 
            +
                weekday? && !BusinessTime::Config.holidays.include?(self)
         | 
| 5 5 | 
             
              end
         | 
| 6 | 
            -
             | 
| 6 | 
            +
             | 
| 7 7 | 
             
              def weekday?
         | 
| 8 | 
            -
                BusinessTime::Config.weekdays.include?  | 
| 8 | 
            +
                BusinessTime::Config.weekdays.include? wday
         | 
| 9 9 | 
             
              end
         | 
| 10 | 
            -
             | 
| 10 | 
            +
             | 
| 11 11 | 
             
              def business_days_until(to_date)
         | 
| 12 12 | 
             
                (self...to_date).select{ |day| day.workday? }.size
         | 
| 13 13 | 
             
              end
         | 
| @@ -4,15 +4,13 @@ | |
| 4 4 | 
             
            #  3.business_days.after(some_date)
         | 
| 5 5 | 
             
            #  4.business_hours.before(some_date_time)
         | 
| 6 6 | 
             
            class Fixnum
         | 
| 7 | 
            -
              include BusinessTime
         | 
| 8 | 
            -
              
         | 
| 9 7 | 
             
              def business_hours
         | 
| 10 | 
            -
                BusinessHours.new(self)
         | 
| 8 | 
            +
                BusinessTime::BusinessHours.new(self)
         | 
| 11 9 | 
             
              end
         | 
| 12 10 | 
             
              alias_method :business_hour, :business_hours
         | 
| 13 | 
            -
             | 
| 11 | 
            +
             | 
| 14 12 | 
             
              def business_days
         | 
| 15 | 
            -
                BusinessDays.new(self)
         | 
| 13 | 
            +
                BusinessTime::BusinessDays.new(self)
         | 
| 16 14 | 
             
              end
         | 
| 17 | 
            -
              alias_method :business_day, :business_days | 
| 18 | 
            -
            end
         | 
| 15 | 
            +
              alias_method :business_day, :business_days
         | 
| 16 | 
            +
            end
         | 
| @@ -1,14 +1,13 @@ | |
| 1 1 | 
             
            # Add workday and weekday concepts to the Time class
         | 
| 2 2 | 
             
            class Time
         | 
| 3 3 | 
             
              class << self
         | 
| 4 | 
            -
             | 
| 5 4 | 
             
                # Gives the time at the end of the workday, assuming that this time falls on a
         | 
| 6 5 | 
             
                # workday.
         | 
| 7 6 | 
             
                # Note: It pretends that this day is a workday whether or not it really is a
         | 
| 8 7 | 
             
                # workday.
         | 
| 9 8 | 
             
                def end_of_workday(day)
         | 
| 10 9 | 
             
                  end_of_workday = Time.parse(BusinessTime::Config.end_of_workday(day))
         | 
| 11 | 
            -
                   | 
| 10 | 
            +
                  change_business_time(day,end_of_workday.hour,end_of_workday.min,end_of_workday.sec)
         | 
| 12 11 | 
             
                end
         | 
| 13 12 |  | 
| 14 13 | 
             
                # Gives the time at the beginning of the workday, assuming that this time
         | 
| @@ -17,14 +16,14 @@ class Time | |
| 17 16 | 
             
                # workday.
         | 
| 18 17 | 
             
                def beginning_of_workday(day)
         | 
| 19 18 | 
             
                  beginning_of_workday = Time.parse(BusinessTime::Config.beginning_of_workday(day))
         | 
| 20 | 
            -
                   | 
| 19 | 
            +
                  change_business_time(day,beginning_of_workday.hour,beginning_of_workday.min,beginning_of_workday.sec)
         | 
| 21 20 | 
             
                end
         | 
| 22 21 |  | 
| 23 22 | 
             
                # True if this time is on a workday (between 00:00:00 and 23:59:59), even if
         | 
| 24 23 | 
             
                # this time falls outside of normal business hours.
         | 
| 25 24 | 
             
                def workday?(day)
         | 
| 26 25 | 
             
                  Time.weekday?(day) &&
         | 
| 27 | 
            -
             | 
| 26 | 
            +
                    !BusinessTime::Config.holidays.include?(day.to_date)
         | 
| 28 27 | 
             
                end
         | 
| 29 28 |  | 
| 30 29 | 
             
                # True if this time falls on a weekday.
         | 
| @@ -44,7 +43,7 @@ class Time | |
| 44 43 | 
             
                # when the time is outside of business hours
         | 
| 45 44 | 
             
                def roll_forward(time)
         | 
| 46 45 |  | 
| 47 | 
            -
                  if  | 
| 46 | 
            +
                  if Time.before_business_hours?(time) || !Time.workday?(time)
         | 
| 48 47 | 
             
                    next_business_time = Time.beginning_of_workday(time)
         | 
| 49 48 | 
             
                  elsif Time.after_business_hours?(time) || Time.end_of_workday(time) == time
         | 
| 50 49 | 
             
                    next_business_time = Time.beginning_of_workday(time + 1.day)
         | 
| @@ -62,12 +61,12 @@ class Time | |
| 62 61 | 
             
                # Rolls backwards to the previous end_of_workday when the time is outside
         | 
| 63 62 | 
             
                # of business hours
         | 
| 64 63 | 
             
                def roll_backward(time)
         | 
| 65 | 
            -
                  if (Time.before_business_hours?(time) || !Time.workday?(time))
         | 
| 66 | 
            -
                     | 
| 64 | 
            +
                  prev_business_time = if (Time.before_business_hours?(time) || !Time.workday?(time))
         | 
| 65 | 
            +
                    Time.end_of_workday(time) - 1.day
         | 
| 67 66 | 
             
                  elsif Time.after_business_hours?(time)
         | 
| 68 | 
            -
                     | 
| 67 | 
            +
                    Time.end_of_workday(time)
         | 
| 69 68 | 
             
                  else
         | 
| 70 | 
            -
                     | 
| 69 | 
            +
                    time.clone
         | 
| 71 70 | 
             
                  end
         | 
| 72 71 |  | 
| 73 72 | 
             
                  while !Time.workday?(prev_business_time)
         | 
| @@ -79,27 +78,21 @@ class Time | |
| 79 78 |  | 
| 80 79 | 
             
                private
         | 
| 81 80 |  | 
| 82 | 
            -
                def  | 
| 81 | 
            +
                def change_business_time time, hour, min=0, sec=0
         | 
| 83 82 | 
             
                  if Time.zone
         | 
| 84 83 | 
             
                    time.in_time_zone(Time.zone).change(:hour => hour, :min => min, :sec => sec)
         | 
| 85 84 | 
             
                  else
         | 
| 86 85 | 
             
                    time.change(:hour => hour, :min => min, :sec => sec)
         | 
| 87 86 | 
             
                  end
         | 
| 88 87 | 
             
                end
         | 
| 89 | 
            -
             | 
| 90 | 
            -
             | 
| 91 88 | 
             
              end
         | 
| 92 | 
            -
            end
         | 
| 93 | 
            -
             | 
| 94 | 
            -
            class Time
         | 
| 95 89 |  | 
| 96 90 | 
             
              def business_time_until(to_time)
         | 
| 97 | 
            -
             | 
| 98 91 | 
             
                # Make sure that we will calculate time from A to B "clockwise"
         | 
| 99 | 
            -
                direction = 1
         | 
| 100 92 | 
             
                if self < to_time
         | 
| 101 93 | 
             
                  time_a = self
         | 
| 102 94 | 
             
                  time_b = to_time
         | 
| 95 | 
            +
                  direction = 1
         | 
| 103 96 | 
             
                else
         | 
| 104 97 | 
             
                  time_a = to_time
         | 
| 105 98 | 
             
                  time_b = self
         | 
| @@ -113,7 +106,7 @@ class Time | |
| 113 106 | 
             
                # If same date, then calculate difference straight forward
         | 
| 114 107 | 
             
                if time_a.to_date == time_b.to_date
         | 
| 115 108 | 
             
                  result = time_b - time_a
         | 
| 116 | 
            -
                  return result  | 
| 109 | 
            +
                  return result * direction
         | 
| 117 110 | 
             
                end
         | 
| 118 111 |  | 
| 119 112 | 
             
                # Both times are in different dates
         | 
| @@ -142,7 +135,6 @@ class Time | |
| 142 135 | 
             
                end
         | 
| 143 136 |  | 
| 144 137 | 
             
                # Make sure that sign is correct
         | 
| 145 | 
            -
                result  | 
| 138 | 
            +
                result * direction
         | 
| 146 139 | 
             
              end
         | 
| 147 | 
            -
             | 
| 148 140 | 
             
            end
         | 
| @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            BusinessTime::Config.load("#{Rails.root}/config/business_time.yml")
         | 
| 2 2 |  | 
| 3 3 | 
             
            # or you can configure it manually:  look at me!  I'm Tim Ferriss!
         | 
| 4 | 
            -
            #  BusinessTime | 
| 5 | 
            -
            #  BusinessTime | 
| 6 | 
            -
            #  BusinessTime | 
| 4 | 
            +
            #  BusinessTime::Config.beginning_of_workday = "10:00 am"
         | 
| 5 | 
            +
            #  BusinessTime::Config.end_of_workday = "11:30 am"
         | 
| 6 | 
            +
            #  BusinessTime::Config.holidays << Date.parse("August 4th, 2010")
         | 
| 7 7 |  | 
    
        metadata
    CHANGED
    
    | @@ -1,83 +1,110 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: business_time
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.7.0
         | 
| 5 | 
            +
              prerelease: 
         | 
| 5 6 | 
             
            platform: ruby
         | 
| 6 7 | 
             
            authors:
         | 
| 7 8 | 
             
            - bokmann
         | 
| 8 9 | 
             
            autorequire: 
         | 
| 9 10 | 
             
            bindir: bin
         | 
| 10 11 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 12 | 
            +
            date: 2014-01-27 00:00:00.000000000 Z
         | 
| 12 13 | 
             
            dependencies:
         | 
| 13 14 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 15 | 
             
              name: activesupport
         | 
| 15 16 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 17 | 
            +
                none: false
         | 
| 16 18 | 
             
                requirements:
         | 
| 17 | 
            -
                - - '>='
         | 
| 19 | 
            +
                - - ! '>='
         | 
| 18 20 | 
             
                  - !ruby/object:Gem::Version
         | 
| 19 21 | 
             
                    version: 3.1.0
         | 
| 20 22 | 
             
              type: :runtime
         | 
| 21 23 | 
             
              prerelease: false
         | 
| 22 24 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 25 | 
            +
                none: false
         | 
| 23 26 | 
             
                requirements:
         | 
| 24 | 
            -
                - - '>='
         | 
| 27 | 
            +
                - - ! '>='
         | 
| 25 28 | 
             
                  - !ruby/object:Gem::Version
         | 
| 26 29 | 
             
                    version: 3.1.0
         | 
| 27 30 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 28 31 | 
             
              name: tzinfo
         | 
| 29 32 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 33 | 
            +
                none: false
         | 
| 30 34 | 
             
                requirements:
         | 
| 31 35 | 
             
                - - ~>
         | 
| 32 36 | 
             
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            -
                    version:  | 
| 37 | 
            +
                    version: 1.1.0
         | 
| 34 38 | 
             
              type: :runtime
         | 
| 35 39 | 
             
              prerelease: false
         | 
| 36 40 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 41 | 
            +
                none: false
         | 
| 37 42 | 
             
                requirements:
         | 
| 38 43 | 
             
                - - ~>
         | 
| 39 44 | 
             
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            -
                    version:  | 
| 45 | 
            +
                    version: 1.1.0
         | 
| 41 46 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 42 47 | 
             
              name: rake
         | 
| 43 48 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 49 | 
            +
                none: false
         | 
| 44 50 | 
             
                requirements:
         | 
| 45 | 
            -
                - - '>='
         | 
| 51 | 
            +
                - - ! '>='
         | 
| 46 52 | 
             
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            -
                    version: 0 | 
| 53 | 
            +
                    version: '0'
         | 
| 48 54 | 
             
              type: :development
         | 
| 49 55 | 
             
              prerelease: false
         | 
| 50 56 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 57 | 
            +
                none: false
         | 
| 51 58 | 
             
                requirements:
         | 
| 52 | 
            -
                - - '>='
         | 
| 59 | 
            +
                - - ! '>='
         | 
| 53 60 | 
             
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            -
                    version: 0 | 
| 61 | 
            +
                    version: '0'
         | 
| 55 62 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 56 | 
            -
              name:  | 
| 63 | 
            +
              name: rdoc
         | 
| 57 64 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 65 | 
            +
                none: false
         | 
| 58 66 | 
             
                requirements:
         | 
| 59 | 
            -
                - - '>='
         | 
| 67 | 
            +
                - - ! '>='
         | 
| 60 68 | 
             
                  - !ruby/object:Gem::Version
         | 
| 61 69 | 
             
                    version: '0'
         | 
| 62 70 | 
             
              type: :development
         | 
| 63 71 | 
             
              prerelease: false
         | 
| 64 72 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 73 | 
            +
                none: false
         | 
| 65 74 | 
             
                requirements:
         | 
| 66 | 
            -
                - - '>='
         | 
| 75 | 
            +
                - - ! '>='
         | 
| 67 76 | 
             
                  - !ruby/object:Gem::Version
         | 
| 68 77 | 
             
                    version: '0'
         | 
| 69 78 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 70 | 
            -
              name:  | 
| 79 | 
            +
              name: minitest
         | 
| 80 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 81 | 
            +
                none: false
         | 
| 82 | 
            +
                requirements:
         | 
| 83 | 
            +
                - - ! '>='
         | 
| 84 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 85 | 
            +
                    version: '0'
         | 
| 86 | 
            +
              type: :development
         | 
| 87 | 
            +
              prerelease: false
         | 
| 88 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 89 | 
            +
                none: false
         | 
| 90 | 
            +
                requirements:
         | 
| 91 | 
            +
                - - ! '>='
         | 
| 92 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 93 | 
            +
                    version: '0'
         | 
| 94 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 95 | 
            +
              name: minitest-rg
         | 
| 71 96 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 97 | 
            +
                none: false
         | 
| 72 98 | 
             
                requirements:
         | 
| 73 | 
            -
                - - '>='
         | 
| 99 | 
            +
                - - ! '>='
         | 
| 74 100 | 
             
                  - !ruby/object:Gem::Version
         | 
| 75 101 | 
             
                    version: '0'
         | 
| 76 102 | 
             
              type: :development
         | 
| 77 103 | 
             
              prerelease: false
         | 
| 78 104 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 105 | 
            +
                none: false
         | 
| 79 106 | 
             
                requirements:
         | 
| 80 | 
            -
                - - '>='
         | 
| 107 | 
            +
                - - ! '>='
         | 
| 81 108 | 
             
                  - !ruby/object:Gem::Version
         | 
| 82 109 | 
             
                    version: '0'
         | 
| 83 110 | 
             
            description: Have you ever wanted to do things like "6.business_days.from_now" and
         | 
| @@ -101,27 +128,35 @@ files: | |
| 101 128 | 
             
            - rails_generators/business_time_config/business_time_config_generator.rb
         | 
| 102 129 | 
             
            - rails_generators/business_time_config/templates/business_time.rb
         | 
| 103 130 | 
             
            - rails_generators/business_time_config/templates/business_time.yml
         | 
| 104 | 
            -
            homepage:  | 
| 105 | 
            -
            licenses: | 
| 106 | 
            -
             | 
| 131 | 
            +
            homepage: https://github.com/bokmann/business_time
         | 
| 132 | 
            +
            licenses:
         | 
| 133 | 
            +
            - MIT
         | 
| 107 134 | 
             
            post_install_message: 
         | 
| 108 135 | 
             
            rdoc_options: []
         | 
| 109 136 | 
             
            require_paths:
         | 
| 110 137 | 
             
            - lib
         | 
| 111 138 | 
             
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 139 | 
            +
              none: false
         | 
| 112 140 | 
             
              requirements:
         | 
| 113 | 
            -
              - - '>='
         | 
| 141 | 
            +
              - - ! '>='
         | 
| 114 142 | 
             
                - !ruby/object:Gem::Version
         | 
| 115 143 | 
             
                  version: '0'
         | 
| 144 | 
            +
                  segments:
         | 
| 145 | 
            +
                  - 0
         | 
| 146 | 
            +
                  hash: 599448304722507361
         | 
| 116 147 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 148 | 
            +
              none: false
         | 
| 117 149 | 
             
              requirements:
         | 
| 118 | 
            -
              - - '>='
         | 
| 150 | 
            +
              - - ! '>='
         | 
| 119 151 | 
             
                - !ruby/object:Gem::Version
         | 
| 120 152 | 
             
                  version: '0'
         | 
| 153 | 
            +
                  segments:
         | 
| 154 | 
            +
                  - 0
         | 
| 155 | 
            +
                  hash: 599448304722507361
         | 
| 121 156 | 
             
            requirements: []
         | 
| 122 157 | 
             
            rubyforge_project: 
         | 
| 123 | 
            -
            rubygems_version:  | 
| 158 | 
            +
            rubygems_version: 1.8.23
         | 
| 124 159 | 
             
            signing_key: 
         | 
| 125 | 
            -
            specification_version:  | 
| 160 | 
            +
            specification_version: 3
         | 
| 126 161 | 
             
            summary: Support for doing time math in business hours and days
         | 
| 127 162 | 
             
            test_files: []
         | 
    
        checksums.yaml
    DELETED
    
    | @@ -1,7 +0,0 @@ | |
| 1 | 
            -
            ---
         | 
| 2 | 
            -
            SHA1:
         | 
| 3 | 
            -
              metadata.gz: 85605515b3dfca0f7d48ed3ff03cabe4d0265930
         | 
| 4 | 
            -
              data.tar.gz: f8637bacc2e3c19665a87484ad48c03056ec4a2e
         | 
| 5 | 
            -
            SHA512:
         | 
| 6 | 
            -
              metadata.gz: 73a15a3b9fef741d3e095c451871ff3ca51287499a46518bc01c7a4536db5347c9a919c0c4c4bf12b5f98381e1efb8ee675ef3be3e61be9fe44dc68935a47df1
         | 
| 7 | 
            -
              data.tar.gz: 2c3c0fb687cf7545e16d8315ed1d10dfe29c2bd3625b99f8c9226108bb22c5b9d693490089a4462b9cee839f28d0484c0e5989250245166e28370ae6352faddf
         |