Giter Club home page Giter Club logo

business_time's Introduction

business_time

CI

ActiveSupport gives us some great helpers so we can do things like:

5.days.ago

and

8.hours.from_now

as well as helpers to do that from any provided date or time.

I needed this, but taking into account business hours/days and holidays.

Usage

install the gem

gem install business_time

open up your console

# if in irb, add these lines:

require 'business_time'

# try these examples, using the current time:

1.business_hour.from_now
4.business_hours.from_now
8.business_hours.from_now

1.business_hour.ago
4.business_hours.ago
8.business_hours.ago

1.business_day.from_now
4.business_days.from_now
8.business_days.from_now

1.business_day.ago
4.business_days.ago
8.business_days.ago

Date.today.workday?
Date.parse("2015-12-09").workday?
Date.parse("2015-12-12").workday?

And we can do it from any Date or Time object.

my_birthday = Date.parse("August 4th, 1969")
8.business_days.after(my_birthday)
8.business_days.before(my_birthday)

my_birthday = Time.parse("August 4th, 1969, 8:32 am")
8.business_days.after(my_birthday)
8.business_days.before(my_birthday)

We can adjust the start and end time of our business hours

BusinessTime::Config.beginning_of_workday = "8:30 am"
BusinessTime::Config.end_of_workday = "5:30 pm"

Or we can temporarily override the configured values

BusinessTime::Config.with(beginning_of_workday: "8 am", end_of_workday: "6 pm") do
  1.business_hour.from_now
end

and we can add holidays that don't count as business days

July 5 in 2010 is a monday that the U.S. takes off because our independence day falls on that Sunday.

three_day_weekend = Date.parse("July 5th, 2010")
BusinessTime::Config.holidays << three_day_weekend
friday_afternoon = Time.parse("July 2nd, 2010, 4:50 pm")
tuesday_morning = 1.business_hour.after(friday_afternoon)

plus, we can change the work week:

# July 9th in 2010 is a Friday.
BusinessTime::Config.work_week = [:sun, :mon, :tue, :wed, :thu]
thursday_afternoon = Time.parse("July 8th, 2010, 4:50 pm")
sunday_morning = 1.business_hour.after(thursday_afternoon)

As alternative we also can change the business hours for each work day:

BusinessTime::Config.work_hours = {
  mon: ["9:00","17:00"],
  fri: ["9:00","17:00"],
  sat: ["10:00","15:00"]
}
friday = Time.parse("December 24, 2010 15:00")
monday = Time.parse("December 27, 2010 11:00")
working_hours = friday.business_time_until(monday) # 9.hours

You can also calculate business duration between two dates

friday = Date.parse("December 24, 2010")
monday = Date.parse("December 27, 2010")
friday.business_days_until(monday) #=> 1

Or you can calculate business duration between two Time objects

ticket_reported = Time.parse("February 3, 2012, 10:40 am")
ticket_resolved = Time.parse("February 4, 2012, 10:50 am")
ticket_reported.business_time_until(ticket_resolved) #=> 8.hours + 10.minutes

You can also determine if a given time is within business hours

Time.parse("February 3, 2012, 10:00 am").during_business_hours?

Note that counterintuitively, durations might not be quite what you expect when involving weekends. Consider the following example:

ticket_reported = Time.parse("February 3, 2012, 10:40 am")
ticket_resolved = Time.parse("February 4, 2012, 10:40 am")
ticket_reported.business_time_until(ticket_resolved) # will equal 6 hours and 20 minutes!

Why does this happen? Feb 4 2012 is a Saturday. That time will roll over to Monday, Feb 6th 2012, 9:00am. The business time between 10:40am friday and 9am monday is 6 hours and 20 minutes. From a quick inspection of the code, it looks like it should be 8 hours.

Or you can calculate business dates between two dates

monday = Date.parse("December 20, 2010")
wednesday = Date.parse("December 22, 2010")
monday.business_dates_until(wednesday) #=> [Mon, 20 Dec 2010, Tue, 21 Dec 2010]

You can get the first workday after a time or return itself if it is a workday

saturday = Time.parse("Sat Aug 9, 18:00:00, 2014")
monday = Time.parse("Mon Aug 11, 18:00:00, 2014")
Time.first_business_day(saturday) #=> "Mon Aug 11, 18:00:00, 2014"
Time.first_business_day(monday) #=> "Mon Aug 11, 18:00:00, 2014"

# similar to Time#first_business_day Time#previous_business_day only cares about
# workdays:
saturday = Time.parse("Sat Aug 9, 18:00:00, 2014")
monday = Time.parse("Mon Aug 11, 18:00:00, 2014")
Time.previous_business_day(saturday) #=> "Fri Aug 8, 18:00:00, 2014"
Time.previous_business_day(monday) #=> "Mon Aug 11, 18:00:00, 2014"

Rails generator

rails generate business_time:config

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.

Timezone support

This gem strives to be timezone-agnostic. Due to some complications in the handling of timezones in the built in Time class, and some complexities (bugs?) in the timeWithZone class, this was harder than expected... but here's the idea:

  • When you configure the gem with something like 9:00am as the start time, this is agnostic of time zone.
  • When you are dealing with a Time or TimeWithZone class, the timezone is preserved and the beginning and end of times for the business day are referenced in that time zone.

This can lead to some weird looking effects if, say, you are in the Eastern time zone but doing everything in UTC times... Your business day will appear to start and end at 9:00 and 5:00 UTC.

If this seems perplexing to you, I can almost guarantee you are in over your head with timezones in other ways too, this is just the first place you encountered it.

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.

Integration with the Holidays gem

Chris Wise wrote up a great article[http://murmurinfo.wordpress.com/2012/01/11/handling-holidays-and-business-hours/] on using the business_time gem with the holidays[https://github.com/alexdunae/holidays] gem. It boils down to this:

Holidays.between(Date.civil(2013, 1, 1), 2.years.from_now, :ca_on, :observed).map do |holiday|
  BusinessTime::Config.holidays << holiday[:date]
  # Implement long weekends if they apply to the region, eg:
  # BusinessTime::Config.holidays << holiday[:date].next_week if !holiday[:date].weekday?
end

You can pass holidays as an option In addition to having static holidays in BusinessTime::Config.holidays, you can also pass holidays as an option (date, time, string, or array of dates, times and strings). If, for example, you are processing calculations for many regions with different holidays, you can pass in the appropriate holidays for the region with each calculation.

three_day_weekend = Date.parse("July 5th, 2010")
friday_afternoon = Time.parse("July 2nd, 2010, 4:50 pm")
tuesday_morning = 1.business_hour.after(friday_afternoon, holidays: three_day_weekend)

Contributors

(Special thanks for Arild on the complexities of dealing with TimeWithZone)

Note on Patches/Pull Requests

  • Fork the project.
  • Make your feature addition or bug fix.
  • Add tests for it. This is important so I don't break it in a future version unintentionally.
  • Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
  • Send me a pull request. Bonus points for topic branches.

TODO

  • Arild has pointed out that there may be some logical inconsistencies regarding the beginning_of_workday and end_of workday times not actually being considered inside of the workday. I'd like to make sure that they work as if the beginning_of_workday is included and the end_of_workday is not included, just like the '...' range operator in Ruby.

NOT TODO

  • I spent way too much time in my previous java-programmer life building frameworks that worshipped complexity, always trying to give the developer-user ultimate flexibility at the expense of the 'surface area' of the api. Never again - I will sooner limit functionality to 80% so that something stays usable and let people fork.
  • While there have been requests to add 'business minutes' and even 'business seconds' to this gem, I won't entertain a pull request with such things. If you find it useful, great. Most users won't, and they don't need the baggage.

A note on stability and change

Sometimes people ask me why this gem doesn't release more often. My opinions on that are best discussed in person in a friendly discussion, but I'll attempt some of that here.

First, a big part of the reason is that the projects I do use this gem on are happy with it's current functionality. It is 'suitable for the purpose' for which I released it, and as such, maintenance I do on this gem is a gift to the community.

Second, out of the ~1.3 million downloads (according to rubygems.org), the number of real 'issues' with this gem have been minimal. Most of the issues that are opened are really people with slightly different requirements than I have regarding whether 'off hours' work counts as the previous or the next business day, a disagreement on the semantics of days vs. hours, etc. I take care to try to explain these choices in the open issues, but to my mind, they aren't true issues if it's just a difference of opinion. Even so, I'll gladly accept pull requests that resolve this difference of opinion as a configuration option... just don't expect me to do your job for you. I've already given you 90% of what you need.

Third, a business time gem is, well, relevant to businesses. Many businesses don't move quickly. My government clients move even more slowly. Stability is favored in these environments.

Fourth, new features can wait. To the person that adds them they can be mission critical, but with modern packaging processes, they can use their version without waiting for their changes to be included in the upstream version. Their changes don't break your code.

I'm proud of the work in this gem; the stability is a big part of that. This gem has lived longer than many others that have attempted to do the same thing. I expect it to be here chugging away when Ruby has become the next COBOL.

Copyright

Copyright (c) 2010-2022 bokmann. See LICENSE for details.

business_time's People

Contributors

aghassipour avatar alessani avatar bokmann avatar cadenforrest avatar chapmajs avatar dependabot[bot] avatar drogus avatar dugjason avatar enricob avatar flink avatar glv avatar grosser avatar hmarr avatar ironsand avatar jaredbeck avatar jordinl avatar juliendsv avatar mnoack avatar mpg-yuya-tani avatar mstate avatar petergoldstein avatar piotrj avatar pyromaniac avatar ramontayag avatar rmm5t avatar rwilcox avatar saverio-kantox avatar sbounmy avatar tiagoblackcode avatar xlts avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

business_time's Issues

handling negative business hours & days

At present, negative values are accepted but basically treated as zero. Compare:

irb> 1.hour.ago
 => Fri, 11 Sep 2015 11:41:00 BST +01:00

irb> (-10).days.since(1.hour.ago)
 => Tue, 01 Sep 2015 11:41:00 BST +01:00

irb> (-10).business_days.since(1.hour.ago)
 => Fri, 11 Sep 2015 11:41:00 BST +01:00

Maybe it's a bit daft to try to use negative business days or hours, but people like me will still try to do it! (Having negatives does simplify some interval-based calculations, and Rails does the sensible thing already.)

One option is to get (-x).business_FOO.since(y) to call x.business_FOO.before(y). Even throwing an exception would be better than silently doing nothing.

ps. still a very handy gem - thanks!

Holidays not working when config.time_zone is changed in application.rb

I am using the business time gem and it seems that holidays are not being accounted for. Here's an example of what my config looks like and some console outputs.

/config/business_time.yml:

business_time:
  beginning_of_workday: 8:00 am
  end_of_workday: 1:00 pm
  holidays:
    - Feb 18th, 2013
    - May 27th, 2013
    - July 4th, 2013
    - Sep 2nd, 2013
    - Nov 28th, 2013
    - Nov 29th, 2013
    - Dec 25th, 2013
    - Dec 31st, 2013
    - Jan 1st, 2014
  work_week:
    - mon
    - tue
    - wed
    - thu
    - fri

in Rails console:

1.9.3p327 :024 > BusinessTime::Config.holidays
 => [Mon, 18 Feb 2013 00:00:00 PST -08:00, Mon, 27 May 2013 00:00:00 PDT -07:00, Thu, 04 Jul 2013 00:00:00 PDT -07:00, Mon, 02 Sep 2013 00:00:00 PDT -07:00, Thu, 28 Nov 2013 00:00:00 PST -08:00, Fri, 29 Nov 2013 00:00:00 PST -08:00, Wed, 25 Dec 2013 00:00:00 PST -08:00, Tue, 31 Dec 2013 00:00:00 PST -08:00, Wed, 01 Jan 2014 00:00:00 PST -08:00] 

1.9.3p327 :025 > Time.now
 => 2013-05-21 14:57:18 -0700 

1.9.3p327 :026 > 4.business_days.from_now
 => Mon, 27 May 2013 14:57:42 PDT -07:00

it clearly shows may 27th as a holiday, yet it chooses may 27th as a viable business day. Same with July 4th.
I don't think its a timezone issue because july 3rd and july 5th don't trigger as a holiday either.

1.9.3p327 :021 > 31.business_days.from_now
 => Wed, 03 Jul 2013 14:56:21 PDT -07:00 
1.9.3p327 :022 > 32.business_days.from_now
 => Thu, 04 Jul 2013 14:56:24 PDT -07:00 
1.9.3p327 :023 > 33.business_days.from_now
 => Fri, 05 Jul 2013 14:56:28 PDT -07:00

My project gem specs:

ruby 1.9.3p327
rails 3.2.11
business_time 0.6.1

EDIT:

it seems that updating the config.time_zone in application.rb is causing the issue. FOr instance, if i set:

config.time_zone = 'Pacific Time (US & Canada)'

then business_time holidays fail.

business_time_until output

Hello -

Possibly something I'm just not understanding but I can not quite figure out the output when I run the following. I would expect the output to be 14400 (seconds).

Loading development environment (Rails 3.2.9)
irb(main):001:0> s = Time.now
=> 2012-11-23 11:52:37 -0500
irb(main):002:0> e = s + 4.hours
=> 2012-11-23 15:52:37 -0500
irb(main):003:0> s.business_time_until(e)
=> 442.6407476099994


ruby 1.9.3p286 (2012-10-12 revision 37165) [x86_64-linux]

  • actionmailer (3.2.9)
  • actionpack (3.2.9)
  • activemodel (3.2.9)
  • activerecord (3.2.9)
  • activeresource (3.2.9)
  • activesupport (3.2.9)
  • business_time (0.6.1)

0.7.4 is incompatible with Ruby 2.2.0

0.7.4 was released with updated gems and several other changes, and with known incompatibilities with ruby 2.2.0. The point of 0.7.4 was to give a final dependency upgrade for people on older versions of ruby, so I could set a stage for a 0.8.0 release that can support ruby 2.2.0 and potentially drop support for 1.9.3 if needed .

to illustrate the incompatibility with 2.2.0, check out the project, use something like rbenv to set to ruby 2.2.0, and run the tests. They do not fail on ruby 2.1.5.

Thread issue with version 0.7.0

I just updated to version 0.7.0 now that business_time is thread safe.
Iโ€™m using it with rails 4.0.2, puma 2.7.1 and rubinius 2.2.3.
But now thereโ€™s a major problem, configuration is empty on every request made to the webserver.
Configuration is correctly loaded at startup but after that each thread has an empty configuration (as defined by the code at config.rb on line 13 of business time gem).
If I try with thin for example instead of puma, it seems to work as expected. So I think thereโ€™s a real bug in a true threaded environment (puma + rubinius).

Maybe Thread.current[:business_time_config] should automatically load a previously loaded configuration instead of giving an empty one.

Calculate distance of time in business days

Is it possible to calculate the number of business days between two timestamps? Or the number of hours (for example between a Wednesday at noon and following Tuesday at 3pm)? Thanks!

potential bug in business_days.after

please consider following code:

require 'json'
require 'date'
require 'business_time'

mydate = Date.parse("April 23, 2014")
printf "10 days after %d-%d-%d\n ", mydate.year, mydate.month, mydate.day
printf "using 10.business_days.after(<date>)\n"
print 10.business_days.after(mydate)
print "\n\n"
mydate = Date.parse("April 21, 2014")
printf "10 days after %d-%d-%d\n ", mydate.year, mydate.month, mydate.day
printf "using 10.business_days.after(<date>)\n"
print 10.business_days.after(mydate)
print "\n"

result:

10 days after 2014-4-23
 using 10.business_days.after(<date>)
2014-05-06 17:00:00 -0700

10 days after 2014-4-21
 using 10.business_days.after(<date>)
2014-05-05 17:00:00 -0700

expected the computed days to be 2 days apart.

API for knowing the next business time

as written in the doc, BusinessTime::TimeExtensions#workday? will return true even if the time is outside of the normal business time.

which means the returning value of BusinessTime::BusinessDays#after might be a time which is outside the normal business time.

I'm not against the spec of those API, but I think there are a large amount of people who would like to know the next business time after X business day.

To enable that, I think we'll need some new APIs for this gem, something like...

  1. BusinessTime::TimeExtensions#business_time?
  2. BusinessTime::TimeExtensions#next_if_not_business_time
    • returns the next business time if current time isn't business time
      1. will be used inside the implementation of this API I guess

wdyt? :O

business_day.after does not handle starting time outside business hours properly

The latest version of business_time does not seem to handle calculating business_days.after() based on a date/time that starts outside business hours.
An example:

irb(main):001:0> d=Time.parse("Saturday, August 17, 12:54am")
=> Sat Aug 17 00:54:00 -0700 2013
irb(main):002:0> 1.business_day.after(d)
=> Tue, 20 Aug 2013 00:54:00 PDT -07:00

It seems that business_days.after is completely ignoring the time, which seems to be wrong. It also seems to have the day off by one as 1 business day after should be the EOBD on Monday.

Why was BusinessTime::Config.reset made private?

One of the things our app needs to do is to reload the BusinessTime configuration to calculate differences for different companies.

We've had to resort to calling BusinessTime::Config.send(:reset) in order to reset the configuration. I'm not sure why it's required, you'd think just over-writing the work_hours config setting would do the trick, but it does not.

Here's a test script that proves the case (Ruby 1.9.3-p448, BusinessTime 0.7.2). The second business_days.after call should pass, but it doesn't until we call reset.

require 'business_time'

business_hours = {
  mon: ['09:00', '17:00'],
  tue: ['09:00', '17:00'],
  wed: ['09:00', '17:00'],
  thu: ['09:00', '17:00'],
  fri: ['09:00', '17:00'],
}

open_24_hours = {
  mon: ['00:00', '00:00'],
  tue: ['00:00', '00:00'],
  wed: ['00:00', '00:00'],
  thu: ['00:00', '00:00'],
  fri: ['00:00', '00:00'],
  sat: ['00:00', '00:00'],
  sun: ['00:00', '00:00'],
}

# April 1, 2014 is a Tuesday
start_date = Time.parse '1 April 2014 12:00pm'

BusinessTime::Config.work_hours = open_24_hours
if 15.business_days.after(start_date) == Time.parse('16 April 2014 12:00pm')
  puts '.'
else
  puts 'F'
end

BusinessTime::Config.work_hours = business_hours
if 15.business_days.after(start_date) == Time.parse('22 April 2014 12:00pm')
  puts '.'
else
  puts 'F'
end

BusinessTime::Config.send(:reset)
BusinessTime::Config.work_hours = business_hours
if 15.business_days.after(start_date) == Time.parse('22 April 2014 12:00pm')
  puts '.'
else
  puts 'F'
end

Rails 2 support

The gem's version number suddenly bump from 0.4.0 to 0.6.1, and drop support for rails 2.

So, some features, such as Time.business_time_until doesn't exist on v0.4.0, that means I cannot use this on a rails 2 app.

And I've saw a 0.5.0.pre commit message in git logs. but it seems that this version had never been released?

And also the README never mention will drop support for rails 2.

Holiday patterns

Many of our holidays are repeated year to year. These generally falling to an easy pattern. First Monday in September or December 25th.

I've looked but can't find if patterns are currently acceptable in business_time.yml file. If not, do you think it would be a worthwhile change? If so, I can work on and submit a pull request.

0.7 is incompatible with Rails 3.2.x

Dependency to tzinfo in Rails 3.2.16 is:

rails (= 3.2.16) ruby depends on
      tzinfo (~> 0.3.29) ruby

This incompatibility should be mentioned: the version 0.6.2 is the latest compatible with Rails 3.2.x

gem 'business_time', '~> 0.6.2'

holiday locale conf files

Hello David,

looks great ! Would it be possible to have locale holiday conf files ?

config/locales/holidays_jp.yml or config/locales/holidays_us.yml ? (country-wise)

No support for different countries/contexts.

We have an app that goes into multiple states/countries/provinces and each one has a different definition of a business day. Is there a way to properly support the different contexts needed?

[Feature Request] Holidays by country code

Hi:
It's a fairly big design change for the gem so I'd like to throw the ideas out there and see how other people like it.

BusinessTime::Config.holidays now is initialized as an empty array, but in theory we should have a hash of empty arrays with country codes as keys.

> BusinessTime::Config.holidays
> { US: ["2013-07-04", "2013-12-25"...],
      CA: ["2013-07-01", "2013-12-25...]}

Thoughts?

1.9.3 compatible?

Just curious on the timetable for getting this to work with Ruby 1.9.3-rc1, as this doesn't appear to work properly:

ruby-1.9.3-rc1 :031 > my_birthday = Date.strptime("04-08-2012", "%d-%m-%Y")
 => Sat, 04 Aug 2012 
ruby-1.9.3-rc1 :032 > 10.business_days.before(my_birthday)
 => Mon, 26 Mar 2012 00:00:00 CDT -05:00 

Thanks.

Incosistency between `business_days_until` and `business_days.after`

I've noticed an inconsistency between business_days_until and business_days.after.

>> sat = Date.parse("2006-01-07")
>> mon = Date.parse("2006-01-09")
>> tue = Date.parse("2006-01-10")

>> 1.business_days.after(sat).to_date
=> Mon, 09 Jan 2006
>> sat.business_days_until(mon)
=> 0
>> sat.business_days_until(tue)
=> 1

As you can see, one business day after saturday is monday, but there is 0 business days until monday and 1 business days untils tuesday. For me, adding days to weekend day should look like:

>> 1.business_day.after(sat).to_date
=> Tue, 10 Jan 2006

Let's say that I claim on my website that I will respond to emails within 1 business day. If someone send me an email on saturday, for me it's the same as they would send it on monday. I will read it on monday, so I would like to be able to respond on tuesday, not on monday. business_days_until seems to work with that in mind, but business_days.after acts differently.

Would you agree to change the implementation to match the above example?

1.business_day.before(date) not working

Please consider the following:

date = '12-Jan-2015'.to_date
=> Mon, 12 Jan 2015
1.business_day.before(date)
=> Fri, 09 Jan 2015 00:00:00 UTC +00:00

date = '11-Jan-2015'.to_date
=> Sun, 11 Jan 2015
1.business_day.before(date)
=> Thu, 08 Jan 2015 00:00:00 UTC +00:00

Same result if I set:

BusinessTime::Config.work_week = %w[mon tue wed thu fri]

It looks like a bug or am I missing any relevant setting?

Thanks.

Bug on the range for business_days_until

The code for business_days_until is as follows:

def business_days_until(to_date)
(self...to_date).select{ |day| day.workday? }.size
end

According to the Range on ruby the way is being done, it is excluding the last day. On my understanding the until you have to include the day you are passing as to_date.

Hence the function should look like:

def business_days_until(to_date)
(self..to_date).select{ |day| day.workday? }.size
end

This way it includes the to_date inside the range and it takes it into account.

No method error first_business day

Time.first_business_day(time_off_request.date_requested)

undefined method `first_business_day' for Time:Class (Also did not work for date class).

time_off_request.num_days.business_days.after(time_off_request.date_requested) does work so library is generally working

Even example on readme page not working
= Time.first_business_day(Time.parse("Sat Aug 9, 18:00:00, 2014"))

Method still available?

Ruby 2.2.1 Rails 4.2

Is this library still being supported?

Open issues go back over a year. Last master was release about 10 months ago. If this is dead, that should be announced in the readme and people can either fix themselves or move on.

Seems dead to me.

Basic comparison of business times

I am trying to test a service which provides calculated deadlines for records. My test goes something like this:

require 'rails_helper'

RSpec.describe CalculateDeadline, type: :model do
  describe 'for priority certificates' do
    let(:certificate) { create :certificate, service_level: 'priority' }

    it 'returns 3 business days' do
      expect(CalculateDeadline.call certificate).to eq 3.business_days
    end
  end
end

Of course, this fails miserably since there are no comparison methods provided and the two times are separate instances of BusinessTime::BusinessDays and as such not identical.

Can we add an equality evaluation method. If not, please explain how else I should test my code without either creating two Time instances to compare, or poking about in the instance with something like 3.business_days.instance_variable_get('@days').

NoMethodError: undefined method `during_business_hours?'

added gem 'business_time' to my rails 3.2.13 with ruby 1.9.3 project.
I'm getting the following error:

1.9.3p448 :015 > Time.now.during_business_hours?
  NoMethodError: undefined method `during_business_hours?'  for DateTime:Class

Any ideas?

Odd timezone behavior as soon as integrated with Rails

I ran into a very similar issue as #36, but different enough that I think it deserves a new ticket. I had a script using Business Time that was working just fine for a long time. As soon as I tried to integrate it into my Rails environment, my times started getting butchered. Here is the logic that seemed to be causing my issues:
https://github.com/bokmann/business_time/blob/develop/lib/business_time/time_extensions.rb#L107

Before I integrated Rails, Time.zone was nil. After adding Rails, Time.zone was always set to UTC. My timezone that I was trying to use (passed in the "time" variable) was in UTC-400.

For now I've solved this by setting my Rails timezone to the same timezone that I'm passing into my Business Time functions and that seems to have solved it, however as Business Time is supposed to be timezone agnostic, it would be nice to see this fixed and be able to go back to UTC in my rails app.

Edit: removed note about the new release that was mentioned in #36 after I noticed that the discussion was over a year old.

Update gem?

Ran in to an issue with calling business_days.after() on a date that started on the weekend. Found the bug #14 that has a fix for it and shows it was fixed over a year ago. Verified that the latest version of business_time I see as a gem is 0.6.1, but it still has the broken code in it.

Could you do a new release so the latest gem has the latest code please?

Broken with Rails 3 beta 4

Loading dates from the yml file results in the holiday array containing a bunch of TimeZone objects... The weird thing is that the dates are parsed correctly. Tracing what is read and what is stored gives me this:

  data["business_time"]["holidays"].each do |holiday|
    STDERR.puts "Got holiday #{holiday}; parsing to #{Time.zone.parse( holiday ).class}"
    self.holidays <<
      Time.zone ? Time.zone.parse(holiday) : Time.parse(holiday)
    STDERR.puts "Stored: #{self.holidays.last.class}"
  end

Got holiday 2010-12-24; parsing to ActiveSupport::TimeWithZone
Stored: ActiveSupport::TimeZone

Adding directly to the array in the initializer seems to work. Maybe some magic is going on in the Rails background that not everything regarding Times and Zones are loaded at the time the initializer is run.

Is it possible to create multiple objects with different worktimes?

Hi! First of all, great project!
I just stumbled upon it, and I was wondering if it is possible to create multiple instances of the base class with different business hours.
Something like this:

bt = BusinessTime.new(work_hours: {mon: ["9:00","17:00"], tue: ["10:00","15:00"]})
friday = Date.parse("December 24, 2010")
monday = Date.parse("December 27, 2010")
bt.business_days_until(friday, monday)

My use case is that in my startup we manage beauty salons which have many different opening times, with professionals that may have different working hours.

Weird business_hours.ago result

While this is not affecting my code, I noticed it while playing around while doing some brain storming on other stuff:

>> Time.now
=> 2016-03-31 11:15:08 -0400
>> 72.business_hours.ago
=> 2016-03-18 11:15:14 -0400

Using 3.business_days.ago works as expected.

>> 3.business_days.ago
=> 2016-03-28 11:15:21 -0400

warning: method redefined

I'm getting this with ruby 2.1.1

business_time-0.7.2/lib/business_time/config.rb:76: warning: method redefined; discarding old end_of_workday
business_time-0.7.2/lib/business_time/config.rb:31: warning: previous definition of end_of_workday was here
business_time-0.7.2/lib/business_time/config.rb:85: warning: method redefined; discarding old beginning_of_workday
business_time-0.7.2/lib/business_time/config.rb:31: warning: previous definition of beginning_of_workday was here
business_time-0.7.2/lib/business_time/config.rb:94: warning: method redefined; discarding old work_week=
business_time-0.7.2/lib/business_time/config.rb:34: warning: previous definition of work_week= was here

Consider changing the gem name

Hi @bokmann,

I don't really expect this to sway you, but oh well, I'll try.

I just started using this gem at work. I found out what the gem name references, and it's not super professional and could be reasonably alienating (making people not very comfortable at work).

I know it's technically super annoying to change the gem name (maybe publish to two gem names on rubygems? another hassle, I know).

I say all this as a one-time very tired/thankless OSS dev/maintainer. You made this gem, I didn't, and I get that. If anything, please just give this idea a couple minutes of thought.

-Alan

Business Hours per request

Hello David,

Thanks for the great work! We are using this gem in our rails application to generate reports.
Now some of our reports need to be calculated on 24 hrs working day and some for 8 hrs. Users generate these reports parallely. Right now the changes we are making are reflecting across the application. We were unable to change business hrs on per request basis. Is there any way to change it on per request basis? So that each of our user have different business hrs configuration?

Thanks in advance!

Regards,
Abhishek

How to deal with more than one working period for a given week day?

Your gem is excelent but there is little feature that I need and I would like to know if it could be added to the gem.

I need to define working hours for a given week day without the lunch time. For instance, work hours would be from 9:00 to 12:00 and from 13:00 to 18:00. Basically I would like to configure work hours with something like this:

BusinessTime::Config.work_hours = {
:mon=>["9:00","12:00","13:00","18:00"],
:tue=>["9:00","12:00","13:00","18:00"],
:wed=>["9:00","12:00","13:00","18:00"],
:thu=>["9:00","12:00","13:00","18:00"],
:fri=>["9:00","12:00","13:00","18:00"],
:sat=>["10:00","15:00"]
}

multiple configuration for each record

business_time is great gem but I wanted to know can I use it for multiple business hours for multiple records for example I have multiple records of restaurants which have different business timings like this

[
  Mon: {
    morning: {
      from: 9:00 am, to: 12:00 pm
    },
    noon:{
      from: 2:00 am, to: 5:00 pm
    },
    night{
      from: 7:00pm to: 11:pm
    }
  },
  Tue: {
    morning: {
      from: 10:00 am, to: 12:00 pm
    },
    noon:{
      from: 1:00 am, to: 5:00 pm
    },
    night: {
      from: 7:00pm to: 11:pm
    }
  },
  Wed: {
    morning: {
      from: 9:30 am, to: 12:00 pm
    },
    noon:{
      from: 1:30 am, to: 5:00 pm
    },
    night:{
      from: 7:00pm to: 11:pm
    }
  },
  Thu:{
    morning: {
      from: 9:00 am, to: 01:00 pm
    },
    noon:{
      from: 1:00 am, to: 5:00 pm
    },
    night:
    {
      from: 7:00pm to: 11:pm
    }
  },
  Fri:{
    morning: {
      from: 9:00 am, to: 01:00 pm
    },
    noon:{
      from: 1:00 am, to: 5:00 pm
    },
    night:{
      from: 7:00pm to: 11:pm
    }
  }
  Sat: off
  Sun: off
]

Can I use this gem for to implement this? if yes then How?

business_time_until and ActiveSupport::TimeWithZone

Hello,

Assuming

  • we are in a full working day (00:00:00-23:59:59)
  • Time.zone = 'Paris'

current issue is :

5.hours.ago.business_time_until 1.hours.ago
# => 7200.00005698204 // 2 hours
5.hours.ago.to_time.business_time_until 1.hours.ago.to_time
# => 14400.000063 // 4 hours

So 5 hours - 1 hours = 4 hours, the correct result is :

5.hours.ago.to_time.business_time_until 1.hours.ago.to_time

So why these 2 results are different ?

5.hours.ago.class
# => ActiveSupport::TimeWithZone
5.hours.ago.to_time
# => Time

Basically the main difference is the class used when dealing with business_time_until Time vs ActiveSupport::TimeWithZone
https://github.com/bokmann/business_time/blob/master/lib/business_time/core_ext/time.rb#L100 when using an ActiveSupport::TimeWithZone, it is converted to Time without converting using timezone properly.

I know that business_time is timezone agnostic, but using rails .ago, .from_now helpers are pretty convenient.

Any feedback is appreciated :) !

Calculates next business day wrong for a Sunday

Default configs. Saturday says 1 business day after is Monday. Friday says one business day after is Friday (itself). Thursday says 1 business day after is Thursday (itself). Sunday says 1 business day after is Tuesday. Would expect it to be Monday; same answer for Saturday since weekend is non-business day.

2.1.2 :014 > d = Date.parse("2015-03-28")
=> Sat, 28 Mar 2015
2.1.2 :015 > 1.business_days.after(d)
=> Mon, 30 Mar 2015 20:00:00 EDT -04:00
2.1.2 :016 > d = Date.parse("2015-03-29")
=> Sun, 29 Mar 2015
2.1.2 :017 > 1.business_days.after(d)
=> Tue, 31 Mar 2015 20:00:00 EDT -04:00
2.1.2 :018 > d = Date.parse("2015-03-27")
=> Fri, 27 Mar 2015
2.1.2 :019 > 1.business_days.after(d)
=> Fri, 27 Mar 2015 20:00:00 EDT -04:00
2.1.2 :020 > d = Date.parse("2015-03-26")
=> Thu, 26 Mar 2015
2.1.2 :021 > 1.business_days.after(d)
=> Thu, 26 Mar 2015 20:00:00 EDT -04:00
2.1.2 :022 >

Something wrong with after method

After last update i've seen some weird result from 'after' method:

Sample:

[email protected] (main)> d = Date.parse('2015-05-29')
=> Fri, 29 May 2015
[email protected] (main)> 0.business_days.after(d)
=> Fri, 29 May 2015
[email protected] (main)> 1.business_days.after(d)
=> Mon, 01 Jun 2015
[email protected] (main)> d = Date.parse('2015-05-30')
=> Sat, 30 May 2015
[email protected] (main)> 1.business_days.after(d)
=> Tue, 02 Jun 2015
[email protected] (main)> 0.business_days.after(d)
=> Mon, 01 Jun 2015

Both results should not be Mon, 01 Jun 2015?

I want to get first business day after a date

Release date of master?

I see some nice activity on master branch. 0.6.1 seems to be 1-9-3-support branch.

Is there a release date of the master branch?

ActiveRecord Support.

Thanks for such great work.

Is it possible to supply multiple sets of configurations using ActiveRecord? It is possible to have different working days and holiday days for a multi-location based company.

Thanks a lot

How to deal with several business times?

Idea of this gem is awesome and it almost did what I need. But it seems working time configuration made almost impossible to work with several business time schedules in the same application. For example, I need to deal bank business time and call center business time. Bank usually set it's own business time, but call center has extended availability and almost no holidays ...

Is there a way to solve this issue without hard fixing the core of business_time gem?

end_of_workday shouldn't be taken literal

First of all, thanks for such a great gem!

I'm not really sure if this is an issue since it's something about the way we communicate. When we set up an option to set the business hours for a webapp and the user sets the opening and closing hours (let's say 10:00am and 5:30pm), he would expect his business to be open at 10:00am and stay open until the minute of 5:30pm runs out, so at 5:30:59 is open, but it's closed at 5:31:00.

However, that's not happening, if the closing hour is set to 5:30, the last second it will stay open is 5:29:59.

I know the configuration can be set to include seconds, however, how many people will use it? I think it should be a default until otherwise is stated.

What I ended up doing was monkeypatching the method and adding 1 minute:

module BusinessTime
  module TimeExtensions
    module ClassMethods
      def end_of_workday(day)
        end_of_workday = Time.parse(BusinessTime::Config.end_of_workday(day)) + 1.minute
        change_business_time(day,end_of_workday.hour,end_of_workday.min,end_of_workday.sec)
      end
    end
  end
end

Maybe the way to go would be via a config setting?

Business Days missing in 2015

I noticed that we are missing January 30 and Feburary 27 as business days in 2015. Is there a reason for this?

2.1.4 :006 > date = "2015-03-01".to_date
 => Sun, 01 Mar 2015
2.1.4 :007 > 1.business_day.before(date)
 => Thu, 26 Feb 2015 00:00:00 UTC +00:00

.business_days.after and .business_days_until are not consistent with weekends/holidays

I am having some issues with these two functions. They are not giving me consistent results. For instance:

the following example works. start date is feb 11th, delivery date is feb 13th. 2.business_days_after returns the 13th, which is expected. .business_days_until returns 2 business days which is expected.

start_date => Wed, 11 Feb 2015 12:00:00 -0800
delivery_date = 2.business_days.after(start_date) => Fri, 13 Feb 2015 12:00:00 PST -08:00
start_date.business_days_until(delivery_date) => 2

However, lets add a weekend and a holiday (feb 16th is a holiday in config) into the mix

start_date => Wed, 11 Feb 2015 12:00:00 -0800
delivery_date = 3.business_days.after(start_date) => Tue, 17 Feb 2015 12:00:00 PST -08:00
start_date.business_days_until(delivery_date) => 4

.business_days_until is returning 4 business days instead of the expected 3.

Loading holidays from yml file does not work

There's a set of enclosing parentheses missing in file lib/business_time/config.rb, line 50. As is, I get TimeZone objects:
prompt$ script/runner 'puts BusinessTime::Config.holidays.collect(&:to_s)'
(GMT-05:00) Eastern Time (US & Canada)
(GMT-05:00) Eastern Time (US & Canada)
...

Changing the line to "(Time.zone ? Time.zone.parse(holiday) : Time.parse(holiday))", it works fine:
prompt$ script/runner 'puts BusinessTime::Config.holidays.collect(&:to_s)'
2010-01-01 00:00:00 -0500
2010-01-18 00:00:00 -0500
...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.