# Business [![Gem version](https://badge.fury.io/rb/business.svg)](http://badge.fury.io/rb/business) [![Build status](https://travis-ci.org/gocardless/business.svg?branch=master)](https://travis-ci.org/gocardless/business) Date calculations based on business calendars. ## Documentation To get business, simply: ```bash $ gem install business ``` ### Getting started Get started with business by creating an instance of the calendar class, passing in a hash that specifies with days of the week are considered working days, and which days are holidays. ```ruby calendar = Business::Calendar.new( working_days: %w( mon tue wed thu fri ), holidays: ["01/01/2014", "03/01/2014"] ) ``` A few calendar configs are bundled with the gem (see lib/business/data for details). Load them by calling the `load` class method on `Calendar`. The `load_cached` variant of this method caches the calendars by name after loading them, to avoid reading and parsing the config file multiple times. ```ruby calendar = Business::Calendar.load("weekdays") calendar = Business::Calendar.load_cached("weekdays") ``` ### Checking for business days To check whether a given date is a business day (falls on one of the specified working days, and is not a holiday), use the `business_day?` method on `Calendar`. ```ruby calendar.business_day?(Date.parse("Monday, 9 June 2014")) # => true calendar.business_day?(Date.parse("Sunday, 8 June 2014")) # => false ``` ### Custom calendars To use a calendar you've written yourself, you need to add the directory it's stored in as an additional calendar load path: ```ruby Business::Calendar.additional_load_paths = ['path/to/your/calendar/directory'] ``` You can then load the calendar as normal. ### Business day arithmetic The `add_business_days` and `subtract_business_days` are used to perform business day arithmetic on dates. ```ruby date = Date.parse("Thursday, 12 June 2014") calendar.add_business_days(date, 4).strftime("%A, %d %B %Y") # => "Wednesday, 18 June 2014" calendar.subtract_business_days(date, 4).strftime("%A, %d %B %Y") # => "Friday, 06 June 2014" ``` The `roll_forward` and `roll_backward` methods snap a date to a nearby business day. If provided with a business day, they will return that date. Otherwise, they will advance (forward for `roll_forward` and backward for `roll_backward`) until a business day is found. ```ruby date = Date.parse("Saturday, 14 June 2014") calendar.roll_forward(date).strftime("%A, %d %B %Y") # => "Monday, 16 June 2014" calendar.roll_backward(date).strftime("%A, %d %B %Y") # => "Friday, 13 June 2014" ``` To count the number of business days between two dates, pass the dates to `business_days_between`. This method counts from start of the first date to start of the second date. So, assuming no holidays, there would be two business days between a Monday and a Wednesday. ```ruby date = Date.parse("Saturday, 14 June 2014") calendar.business_days_between(date, date + 7) # => 5 ``` ### Included Calendars We include some calendar data with this Gem but give no guarantees of its accuracy. The calendars that we include are: * Bacs * Bankgirot * BECS * Betalingsservice * Target (SEPA) ## But other libraries already do this Another gem, [business_time](https://github.com/bokmann/business_time), also exists for this purpose. We previously used business_time, but encountered several issues that prompted us to start business. Firstly, business_time works by monkey-patching `Date`, `Time`, and `FixNum`. While this enables syntax like `Time.now + 1.business_day`, it means that all configuration has to be global. GoCardless handles payments across several geographies, so being able to work with multiple working-day calendars is essential for us. Business provides a simple `Calendar` class, that is initialized with a configuration that specifies which days of the week are considered to be working days, and which dates are holidays. Secondly, business_time supports calculations on times as well as dates. For our purposes, date-based calculations are sufficient. Supporting time-based calculations as well makes the code significantly more complex. We chose to avoid this extra complexity by sticking solely to date-based mathematics. ![I'm late for business](http://3.bp.blogspot.com/-aq4iOz2OZzs/Ty8xaQwMhtI/AAAAAAAABrM/-vn4tcRA9-4/s1600/daily-morning-awesomeness-243.jpeg)