# More Times!
Assume time forms an algebraic field over GMT. Finally!
[![PyPI Latest Release](https://img.shields.io/pypi/v/mo-times.svg)](https://pypi.org/project/mo-times/)
[![Build Status](https://github.com/klahnakoski/mo-times/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/klahnakoski/mo-times/actions/workflows/build.yml)
[![Coverage Status](https://coveralls.io/repos/github/klahnakoski/mo-times/badge.svg?branch=dev)](https://coveralls.io/github/klahnakoski/mo-times?branch=dev)
[![Downloads](https://pepy.tech/badge/mo-times)](https://pepy.tech/project/mo-times)
## Details
`Date` is a simplified class for time manipulation. This library is intended for personal and business applications where assuming every solar day has 24 * 60 * 60 seconds is considered accurate. [See *GMT vs UTC* below](//#GMT%20vs%20UTC).
### Assumptions
* **All time is in GMT** - Timezone math is left to be resolved at the human endpoints: Machines should only be dealing with one type of time; without holes, without overlap, and with minimal context.
* **Single time type** - There is no distinction between dates, datetime and times; all measurements in the time dimension are handled by one type called `Date`. This is important for treating time as a vector space.
* **Standard range comparision** - All time range comparisons have been standardized to `min <= value < max`. The minimum is inclusive (`<=`), and the maximum is exclusive (`<`).
## `Date` class
The `Date()` method will convert unix timestamps, millisecond timestamps, various string formats and simple time formulas to create a GMT time
### `Date.now()`
Return `Date` instance with millisecond resolution (in GMT).
### `Date.eod()`
Return end-of-day: Smallest `Date` which is greater than all time points in today. Think of it as tomorrow. Same as `now().ceiling(DAY)`
### `Date.today()`
The beginning of today. Same as `now().floor(DAY)`
### Date.range(min, max, interval)
Return an explicit list of `Dates` starting with `min`, each `interval` more than the last, but now including `max`. Used in defining partitions in time domains.
### `floor(duration=None)`
This method is usually used to perform date comparisons at the given resolution (aka `duration`). Round down to the nearest whole duration. `duration` as assumed to be `DAY` if not provided.
### `format(format="%Y-%m-%d %H:%M:%S")`
Just like `strftime`
### `milli`
Number of milliseconds since epoch
### `unix`
Number of seconds since epoch
### `add(duration)`
Add a `duration` to the time to get a new `Date` instance. The `self` is not modified.
### `addDay()`
Convenience method for `self.add(DAY)`
## `Duration` class
Represents the difference between two `Dates`. There are two scales:
* **`DAY` scale** - includes seconds, minutes, hours, days and weeks.
* **`YEAR` scale** - includes months, quarters, years, and centuries.
### `floor(interval=None)`
Round down to nearest `interval` size.
### `seconds`
return total number of seconds (including partial) in this duration (estimate given for `YEAR` scale)
### `total_seconds()`
Same as the `seconds` property
### `round(interval, decimal=0)`
Return number of given `interval` rounded to given `decimal` places
### `format(interval, decimal=0)`
Return a string representing `self` using given `interval` and `decimal` rounding
# Time as an algebraic field
The `Date` and `Duration` objects are the point and vectors in a one dimensional vector space. As such, the `+` and `-` operators are allowed. Comparisons with (`>`, `>=`, `<=`, `<`) are also supported.
## GMT vs UTC
The solar day is he most popular timekeeping unit. This library chose GMT (UT1) for its base clock because of its consistent seconds in a solar day. UTC suffers from inconsistent leap seconds and makes time-math difficult, even while forcing us to make pedantic conclusions like some minutes do not have 60 seconds. Lucky for us Python's implementation of UTC (`datetime.utcnow()`) is wrong, and implements GMT: Which is what we use.
## Error Analysis
Assuming we need a generous leap second each 6 months (the past decade saw only 4 leap seconds), then GMT deviates from UTC by up to 1 seconds over 181 days (December to June, 15,638,400 seconds) which is an error rate `error = 1/15,638,400 = 0.000006395%`. If we want to call the error "noise", we have a 70dB signal/noise ratio. All applications that can tolerate this level of error should use GMT as their time basis.
Raw data
{
"_id": null,
"home_page": "https://github.com/klahnakoski/mo-times",
"name": "mo-times",
"maintainer": null,
"docs_url": null,
"requires_python": null,
"maintainer_email": null,
"keywords": null,
"author": "Kyle Lahnakoski",
"author_email": "kyle@lahnakoski.com",
"download_url": "https://files.pythonhosted.org/packages/fa/29/efd099ec7f49aa3e8b51629d6fa9433a77e41d437c1bfc5223186122c57e/mo_times-5.632.24139.tar.gz",
"platform": null,
"description": "# More Times!\r\n\r\nAssume time forms an algebraic field over GMT. Finally! \r\n\r\n[![PyPI Latest Release](https://img.shields.io/pypi/v/mo-times.svg)](https://pypi.org/project/mo-times/)\r\n [![Build Status](https://github.com/klahnakoski/mo-times/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/klahnakoski/mo-times/actions/workflows/build.yml)\r\n [![Coverage Status](https://coveralls.io/repos/github/klahnakoski/mo-times/badge.svg?branch=dev)](https://coveralls.io/github/klahnakoski/mo-times?branch=dev)\r\n[![Downloads](https://pepy.tech/badge/mo-times)](https://pepy.tech/project/mo-times)\r\n\r\n\r\n## Details \r\n\r\n`Date` is a simplified class for time manipulation. This library is intended for personal and business applications where assuming every solar day has 24 * 60 * 60 seconds is considered accurate. [See *GMT vs UTC* below](//#GMT%20vs%20UTC).\r\n\r\n\r\n### Assumptions\r\n\r\n* **All time is in GMT** - Timezone math is left to be resolved at the human endpoints: Machines should only be dealing with one type of time; without holes, without overlap, and with minimal context.\r\n* **Single time type** - There is no distinction between dates, datetime and times; all measurements in the time dimension are handled by one type called `Date`. This is important for treating time as a vector space.\r\n* **Standard range comparision** - All time range comparisons have been standardized to `min <= value < max`. The minimum is inclusive (`<=`), and the maximum is exclusive (`<`). \r\n\r\n\r\n## `Date` class \r\n\r\nThe `Date()` method will convert unix timestamps, millisecond timestamps, various string formats and simple time formulas to create a GMT time\r\n\r\n### `Date.now()`\r\n\r\nReturn `Date` instance with millisecond resolution (in GMT).\r\n\r\n### `Date.eod()` \r\n\r\nReturn end-of-day: Smallest `Date` which is greater than all time points in today. Think of it as tomorrow. Same as `now().ceiling(DAY)`\r\n\r\n### `Date.today()`\r\n\r\nThe beginning of today. Same as `now().floor(DAY)`\r\n\r\n### Date.range(min, max, interval)\r\n\r\nReturn an explicit list of `Dates` starting with `min`, each `interval` more than the last, but now including `max`. Used in defining partitions in time domains.\r\n\r\n### `floor(duration=None)`\r\n\r\nThis method is usually used to perform date comparisons at the given resolution (aka `duration`). Round down to the nearest whole duration. `duration` as assumed to be `DAY` if not provided.\r\n\r\n### `format(format=\"%Y-%m-%d %H:%M:%S\")`\r\n\r\nJust like `strftime`\r\n\r\n### `milli`\r\n\r\nNumber of milliseconds since epoch\r\n\r\n### `unix`\r\n\r\nNumber of seconds since epoch\r\n\r\n\r\n### `add(duration)`\r\n\r\nAdd a `duration` to the time to get a new `Date` instance. The `self` is not modified.\r\n\r\n### `addDay()`\r\n\r\nConvenience method for `self.add(DAY)`\r\n\r\n\r\n## `Duration` class\r\n\r\nRepresents the difference between two `Dates`. There are two scales:\r\n\r\n* **`DAY` scale** - includes seconds, minutes, hours, days and weeks.\r\n* **`YEAR` scale** - includes months, quarters, years, and centuries.\r\n\r\n### `floor(interval=None)`\r\n\r\nRound down to nearest `interval` size.\r\n\r\n### `seconds` \r\n\r\nreturn total number of seconds (including partial) in this duration (estimate given for `YEAR` scale)\r\n\r\n### `total_seconds()`\r\n\r\nSame as the `seconds` property\r\n\r\n### `round(interval, decimal=0)`\r\n\r\nReturn number of given `interval` rounded to given `decimal` places\r\n\r\n### `format(interval, decimal=0)`\r\n\r\nReturn a string representing `self` using given `interval` and `decimal` rounding\r\n\r\n\r\n# Time as an algebraic field\r\n\r\nThe `Date` and `Duration` objects are the point and vectors in a one dimensional vector space. As such, the `+` and `-` operators are allowed. Comparisons with (`>`, `>=`, `<=`, `<`) are also supported.\r\n\r\n\r\n## GMT vs UTC\r\n\r\nThe solar day is he most popular timekeeping unit. This library chose GMT (UT1) for its base clock because of its consistent seconds in a solar day. UTC suffers from inconsistent leap seconds and makes time-math difficult, even while forcing us to make pedantic conclusions like some minutes do not have 60 seconds. Lucky for us Python's implementation of UTC (`datetime.utcnow()`) is wrong, and implements GMT: Which is what we use.\r\n\r\n## Error Analysis\r\n\r\nAssuming we need a generous leap second each 6 months (the past decade saw only 4 leap seconds), then GMT deviates from UTC by up to 1 seconds over 181 days (December to June, 15,638,400 seconds) which is an error rate `error = 1/15,638,400 = 0.000006395%`. If we want to call the error \"noise\", we have a 70dB signal/noise ratio. All applications that can tolerate this level of error should use GMT as their time basis.\r\n\r\n\r\n",
"bugtrack_url": null,
"license": "MPL 2.0",
"summary": "More Time! Time as a vector space, the way it was meant to be.",
"version": "5.632.24139",
"project_urls": {
"Homepage": "https://github.com/klahnakoski/mo-times"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "3d8c5986e22c31f24bb93dc05a0e723b93c4a8e0301e4f08a1e342127d4dffa6",
"md5": "f477ef1a6b05e3da28ac22a216a9cc01",
"sha256": "9ab4d96fd6d2fd5fa417db2de2322ee7c353590cfebc9b1dc73fe9a79a8961e1"
},
"downloads": -1,
"filename": "mo_times-5.632.24139-py3-none-any.whl",
"has_sig": false,
"md5_digest": "f477ef1a6b05e3da28ac22a216a9cc01",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 18293,
"upload_time": "2024-05-18T03:39:45",
"upload_time_iso_8601": "2024-05-18T03:39:45.455347Z",
"url": "https://files.pythonhosted.org/packages/3d/8c/5986e22c31f24bb93dc05a0e723b93c4a8e0301e4f08a1e342127d4dffa6/mo_times-5.632.24139-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "fa29efd099ec7f49aa3e8b51629d6fa9433a77e41d437c1bfc5223186122c57e",
"md5": "501a754cdb6a152f242cdc2d279dcb75",
"sha256": "ec1e1d0d6879e8cb6c580306a65ffeca65ae624633b31ddb8107222562ac01d4"
},
"downloads": -1,
"filename": "mo_times-5.632.24139.tar.gz",
"has_sig": false,
"md5_digest": "501a754cdb6a152f242cdc2d279dcb75",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 19361,
"upload_time": "2024-05-18T03:39:47",
"upload_time_iso_8601": "2024-05-18T03:39:47.116885Z",
"url": "https://files.pythonhosted.org/packages/fa/29/efd099ec7f49aa3e8b51629d6fa9433a77e41d437c1bfc5223186122c57e/mo_times-5.632.24139.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-05-18 03:39:47",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "klahnakoski",
"github_project": "mo-times",
"travis_ci": false,
"coveralls": true,
"github_actions": true,
"lcname": "mo-times"
}