business-python


Namebusiness-python JSON
Version 2.1.0 PyPI version JSON
download
home_pagehttps://github.com/gocardless/business-python
SummaryDate calculations based on business calendars.
upload_time2023-08-03 14:32:20
maintainer
docs_urlNone
authorGoCardless
requires_python>=3.8.1,<4.0.0
license
keywords business days working days calendar date
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Business (Python)

[![circleci-badge](https://circleci.com/gh/gocardless/business-python.svg?style=shield)](https://app.circleci.com/pipelines/github/gocardless/business-python) [![pypi-badge](https://badge.fury.io/py/business-python.svg)](https://badge.fury.io/py/business-python)

Date calculations based on business calendars. (Python 3.8+)

Python implementation of https://github.com/gocardless/business

## Documentation

To get business, simply:

```bash
$ pip install business-python
```

## Version 2.1.0 breaking changes

In version 2.1.0 we have dropped support for End-of-Life Python version 3.6 and 3.7. Last release supporting these versions is [v2.0.3](https://github.com/gocardless/business-python/tree/v2.0.3).

## Version 2.0.0 breaking changes

In version 2.0.0 we have removed the bundled calendars. If you still need these they are available on [v1.0.1](https://github.com/gocardless/business-python/tree/74fe7e4068e0f16b68e7478f8b5ca1cc52f9a7d0/business/data).

### Migration

- Download/create calendars to a directory within your project eg: `lib/calendars`
- Change your code to include the `load_path` for your calendars
- Continue using `.load("my_calendar")` as usual

```python
# lib/calendars contains yml files
Calendar.load_paths = ['lib/calendars']
calendar = Calendar.load("my_calendar")
```

### Getting started

Get started with business by creating an instance of the calendar class, passing in a hash that specifies which days of the week are considered working days, and which days are holidays.

```python
from business.calendar import Calendar

calendar = Calendar(
  working_days=["monday", "tuesday", "wednesday", "thursday", "friday"],
  # array items are either parseable date strings, or real datetime.date objects
  holidays=["January 1st, 2020", "April 10th, 2020"],
  extra_working_dates=[],
)
```

`extra_working_dates` key makes the calendar to consider a weekend day as a working day.

If `working_days` is missing, then common default is used (mon-fri).
If `holidays` is missing, "no holidays" assumed.
If `extra_working_dates` is missing, then no changes in `working_days` will happen.

Elements of `holidays` and `extra_working_dates` may be either strings that `Calendar.parse_date()` can understand, or YYYY-MM-DD (which is considered as a Date by Python YAML itself).

#### Calendar YAML file example

```yaml
# lib/calendars/my_calendar.yml
working_days:
  - Monday
  - Sunday
holidays:
  - 2017-01-08 # Same as January 8th, 2017
extra_working_dates:
  - 2020-12-26 # Will consider 26 Dec 2020 (A Saturday), a working day
```

The `load_cache` method allows a thread safe way to avoid reloading the same calendar multiple times, and provides a performant way to dynamically load calendars for different requests.

#### Using business-python

Define your calendars in a folder eg: `lib/calendars` and set this directory on `Calendar.load_paths=`

```python
Calendar.load_paths = ['lib/calendars']
calendar = Calendar.load_cache("my_calendar")
```

### Input data types

The `parse_date` method is used to process the input date(s) in each method and return a `datetime.date` object.

```python
Calendar.parse_date("2019-01-01")
# => datetime.date(2019, 1, 1)
```

Supported data types are:

- `datetime.date`
- `datetime.datetime`
- `pandas.Timestamp` (treated as `datetime.datetime`)
- date string parseable by [`dateutil.parser.parse`](https://dateutil.readthedocs.io/en/stable/parser.html#dateutil.parser.parse)

`numpy.datetime64` is not supported, but can be converted to `datetime.date`:

```python
numpy.datetime64('2014-06-01T23:00:05.453000000').astype('M8[D]').astype('O')
# =>  datetime.date(2014, 6, 1)
```

### Checking for business days

To check whether a given date is a business day (falls on one of the specified working days or extra working dates, and is not a holiday), use the `is_business_day` method on `Calendar`.

```python
calendar.is_business_day("Monday, 8 June 2020")
# => true
calendar.is_business_day("Sunday, 7 June 2020")
# => false
```

### Business day arithmetic

> 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.

The `add_business_days` method is used to perform business day arithmetic on dates.

```python
input_date = Calendar.parse_date("Thursday, 12 June 2014")
calendar.add_business_days(input_date, 4).strftime("%A, %d %B %Y")
# => "Wednesday, 18 June 2014"
calendar.add_business_days(input_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.

```python
input_date = Calendar.parse_date("Saturday, 14 June 2014")
calendar.roll_forward(input_date).strftime("%A, %d %B %Y")
# => "Monday, 16 June 2014"
calendar.roll_backward(input_date).strftime("%A, %d %B %Y")
# => "Friday, 13 June 2014"
```

In contrast, the `next_business_day` and `previous_business_day` methods will always move to a next or previous date until a business day is found, regardless if the input provided is a business day.

```python
input_date = Calendar.parse_date("Monday, 9 June 2014")
calendar.roll_forward(input_date).strftime("%A, %d %B %Y")
# => "Monday, 09 June 2014"
calendar.next_business_day(input_date).strftime("%A, %d %B %Y")
# => "Tuesday, 10 June 2014"
calendar.previous_business_day(input_date).strftime("%A, %d %B %Y")
# => "Friday, 06 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.

```python
from datetime import timedelta

input_date = Calendar.parse_date("Saturday, 14 June 2014")
calendar.business_days_between(input_date, input_date + timedelta(days=7))
# => 5
```

The `get_business_day_of_month` method return the running total of business days for a given date in that month. This method counts the number of business days from the start of the first day of the month to the given input date.

```python
input_date = Calendar.parse_date("Thursday, 12 June 2014")
calendar.get_business_day_of_month(input_date)
# => 9
```

## License & Contributing

- This is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
- Bug reports and pull requests are welcome on GitHub at https://github.com/gocardless/business-python.

GoCardless ♥ open source. If you do too, come [join us](https://gocardless.com/about/jobs).

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/gocardless/business-python",
    "name": "business-python",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8.1,<4.0.0",
    "maintainer_email": "",
    "keywords": "business days,working days,calendar,date",
    "author": "GoCardless",
    "author_email": "engineering@gocardless.com",
    "download_url": "https://files.pythonhosted.org/packages/d9/6b/367ce424f7c10aca63bc16bf303370b4ecb9539586a66c23eeac1c41f15a/business_python-2.1.0.tar.gz",
    "platform": null,
    "description": "# Business (Python)\n\n[![circleci-badge](https://circleci.com/gh/gocardless/business-python.svg?style=shield)](https://app.circleci.com/pipelines/github/gocardless/business-python) [![pypi-badge](https://badge.fury.io/py/business-python.svg)](https://badge.fury.io/py/business-python)\n\nDate calculations based on business calendars. (Python 3.8+)\n\nPython implementation of https://github.com/gocardless/business\n\n## Documentation\n\nTo get business, simply:\n\n```bash\n$ pip install business-python\n```\n\n## Version 2.1.0 breaking changes\n\nIn version 2.1.0 we have dropped support for End-of-Life Python version 3.6 and 3.7. Last release supporting these versions is [v2.0.3](https://github.com/gocardless/business-python/tree/v2.0.3).\n\n## Version 2.0.0 breaking changes\n\nIn version 2.0.0 we have removed the bundled calendars. If you still need these they are available on [v1.0.1](https://github.com/gocardless/business-python/tree/74fe7e4068e0f16b68e7478f8b5ca1cc52f9a7d0/business/data).\n\n### Migration\n\n- Download/create calendars to a directory within your project eg: `lib/calendars`\n- Change your code to include the `load_path` for your calendars\n- Continue using `.load(\"my_calendar\")` as usual\n\n```python\n# lib/calendars contains yml files\nCalendar.load_paths = ['lib/calendars']\ncalendar = Calendar.load(\"my_calendar\")\n```\n\n### Getting started\n\nGet started with business by creating an instance of the calendar class, passing in a hash that specifies which days of the week are considered working days, and which days are holidays.\n\n```python\nfrom business.calendar import Calendar\n\ncalendar = Calendar(\n  working_days=[\"monday\", \"tuesday\", \"wednesday\", \"thursday\", \"friday\"],\n  # array items are either parseable date strings, or real datetime.date objects\n  holidays=[\"January 1st, 2020\", \"April 10th, 2020\"],\n  extra_working_dates=[],\n)\n```\n\n`extra_working_dates` key makes the calendar to consider a weekend day as a working day.\n\nIf `working_days` is missing, then common default is used (mon-fri).\nIf `holidays` is missing, \"no holidays\" assumed.\nIf `extra_working_dates` is missing, then no changes in `working_days` will happen.\n\nElements of `holidays` and `extra_working_dates` may be either strings that `Calendar.parse_date()` can understand, or YYYY-MM-DD (which is considered as a Date by Python YAML itself).\n\n#### Calendar YAML file example\n\n```yaml\n# lib/calendars/my_calendar.yml\nworking_days:\n  - Monday\n  - Sunday\nholidays:\n  - 2017-01-08 # Same as January 8th, 2017\nextra_working_dates:\n  - 2020-12-26 # Will consider 26 Dec 2020 (A Saturday), a working day\n```\n\nThe `load_cache` method allows a thread safe way to avoid reloading the same calendar multiple times, and provides a performant way to dynamically load calendars for different requests.\n\n#### Using business-python\n\nDefine your calendars in a folder eg: `lib/calendars` and set this directory on `Calendar.load_paths=`\n\n```python\nCalendar.load_paths = ['lib/calendars']\ncalendar = Calendar.load_cache(\"my_calendar\")\n```\n\n### Input data types\n\nThe `parse_date` method is used to process the input date(s) in each method and return a `datetime.date` object.\n\n```python\nCalendar.parse_date(\"2019-01-01\")\n# => datetime.date(2019, 1, 1)\n```\n\nSupported data types are:\n\n- `datetime.date`\n- `datetime.datetime`\n- `pandas.Timestamp` (treated as `datetime.datetime`)\n- date string parseable by [`dateutil.parser.parse`](https://dateutil.readthedocs.io/en/stable/parser.html#dateutil.parser.parse)\n\n`numpy.datetime64` is not supported, but can be converted to `datetime.date`:\n\n```python\nnumpy.datetime64('2014-06-01T23:00:05.453000000').astype('M8[D]').astype('O')\n# =>  datetime.date(2014, 6, 1)\n```\n\n### Checking for business days\n\nTo check whether a given date is a business day (falls on one of the specified working days or extra working dates, and is not a holiday), use the `is_business_day` method on `Calendar`.\n\n```python\ncalendar.is_business_day(\"Monday, 8 June 2020\")\n# => true\ncalendar.is_business_day(\"Sunday, 7 June 2020\")\n# => false\n```\n\n### Business day arithmetic\n\n> 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.\n\nThe `add_business_days` method is used to perform business day arithmetic on dates.\n\n```python\ninput_date = Calendar.parse_date(\"Thursday, 12 June 2014\")\ncalendar.add_business_days(input_date, 4).strftime(\"%A, %d %B %Y\")\n# => \"Wednesday, 18 June 2014\"\ncalendar.add_business_days(input_date, -4).strftime(\"%A, %d %B %Y\")\n# => \"Friday, 06 June 2014\"\n```\n\nThe `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.\n\n```python\ninput_date = Calendar.parse_date(\"Saturday, 14 June 2014\")\ncalendar.roll_forward(input_date).strftime(\"%A, %d %B %Y\")\n# => \"Monday, 16 June 2014\"\ncalendar.roll_backward(input_date).strftime(\"%A, %d %B %Y\")\n# => \"Friday, 13 June 2014\"\n```\n\nIn contrast, the `next_business_day` and `previous_business_day` methods will always move to a next or previous date until a business day is found, regardless if the input provided is a business day.\n\n```python\ninput_date = Calendar.parse_date(\"Monday, 9 June 2014\")\ncalendar.roll_forward(input_date).strftime(\"%A, %d %B %Y\")\n# => \"Monday, 09 June 2014\"\ncalendar.next_business_day(input_date).strftime(\"%A, %d %B %Y\")\n# => \"Tuesday, 10 June 2014\"\ncalendar.previous_business_day(input_date).strftime(\"%A, %d %B %Y\")\n# => \"Friday, 06 June 2014\"\n```\n\nTo 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.\n\n```python\nfrom datetime import timedelta\n\ninput_date = Calendar.parse_date(\"Saturday, 14 June 2014\")\ncalendar.business_days_between(input_date, input_date + timedelta(days=7))\n# => 5\n```\n\nThe `get_business_day_of_month` method return the running total of business days for a given date in that month. This method counts the number of business days from the start of the first day of the month to the given input date.\n\n```python\ninput_date = Calendar.parse_date(\"Thursday, 12 June 2014\")\ncalendar.get_business_day_of_month(input_date)\n# => 9\n```\n\n## License & Contributing\n\n- This is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).\n- Bug reports and pull requests are welcome on GitHub at https://github.com/gocardless/business-python.\n\nGoCardless \u2665 open source. If you do too, come [join us](https://gocardless.com/about/jobs).\n",
    "bugtrack_url": null,
    "license": "",
    "summary": "Date calculations based on business calendars.",
    "version": "2.1.0",
    "project_urls": {
        "Bug Tracker": "https://github.com/gocardless/business-python/issues",
        "Changelog": "https://github.com/gocardless/business-python/blob/master/CHANGELOG.md",
        "Homepage": "https://github.com/gocardless/business-python",
        "Repository": "https://github.com/gocardless/business-python",
        "Security": "https://github.com/gocardless/business-python/blob/master/SECURITY.md"
    },
    "split_keywords": [
        "business days",
        "working days",
        "calendar",
        "date"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "c4159b1bda482237cb9b5e5b19b094f5524e6a28a1a8f906f47d5c27dc8f68f5",
                "md5": "158c0308bd035d42c1c54564fcd96efa",
                "sha256": "71facfdc48f3d4f9701b700846a283ee7e46f5062124ad09544866ab253df8ea"
            },
            "downloads": -1,
            "filename": "business_python-2.1.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "158c0308bd035d42c1c54564fcd96efa",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8.1,<4.0.0",
            "size": 8240,
            "upload_time": "2023-08-03T14:32:18",
            "upload_time_iso_8601": "2023-08-03T14:32:18.756074Z",
            "url": "https://files.pythonhosted.org/packages/c4/15/9b1bda482237cb9b5e5b19b094f5524e6a28a1a8f906f47d5c27dc8f68f5/business_python-2.1.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "d96b367ce424f7c10aca63bc16bf303370b4ecb9539586a66c23eeac1c41f15a",
                "md5": "6873f68b75edc01d5f406ee85b7f172a",
                "sha256": "0aea27ab44e11f9d8be7e5b530659c3b18651f01470288797151e10651898d8e"
            },
            "downloads": -1,
            "filename": "business_python-2.1.0.tar.gz",
            "has_sig": false,
            "md5_digest": "6873f68b75edc01d5f406ee85b7f172a",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8.1,<4.0.0",
            "size": 7796,
            "upload_time": "2023-08-03T14:32:20",
            "upload_time_iso_8601": "2023-08-03T14:32:20.563585Z",
            "url": "https://files.pythonhosted.org/packages/d9/6b/367ce424f7c10aca63bc16bf303370b4ecb9539586a66c23eeac1c41f15a/business_python-2.1.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-08-03 14:32:20",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "gocardless",
    "github_project": "business-python",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "business-python"
}
        
Elapsed time: 0.10928s