Comments (5)
Hey, @take! Glad to hear you're finding the gem useful.
You're correct that Biz#time
calculations using day-based durations aren't currently supported. Unlike duration calculations using seconds, minutes, and hours, day-based calculations move into a realm of behavior where people start to have differing opinions about what the optimal behavior should be. Black and white begins to give way to a muddy grey.
After spending good deal of time reading through the issues of similar gems, I know this functionality is important to a subset of users, but it's often plagued by inconsistencies and weird corner cases in practice.
For example, given a standard configuration:
Biz.configure do |config|
config.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'},
}
config.time_zone = 'Etc/UTC'
end
Consider these examples and possible return values:
# Business day, before hours
Biz.time(1, :day).after(Time.utc(2015, 3, 9, 6))
# => 2015-03-09 09:00:00 UTC?
# *or*
# => 2015-03-10 09:00:00 UTC?
# Business day, during hours
Biz.time(1, :day).after(Time.utc(2015, 3, 9, 12))
# => 2015-03-10 09:00:00 UTC?
# *or*
# => 2015-03-10 12:00:00 UTC?
# Business day, after hours
Biz.time(1, :day).after(Time.utc(2015, 3, 9, 20))
# => 2015-03-10 09:00:00 UTC?
# *or*
# => 2015-03-11 09:00:00 UTC?
# Non-business day
Biz.time(1, :day).after(Time.utc(2015, 3, 8, 12))
# => 2015-03-09 09:00:00 UTC?
# *or*
# => 2015-03-10 09:00:00 UTC?
I currently have an implementation in the works that would work like the following for the above examples:
# Business day, before hours
Biz.time(1, :day).after(Time.utc(2015, 3, 9, 6)) # => 2015-03-10 09:00:00 UTC
# Business day, during hours
Biz.time(1, :day).after(Time.utc(2015, 3, 9, 12)) # => 2015-03-10 09:00:00 UTC
# Business day, after hours
Biz.time(1, :day).after(Time.utc(2015, 3, 9, 20)) # => 2015-03-10 09:00:00 UTC
# Non-business day
Biz.time(1, :day).after(Time.utc(2015, 3, 8, 12)) # => 2015-03-09 09:00:00 UTC
The main idea is to have the calculation operate exclusively on the day level before dropping down to the hours configuration to return the first time after the number of specified business days has elapsed. I don't know if it'll satisfy everyone, but it will at least be consistent and easy to reason about.
In the meantime, I've already merged a PR to remove 'day' duration support for the time being until the real implementation is available. I'd love to hear any comments you have about the proposed implementation.
I'll keep this issue open and marked as a feature request for now.
from biz.
Thanks for the detailed informations!
Yea I realised that there are weird corner cases and I also found out some alternative gems has an API for it, and some doesn't.
For example the working_hours gem solves this by adding an API which advances to the next business time.
[9] pry(main)> time
=> 2015-03-09 17:01:00 UTC
[10] pry(main)> time + 1.working.days
=> Tue, 10 Mar 2015 17:01:00 UTC +00:00
[11] pry(main)> (time + 1.working.days).in_working_hours?
=> false
[12] pry(main)> WorkingHours.advance_to_working_time(time + 1.working.days)
=> Wed, 11 Mar 2015 09:00:00 UTC +00:00
but I think we can just include that operation inside the day calculation process, like you mentioned above.
I have an opinion about the current implementation you're working on, would be awesome if you read through it. Basically I agree with the The main idea is to have the calculation operate exclusively on the day level before dropping down to the hours configuration to return the first time after the number of specified business days has elapsed.
part, but I think I have a different opinion about how the day exclusive calculation works.
So for the 4 examples you posted above,
# Business day, before hours
Biz.time(1, :day).after(Time.utc(2015, 3, 9, 6)) # => 2015-03-10 09:00:00 UTC
# Business day, during hours
Biz.time(1, :day).after(Time.utc(2015, 3, 9, 12)) # => 2015-03-10 09:00:00 UTC
# Business day, after hours
Biz.time(1, :day).after(Time.utc(2015, 3, 9, 20)) # => 2015-03-10 09:00:00 UTC
# Non-business day
Biz.time(1, :day).after(Time.utc(2015, 3, 8, 12)) # => 2015-03-09 09:00:00 UTC
I'm basically against the last 3 because I think adding 1 business day means the next business time after the 24hours including the next business time.
So I think the last 3 should be
# Business day, during hours
Biz.time(1, :day).after(Time.utc(2015, 3, 9, 12)) # => 2015-03-10 12:00:00 UTC
# Business day, after hours
Biz.time(1, :day).after(Time.utc(2015, 3, 9, 20)) # => 2015-03-11 09:00:00 UTC
# Non-business day
Biz.time(1, :day).after(Time.utc(2015, 3, 8, 12)) # => 2015-03-09 12:00:00 UTC
Of course I don't think this the next business time after the 24hours including the next business time definition will be the definition for everyone, it might have some deficit, and I think there's a high possibility I'll change my mind.
So please tell me what you think about this definition.
Thanks! :D
from biz.
@take Thanks for taking the time to write that up. I think it makes a lot of sense, and the underlying rule is simple and consistent. Let me see what I can do!
from biz.
@craiglittle Thanks! Please feel free to ping me anytime, I'll be happy to help you :)
from biz.
@take I just opened a PR (#17) for this feature. Let's move the discussion over there!
from biz.
Related Issues (20)
- Question: equivalent of working_hours #advance_to_working_time ? HOT 2
- Specify extra working periods HOT 2
- NoMethodError: undefined method `on' for #<Biz::Periods::Proxy:0x007f9b164d5d10> HOT 3
- Find the next busniess day during work hours HOT 2
- NoMethodError: undefined method `wday' for nil:NilClass HOT 4
- dates.days(0).after returns nil HOT 4
- Short days before holiday HOT 2
- Store configuration in a database HOT 4
- Timezone not included in returned time objects HOT 2
- Infinity loop when no hours are configured HOT 3
- Times spanning over midnight (nonsensical hours provided) HOT 2
- Please consider adding a changelog HOT 3
- Strange behavior with 24-hour work days HOT 7
- help! 在设置shifts之后,时长计算有误,麻烦关注一下 HOT 1
- Export to schema.org OpeningHoursSpecification HOT 1
- Incorrect periods and working hours when shifts and hours fall on same day HOT 1
- How to handle cases where two schedules don't intersect at all? HOT 1
- Creating empty Biz::Schedule HOT 7
- TypeError Exception when using Ruby 2.4.0
- Documentation for setting global config in Rails HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from biz.