fly-hour-timer 1.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ """fly_hour_timer - a timezone-free time library: <hour>.<min_sec>"""
2
+
3
+ from .fly_hour_timer import FlyHourTimer
4
+
5
+ #: The static tool (alias of the :class:`FlyHourTimer` class). Call the methods
6
+ #: directly, e.g. ``fly_hour_timer.hour_timer()``.
7
+ fly_hour_timer = FlyHourTimer
8
+
9
+ __all__ = ["FlyHourTimer", "fly_hour_timer"]
10
+ __version__ = "0.3.0"
@@ -0,0 +1,157 @@
1
+ """Core static utility of the fly_hour_timer library.
2
+
3
+ Time representation: <hour>.<min_sec>
4
+
5
+ The "hour" is simply ``unix_time // 3600`` -- the number of whole hours elapsed
6
+ since the unix epoch. ``<min_sec>`` is the minutes and seconds inside that
7
+ hour. Because everything is derived directly from the absolute unix time, the
8
+ string is fully timezone-free and identical on any machine anywhere.
9
+ """
10
+
11
+ import time as _time
12
+ from datetime import datetime, timezone as dt_timezone
13
+
14
+ __all__ = ["FlyHourTimer"]
15
+
16
+
17
+ class FlyHourTimer:
18
+ """Static time tool: represents time as ``<hour>.<min_sec>``.
19
+
20
+ All methods are static; no instance is required.
21
+
22
+ >>> FlyHourTimer.hour_timer(1_000_000_000) # 2001-09-09 01:46:40 UTC
23
+ '277777.4640'
24
+ >>> FlyHourTimer.hour_timer_short(1_000_000_000)
25
+ '777.4640'
26
+ >>> FlyHourTimer.hour_timer(0) # the epoch
27
+ '0.0000'
28
+ """
29
+
30
+ # ------------------------------------------------------------------
31
+ # public API
32
+ # ------------------------------------------------------------------
33
+
34
+ @staticmethod
35
+ def hour(unix_time=None):
36
+ """Return the hour: whole hours elapsed since the unix epoch.
37
+
38
+ Equivalent to ``unix_time // 3600``.
39
+
40
+ Args:
41
+ unix_time: unix time in seconds (int/float/numeric str).
42
+ Defaults to the current time when omitted.
43
+
44
+ Returns:
45
+ str: e.g. ``'277777'``.
46
+ """
47
+ hours, _, _ = FlyHourTimer._split(unix_time)
48
+ return str(hours)
49
+
50
+ @staticmethod
51
+ def min_sec(unix_time=None):
52
+ """Return the ``<min_sec>`` part: minutes and seconds inside the hour.
53
+
54
+ Args:
55
+ unix_time: unix time in seconds, defaults to the current time.
56
+
57
+ Returns:
58
+ str: 4 digits ``MMSS``, e.g. ``'0102'`` means 01 min 02 sec.
59
+ """
60
+ _, minute, second = FlyHourTimer._split(unix_time)
61
+ return f"{minute:02d}{second:02d}"
62
+
63
+ @staticmethod
64
+ def hour_timer(unix_time=None):
65
+ """Return time as ``<hour>.<min_sec>``, where hour = ``unix_time // 3600``.
66
+
67
+ Args:
68
+ unix_time: unix time in seconds, defaults to the current time.
69
+
70
+ Returns:
71
+ str: e.g. ``'277777.4640'``.
72
+ """
73
+ hours, minute, second = FlyHourTimer._split(unix_time)
74
+ return f"{hours}.{minute:02d}{second:02d}"
75
+
76
+ @staticmethod
77
+ def hour_timer_short(unix_time=None):
78
+ """Return time as ``<last 3 digits of hour>.<min_sec>``.
79
+
80
+ The last 3 digits of the hour roll over roughly every 1000 hours
81
+ (~41.7 days), giving a compact, timezone-free time id for logs and
82
+ bot conversations.
83
+
84
+ Args:
85
+ unix_time: unix time in seconds, defaults to the current time.
86
+
87
+ Returns:
88
+ str: e.g. hour ``277777`` -> ``'777.4640'``.
89
+ """
90
+ hours, minute, second = FlyHourTimer._split(unix_time)
91
+ return f"{hours % 1000:03d}.{minute:02d}{second:02d}"
92
+
93
+ @staticmethod
94
+ def hour_timer_to_time(hour_timer):
95
+ """Convert a ``<hour>.<min_sec>`` string into a ``time.struct_time``.
96
+
97
+ Because ``<hour>`` already encodes the total elapsed hours since the
98
+ epoch (and therefore the date), this is a complete, timezone-free
99
+ inverse of :meth:`hour_timer` -- no "today" anchor is needed. The
100
+ result is UTC based (``time.gmtime``).
101
+
102
+ Args:
103
+ hour_timer: the ``<hour>.<min_sec>`` string, e.g.
104
+ ``'277777.4640'``.
105
+
106
+ Returns:
107
+ time.struct_time: UTC struct_time reconstructed from the string.
108
+
109
+ Raises:
110
+ ValueError: if ``hour_timer`` is malformed or out of range.
111
+ """
112
+ hours, minute, second = FlyHourTimer._parse_hour_timer(hour_timer)
113
+ unix_time = hours * 3600 + minute * 60 + second
114
+ return _time.gmtime(unix_time)
115
+
116
+ # ------------------------------------------------------------------
117
+ # internals
118
+ # ------------------------------------------------------------------
119
+
120
+ @staticmethod
121
+ def _split(unix_time):
122
+ """Split a unix time into (total_hours, minute, second)."""
123
+ if unix_time is None:
124
+ ts = datetime.now(dt_timezone.utc).timestamp()
125
+ else:
126
+ ts = float(unix_time)
127
+ hours = int(ts // 3600)
128
+ rem = ts - hours * 3600 # seconds inside the hour, always in [0, 3600)
129
+ minute = int(rem // 60)
130
+ second = int(rem % 60)
131
+ return hours, minute, second
132
+
133
+ @staticmethod
134
+ def _parse_hour_timer(hour_timer):
135
+ """Parse ``'<hour>.<min_sec>'`` into (total_hours, minute, second)."""
136
+ if not isinstance(hour_timer, str):
137
+ raise ValueError(f"hour_timer must be a str, got {hour_timer!r}")
138
+ text = hour_timer.strip()
139
+ if text.count(".") != 1:
140
+ raise ValueError(
141
+ f"hour_timer must look like '<hour>.<min_sec>', got {hour_timer!r}"
142
+ )
143
+ hour_part, min_sec_part = text.split(".", 1)
144
+ if not min_sec_part.isdigit() or len(min_sec_part) != 4:
145
+ raise ValueError(
146
+ f"hour_timer '<min_sec>' must be 4 digits, got {hour_timer!r}"
147
+ )
148
+ try:
149
+ hours = int(hour_part)
150
+ except ValueError:
151
+ raise ValueError(
152
+ f"hour_timer '<hour>' must be an integer, got {hour_timer!r}"
153
+ ) from None
154
+ minute, second = int(min_sec_part[:2]), int(min_sec_part[2:])
155
+ if not (0 <= minute <= 59 and 0 <= second <= 59):
156
+ raise ValueError(f"hour_timer '<min_sec>' out of range, got {hour_timer!r}")
157
+ return hours, minute, second
@@ -0,0 +1,147 @@
1
+ Metadata-Version: 2.4
2
+ Name: fly_hour_timer
3
+ Version: 1.1.2
4
+ Summary: A timezone-free Python time library: represents time as <hour>.<min_sec>
5
+ Author: fly
6
+ License: MIT
7
+ Keywords: time,timezone-free,hour-timer,ai-bot,unix-time
8
+ Classifier: Development Status :: 5 - Production/Stable
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
14
+ Classifier: Topic :: Utilities
15
+ Requires-Python: >=3.8
16
+ Description-Content-Type: text/markdown
17
+
18
+ # fly_hour_timer
19
+
20
+ **English** | [简体中文](README_zh.md)
21
+
22
+ A timezone-free Python time library that represents time as **`<hour>.<min_sec>`**.
23
+
24
+ The core idea: express time as `<hour>.<min_sec>`, where the **hour is simply
25
+ `unix_time // 3600`** (whole hours elapsed since the unix epoch) and `<min_sec>`
26
+ is the minutes and seconds inside that hour. Because everything is derived
27
+ directly from the absolute unix time, the string is fully timezone-free and
28
+ identical on any machine anywhere — especially friendly for AI bots that
29
+ exchange timestamps across regions.
30
+
31
+ - No third-party dependency, pure standard library (`datetime` / `time` only)
32
+ - Fully timezone-free by construction
33
+ - Python >= 3.8
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ pip install fly_hour_timer
39
+ ```
40
+
41
+ Or from source:
42
+
43
+ ```bash
44
+ git clone https://github.com/<your-name>/fly_hour_timer.git
45
+ cd fly_hour_timer
46
+ pip install .
47
+ ```
48
+
49
+ ## Quick Start
50
+
51
+ `fly_hour_timer` is a static tool — no instance configuration required:
52
+
53
+ ```python
54
+ from fly_hour_timer import fly_hour_timer
55
+
56
+ fly_hour_timer.hour() # '277777' -> hour (unix_time // 3600), str
57
+ fly_hour_timer.min_sec() # '4640' -> minutes + seconds, str
58
+ fly_hour_timer.hour_timer() # '277777.4640' -> <hour>.<min_sec>
59
+ fly_hour_timer.hour_timer_short() # '777.4640' -> <last 3 digits of hour>.<min_sec>
60
+ ```
61
+
62
+ With an explicit unix time (seconds):
63
+
64
+ ```python
65
+ from fly_hour_timer import FlyHourTimer
66
+
67
+ FlyHourTimer.hour_timer(1_000_000_000) # '277777.4640'
68
+ FlyHourTimer.hour_timer_short(1_000_000_000) # '777.4640'
69
+ ```
70
+
71
+ ## API
72
+
73
+ | Method | Description | Returns |
74
+ | --- | --- | --- |
75
+ | `hour(unix_time=None)` | Whole hours since the epoch, `unix_time // 3600` | `str` |
76
+ | `min_sec(unix_time=None)` | Minutes + seconds inside the hour, 4 digits (`'0102'` = 01m02s) | `str` |
77
+ | `hour_timer(unix_time=None)` | `<hour>.<min_sec>` | `str` |
78
+ | `hour_timer_short(unix_time=None)` | `<last 3 digits of hour>.<min_sec>` | `str` |
79
+ | `hour_timer_to_time(hour_timer)` | Parse `<hour>.<min_sec>` back into a UTC `time.struct_time` | `time.struct_time` |
80
+
81
+ ### Parameters
82
+
83
+ - **`unix_time`** — unix time in seconds (`int` / `float` / numeric `str`).
84
+ Omit to use the current time.
85
+
86
+ ## How it works
87
+
88
+ Given a unix time in seconds:
89
+
90
+ ```
91
+ hour = unix_time // 3600 # whole hours since the epoch
92
+ rem = unix_time - hour * 3600 # seconds left inside the hour (0..3599)
93
+ min_sec = "%02d%02d" % (rem // 60, rem % 60)
94
+ ```
95
+
96
+ - `hour_timer()` -> `f"{hour}.{min_sec}"`
97
+ - `hour_timer_short()` -> `f"{hour % 1000:03d}.{min_sec}"` — the last 3 digits
98
+ of the hour roll over roughly every 1000 hours (~41.7 days), giving a compact,
99
+ timezone-free time id for logs and bot conversations.
100
+
101
+ No timezone parameter is needed: the hour count and the leftover minutes/seconds
102
+ come straight from the absolute unix time, so the result is the same everywhere.
103
+
104
+ ## Reverse Conversion: `hour_timer_to_time()`
105
+
106
+ Since `<hour>` already encodes the total elapsed hours since the epoch (and thus
107
+ the full date), the conversion back is complete and needs no "today" anchor. It
108
+ returns a UTC `time.struct_time`:
109
+
110
+ ```python
111
+ from fly_hour_timer import FlyHourTimer
112
+
113
+ st = FlyHourTimer.hour_timer_to_time("277777.4640")
114
+ # time.struct_time(... 2001, 9, 9, 1, 46, 40 ...)
115
+ st.tm_hour, st.tm_min, st.tm_sec # (1, 46, 40)
116
+ ```
117
+
118
+ It is the exact inverse of `hour_timer()` for the clock fields, and raises
119
+ `ValueError` on malformed or out-of-range input (e.g. minutes `>= 60`).
120
+
121
+ > Note: pass the **full** `hour_timer()` string here. A short string like
122
+ > `'777.4640'` (from `hour_timer_short()`) has lost the high-order hour digits,
123
+ > so it reconstructs a different (much earlier) instant.
124
+
125
+ ## Examples
126
+
127
+ ```python
128
+ >>> from fly_hour_timer import FlyHourTimer
129
+ >>> FlyHourTimer.hour_timer(0)
130
+ '0.0000'
131
+ >>> FlyHourTimer.hour_timer(1_000_000_000)
132
+ '277777.4640'
133
+ >>> FlyHourTimer.hour_timer_short(1_000_000_000)
134
+ '777.4640'
135
+ ```
136
+
137
+ Run `python examples.py` in this repository for a live demo.
138
+
139
+ ## Tests
140
+
141
+ ```bash
142
+ python tests/test_fly_hour_timer.py
143
+ ```
144
+
145
+ ## License
146
+
147
+ MIT
@@ -0,0 +1,6 @@
1
+ fly_hour_timer/__init__.py,sha256=rWgT2xQFUWC4kQJFGlz5tK8Y4hlhFkwrur8DlDbyJS4,352
2
+ fly_hour_timer/fly_hour_timer.py,sha256=XIOMrmSSDGEq4m2MKbr1S1jE31Z_n4__IhsQmpV-mj0,5779
3
+ fly_hour_timer-1.1.2.dist-info/METADATA,sha256=_h5zQ8ssbdnBnH6dua0twqbwd24F6QlafSd_Ll1O6gM,4836
4
+ fly_hour_timer-1.1.2.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
5
+ fly_hour_timer-1.1.2.dist-info/top_level.txt,sha256=mQA8VEQL6M4lIrgxX3pVW4C98ORt9LiKedvGwKNAzuY,15
6
+ fly_hour_timer-1.1.2.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ fly_hour_timer