# timefhuman
[](https://pypi.python.org/pypi/timefhuman/)
[](https://coveralls.io/github/alvinwan/timefhuman?branch=master)
Extract datetimes, datetime ranges, and datetime lists from natural language text. Supports Python3+[^1]
[^1]: https://github.com/alvinwan/timefhuman/issues/3
----
## Getting Started
Install with pip using
```python
pip install timefhuman
```
Then, find natural language dates and times in any text.
```python
>>> from timefhuman import timefhuman
>>> timefhuman("How does 5p mon sound? Or maybe 4p tu?")
[datetime.datetime(2018, 8, 6, 17, 0), datetime.datetime(2018, 8, 7, 16, 0)]
```
The text can contain not only datetimes but also ranges of datetimes or lists of datetimes.
```python
>>> timefhuman('3p-4p') # time range
(datetime.datetime(2018, 7, 17, 15, 0), datetime.datetime(2018, 7, 17, 16, 0))
>>> timefhuman('7/17 4PM to 7/17 5PM') # range of datetimes
(datetime.datetime(2018, 7, 17, 16, 0), datetime.datetime(2018, 7, 17, 17, 0))
>>> timefhuman('Monday 3 pm or Tu noon') # list of datetimes
[datetime.datetime(2018, 8, 6, 15, 0), datetime.datetime(2018, 8, 7, 12, 0)]
>>> timefhuman('7/17 4-5 or 5-6 PM') # list of ranges of datetimes!
[(datetime.datetime(2018, 7, 17, 16, 0), datetime.datetime(2018, 7, 17, 17, 0)),
(datetime.datetime(2018, 7, 17, 17, 0), datetime.datetime(2018, 7, 17, 18, 0))]
```
Durations are also supported.
```python
>>> timefhuman('30 minutes') # duration
datetime.timedelta(seconds=1800)
>>> timefhuman('30-40 mins') # range of durations
(datetime.timedelta(seconds=1800), datetime.timedelta(seconds=2400))
>>> timefhuman('30 or 40m') # list of durations
[datetime.timedelta(seconds=1800), datetime.timedelta(seconds=2400)]
```
When possible, timefhuman will infer any missing information, using context from other datetimes.
```python
>>> timefhuman('3-4p') # infer "PM" for "3"
(datetime.datetime(2018, 7, 17, 15, 0), datetime.datetime(2018, 7, 17, 16, 0))
>>> timefhuman('7/17 4 or 5 PM') # infer "PM" for "4" and infer "7/17" for "5 PM"
[datetime.datetime(2018, 7, 17, 16, 0), datetime.datetime(2018, 7, 17, 17, 0)]
>>> timefhuman('7/17, 7/18, 7/19 at 9') # infer "9a" for "7/17", "7/18"
[datetime.datetime(2018, 7, 17, 9, 0), datetime.datetime(2018, 7, 18, 9, 0),
datetime.datetime(2018, 7, 19, 9, 0)]
>>> timefhuman('3p -4p PDT') # infer timezone "PDT" for "3p"
(datetime.datetime(2018, 8, 4, 15, 0, tzinfo=pytz.timezone('US/Pacific')),
datetime.datetime(2018, 8, 4, 16, 0, tzinfo=pytz.timezone('US/Pacific')))
```
You can also use natural language descriptions of dates and times.
```python
>>> timefhuman('next Monday')
datetime.datetime(2018, 8, 6, 0, 0)
>>> timefhuman('next next Monday')
datetime.datetime(2018, 8, 13, 0, 0)
>>> timefhuman('last Wednesday of December')
datetime.datetime(2018, 12, 26, 0, 0)
>>> timefhuman('afternoon')
datetime.datetime(2018, 8, 4, 15, 0)
```
See more examples in [`tests/test_e2e.py`](tests/test_e2e.py).
## Advanced Usage
For more configuration options, simply create a `tfhConfig` object.
```python
from timefhuman import tfhConfig
config = tfhConfig()
```
**Return matched text**: You can additionally grab the matched text from the input string. This is useful for modifying the input string, for example.
```python
>>> config = tfhConfig(return_matched_text=True)
>>> timefhuman('We could maybe do 3 PM, if you still have time', config=config)
[('3 PM', datetime.datetime(2018, 8, 4, 15, 0))]
```
**Change 'Now'**: You can configure the default date that timefhuman uses to fill in missing information. This would be useful if you're extracting dates from an email sent a year ago.
```python
>>> config = tfhConfig(now=datetime.datetime(2018, 8, 4, 0, 0))
>>> timefhuman('upcoming Monday noon', config=config)
datetime.datetime(2018, 8, 6, 12, 0)
```
You can also set a default timezone, by again using the config's `now`.
```python
>>> config = tfhConfig(
... now=datetime.datetime(2018, 8, 4), tzinfo=pytz.timezone('US/Pacific'))
>>> timefhuman('Wed', config=config)
datetime.datetime(2018, 8, 8, 0, 0, tzinfo=pytz.timezone('US/Pacific'))
>>> timefhuman('Wed EST', config=config) # EST timezone in the input takes precedence
datetime.datetime(2018, 8, 8, 0, 0, tzinfo=pytz.timezone('US/Michigan'))
```
**Use explicit information only**: Say you only want to extract *dates* OR *times*. You don't want the library to infer information. You can disable most inference by setting `infer_datetimes=False`. Instead of always returning a datetime, timefhuman will be able to return date or time objects, depending on what's provided.
```python
>>> config = tfhConfig(infer_datetimes=False)
>>> timefhuman('3 PM', config=config)
datetime.time(15, 0)
>>> timefhuman('12/18/18', config=config)
datetime.date(2018, 12, 18)
```
**Past datetimes**: By default, datetimes are assumed to occur in the future, so if "3pm" today has already passed, the returned datetime will be for *tomorrow*. However, if datetimes are assumed to have occurred in the past (e.g., from an old letter, talking about past events), you can configure the direction.
```python
>>> from timefhuman import Direction
>>> config = tfhConfig(direction=Direction.previous)
>>> timefhuman('3PM') # the default
datetime.datetime(2018, 8, 5, 15, 0)
>>> timefhuman('3PM', config=config) # changing direction
datetime.datetime(2018, 8, 4, 15, 0)
```
Here is the full set of supported configuration options:
```python
@dataclass
class tfhConfig:
# Default to the next valid datetime or the previous one
direction: Direction = Direction.next
# Always return datetime objects. If no date, use now.date(). If no time, use midnight.
infer_datetimes: bool = True
# The 'current' datetime, used if infer_datetimes is True. Defaults to datetime.now().
now: datetime | None = None
# Return the matched text from the input string
return_matched_text: bool = False
# Return a single object instead of a list when there's only one match
return_single_object: bool = True
```
## Development
Install the development version.
```shell
$ pip install .e .[test] # for bash
$ pip install -e .\[test\] # for zsh
```
To run tests and simultaneously generate a coverage report, use the following commands:
```shell
$ py.test --cov
$ coverage html
$ open htmlcov/index.html
```
Raw data
{
"_id": null,
"home_page": "https://github.com/alvinwan/timefhuman",
"name": "timefhuman",
"maintainer": null,
"docs_url": null,
"requires_python": null,
"maintainer_email": null,
"keywords": null,
"author": "Alvin Wan",
"author_email": "hi@alvinwan.com",
"download_url": "https://files.pythonhosted.org/packages/9a/3d/e9d9eb252a80dd47d87d829a068958221ca26cd210df6f989c4eecfcac8e/timefhuman-0.1.2.tar.gz",
"platform": null,
"description": "# timefhuman\n\n[](https://pypi.python.org/pypi/timefhuman/)\n[](https://coveralls.io/github/alvinwan/timefhuman?branch=master)\n\nExtract datetimes, datetime ranges, and datetime lists from natural language text. Supports Python3+[^1]\n\n[^1]: https://github.com/alvinwan/timefhuman/issues/3\n\n----\n\n## Getting Started\n\nInstall with pip using\n\n```python\npip install timefhuman\n```\n\nThen, find natural language dates and times in any text.\n\n```python\n>>> from timefhuman import timefhuman\n\n>>> timefhuman(\"How does 5p mon sound? Or maybe 4p tu?\")\n[datetime.datetime(2018, 8, 6, 17, 0), datetime.datetime(2018, 8, 7, 16, 0)]\n```\n\nThe text can contain not only datetimes but also ranges of datetimes or lists of datetimes.\n\n```python\n>>> timefhuman('3p-4p') # time range\n(datetime.datetime(2018, 7, 17, 15, 0), datetime.datetime(2018, 7, 17, 16, 0))\n\n>>> timefhuman('7/17 4PM to 7/17 5PM') # range of datetimes\n(datetime.datetime(2018, 7, 17, 16, 0), datetime.datetime(2018, 7, 17, 17, 0))\n\n>>> timefhuman('Monday 3 pm or Tu noon') # list of datetimes\n[datetime.datetime(2018, 8, 6, 15, 0), datetime.datetime(2018, 8, 7, 12, 0)]\n\n>>> timefhuman('7/17 4-5 or 5-6 PM') # list of ranges of datetimes!\n[(datetime.datetime(2018, 7, 17, 16, 0), datetime.datetime(2018, 7, 17, 17, 0)),\n (datetime.datetime(2018, 7, 17, 17, 0), datetime.datetime(2018, 7, 17, 18, 0))]\n```\n\nDurations are also supported.\n\n```python\n>>> timefhuman('30 minutes') # duration\ndatetime.timedelta(seconds=1800)\n\n>>> timefhuman('30-40 mins') # range of durations\n(datetime.timedelta(seconds=1800), datetime.timedelta(seconds=2400))\n\n>>> timefhuman('30 or 40m') # list of durations\n[datetime.timedelta(seconds=1800), datetime.timedelta(seconds=2400)]\n```\n\nWhen possible, timefhuman will infer any missing information, using context from other datetimes.\n\n```python\n>>> timefhuman('3-4p') # infer \"PM\" for \"3\"\n(datetime.datetime(2018, 7, 17, 15, 0), datetime.datetime(2018, 7, 17, 16, 0))\n\n>>> timefhuman('7/17 4 or 5 PM') # infer \"PM\" for \"4\" and infer \"7/17\" for \"5 PM\"\n[datetime.datetime(2018, 7, 17, 16, 0), datetime.datetime(2018, 7, 17, 17, 0)]\n\n>>> timefhuman('7/17, 7/18, 7/19 at 9') # infer \"9a\" for \"7/17\", \"7/18\"\n[datetime.datetime(2018, 7, 17, 9, 0), datetime.datetime(2018, 7, 18, 9, 0),\n datetime.datetime(2018, 7, 19, 9, 0)]\n\n>>> timefhuman('3p -4p PDT') # infer timezone \"PDT\" for \"3p\"\n(datetime.datetime(2018, 8, 4, 15, 0, tzinfo=pytz.timezone('US/Pacific')),\n datetime.datetime(2018, 8, 4, 16, 0, tzinfo=pytz.timezone('US/Pacific')))\n```\n\nYou can also use natural language descriptions of dates and times.\n\n```python\n>>> timefhuman('next Monday')\ndatetime.datetime(2018, 8, 6, 0, 0)\n\n>>> timefhuman('next next Monday')\ndatetime.datetime(2018, 8, 13, 0, 0)\n\n>>> timefhuman('last Wednesday of December')\ndatetime.datetime(2018, 12, 26, 0, 0)\n\n>>> timefhuman('afternoon')\ndatetime.datetime(2018, 8, 4, 15, 0)\n```\n\nSee more examples in [`tests/test_e2e.py`](tests/test_e2e.py).\n\n## Advanced Usage\n\nFor more configuration options, simply create a `tfhConfig` object.\n\n```python\nfrom timefhuman import tfhConfig\nconfig = tfhConfig()\n```\n\n**Return matched text**: You can additionally grab the matched text from the input string. This is useful for modifying the input string, for example.\n\n```python\n>>> config = tfhConfig(return_matched_text=True)\n\n>>> timefhuman('We could maybe do 3 PM, if you still have time', config=config)\n[('3 PM', datetime.datetime(2018, 8, 4, 15, 0))]\n```\n\n**Change 'Now'**: You can configure the default date that timefhuman uses to fill in missing information. This would be useful if you're extracting dates from an email sent a year ago.\n\n```python\n>>> config = tfhConfig(now=datetime.datetime(2018, 8, 4, 0, 0))\n\n>>> timefhuman('upcoming Monday noon', config=config)\ndatetime.datetime(2018, 8, 6, 12, 0)\n```\n\nYou can also set a default timezone, by again using the config's `now`.\n\n```python\n>>> config = tfhConfig(\n... now=datetime.datetime(2018, 8, 4), tzinfo=pytz.timezone('US/Pacific'))\n\n>>> timefhuman('Wed', config=config)\ndatetime.datetime(2018, 8, 8, 0, 0, tzinfo=pytz.timezone('US/Pacific'))\n\n>>> timefhuman('Wed EST', config=config) # EST timezone in the input takes precedence\ndatetime.datetime(2018, 8, 8, 0, 0, tzinfo=pytz.timezone('US/Michigan'))\n```\n\n**Use explicit information only**: Say you only want to extract *dates* OR *times*. You don't want the library to infer information. You can disable most inference by setting `infer_datetimes=False`. Instead of always returning a datetime, timefhuman will be able to return date or time objects, depending on what's provided.\n\n```python\n>>> config = tfhConfig(infer_datetimes=False)\n\n>>> timefhuman('3 PM', config=config)\ndatetime.time(15, 0)\n\n>>> timefhuman('12/18/18', config=config)\ndatetime.date(2018, 12, 18)\n```\n\n**Past datetimes**: By default, datetimes are assumed to occur in the future, so if \"3pm\" today has already passed, the returned datetime will be for *tomorrow*. However, if datetimes are assumed to have occurred in the past (e.g., from an old letter, talking about past events), you can configure the direction.\n\n```python\n>>> from timefhuman import Direction\n>>> config = tfhConfig(direction=Direction.previous)\n\n>>> timefhuman('3PM') # the default\ndatetime.datetime(2018, 8, 5, 15, 0)\n\n>>> timefhuman('3PM', config=config) # changing direction\ndatetime.datetime(2018, 8, 4, 15, 0)\n```\n\nHere is the full set of supported configuration options:\n\n```python\n@dataclass\nclass tfhConfig:\n # Default to the next valid datetime or the previous one\n direction: Direction = Direction.next\n \n # Always return datetime objects. If no date, use now.date(). If no time, use midnight.\n infer_datetimes: bool = True\n \n # The 'current' datetime, used if infer_datetimes is True. Defaults to datetime.now().\n now: datetime | None = None\n \n # Return the matched text from the input string\n return_matched_text: bool = False\n \n # Return a single object instead of a list when there's only one match\n return_single_object: bool = True\n```\n\n## Development\n\nInstall the development version.\n\n```shell\n$ pip install .e .[test] # for bash\n$ pip install -e .\\[test\\] # for zsh\n```\n\nTo run tests and simultaneously generate a coverage report, use the following commands:\n\n```shell\n$ py.test --cov\n$ coverage html\n$ open htmlcov/index.html\n```\n",
"bugtrack_url": null,
"license": "Apache 2.0",
"summary": "Extract datetimes, datetime ranges, and datetime lists from natural language text",
"version": "0.1.2",
"project_urls": {
"Download": "https://github.com/alvinwan/timefhuman/archive/0.1.2.zip",
"Homepage": "https://github.com/alvinwan/timefhuman"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "f24c6c851ada7009d8d867929c0bd6be274529d7e60f31400c7af0c3624f426c",
"md5": "fbc85e6e3a8c458060f3ff8b4b09066d",
"sha256": "9d6c0d3d496088b5c802edbe27a80572d4b5baab378b8aa70f7c16aad20ce92e"
},
"downloads": -1,
"filename": "timefhuman-0.1.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "fbc85e6e3a8c458060f3ff8b4b09066d",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 17418,
"upload_time": "2025-02-09T23:39:29",
"upload_time_iso_8601": "2025-02-09T23:39:29.278351Z",
"url": "https://files.pythonhosted.org/packages/f2/4c/6c851ada7009d8d867929c0bd6be274529d7e60f31400c7af0c3624f426c/timefhuman-0.1.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "9a3de9d9eb252a80dd47d87d829a068958221ca26cd210df6f989c4eecfcac8e",
"md5": "ee30fff265b2e7a95ff2402e9d556411",
"sha256": "df007defbd7b5bda96e77708e94a0f557230b80e674fa3be7a81a3da4ad08eee"
},
"downloads": -1,
"filename": "timefhuman-0.1.2.tar.gz",
"has_sig": false,
"md5_digest": "ee30fff265b2e7a95ff2402e9d556411",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 21137,
"upload_time": "2025-02-09T23:39:30",
"upload_time_iso_8601": "2025-02-09T23:39:30.535909Z",
"url": "https://files.pythonhosted.org/packages/9a/3d/e9d9eb252a80dd47d87d829a068958221ca26cd210df6f989c4eecfcac8e/timefhuman-0.1.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-02-09 23:39:30",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "alvinwan",
"github_project": "timefhuman",
"travis_ci": false,
"coveralls": true,
"github_actions": false,
"lcname": "timefhuman"
}