Metadata-Version: 2.5
Name: clock-pattern
Version: 0.9.0
Summary: The Clock Pattern is a Python package that turns time into an injectable dependency.
Project-URL: Homepage, https://github.com/adriamontoto/clock-pattern
Project-URL: Repository, https://github.com/adriamontoto/clock-pattern
Project-URL: Issues, https://github.com/adriamontoto/clock-pattern/issues
Author: Adria Montoto
License-Expression: MIT
License-File: LICENSE.md
Keywords: clock,dependency-injection,development,domain-driven-design,pattern,python,utilities
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: value-object-pattern>=1.31.0
Description-Content-Type: text/markdown

<a name="readme-top"></a>

# 🕰️ Clock Pattern

<p align="center">
    <a href="https://github.com/adriamontoto/clock-pattern/actions/workflows/ci.yaml?event=push&branch=master" target="_blank">
        <img src="https://github.com/adriamontoto/clock-pattern/actions/workflows/ci.yaml/badge.svg?event=push&branch=master" alt="CI Pipeline">
    </a>
    <a href="https://coverage-badge.samuelcolvin.workers.dev/redirect/adriamontoto/clock-pattern" target="_blank">
        <img src="https://coverage-badge.samuelcolvin.workers.dev/adriamontoto/clock-pattern.svg" alt="Coverage Pipeline">
    </a>
    <a href="https://pypi.org/project/clock-pattern" target="_blank">
        <img src="https://img.shields.io/pypi/v/clock-pattern?color=%2334D058&label=pypi%20package" alt="Package Version">
    </a>
    <a href="https://pypi.org/project/clock-pattern/" target="_blank">
        <img src="https://img.shields.io/pypi/pyversions/clock-pattern.svg?color=%2334D058" alt="Supported Python Versions">
    </a>
    <a href="https://pepy.tech/projects/clock-pattern" target="_blank">
        <img src="https://static.pepy.tech/badge/clock-pattern/month" alt="Package Downloads">
    </a>
    <a href="https://deepwiki.com/adriamontoto/clock-pattern" target="_blank">
        <img src="https://img.shields.io/badge/DeepWiki-adriamontoto%2Fclock--pattern-blue.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAyCAYAAAAnWDnqAAAAAXNSR0IArs4c6QAAA05JREFUaEPtmUtyEzEQhtWTQyQLHNak2AB7ZnyXZMEjXMGeK/AIi+QuHrMnbChYY7MIh8g01fJoopFb0uhhEqqcbWTp06/uv1saEDv4O3n3dV60RfP947Mm9/SQc0ICFQgzfc4CYZoTPAswgSJCCUJUnAAoRHOAUOcATwbmVLWdGoH//PB8mnKqScAhsD0kYP3j/Yt5LPQe2KvcXmGvRHcDnpxfL2zOYJ1mFwrryWTz0advv1Ut4CJgf5uhDuDj5eUcAUoahrdY/56ebRWeraTjMt/00Sh3UDtjgHtQNHwcRGOC98BJEAEymycmYcWwOprTgcB6VZ5JK5TAJ+fXGLBm3FDAmn6oPPjR4rKCAoJCal2eAiQp2x0vxTPB3ALO2CRkwmDy5WohzBDwSEFKRwPbknEggCPB/imwrycgxX2NzoMCHhPkDwqYMr9tRcP5qNrMZHkVnOjRMWwLCcr8ohBVb1OMjxLwGCvjTikrsBOiA6fNyCrm8V1rP93iVPpwaE+gO0SsWmPiXB+jikdf6SizrT5qKasx5j8ABbHpFTx+vFXp9EnYQmLx02h1QTTrl6eDqxLnGjporxl3NL3agEvXdT0WmEost648sQOYAeJS9Q7bfUVoMGnjo4AZdUMQku50McDcMWcBPvr0SzbTAFDfvJqwLzgxwATnCgnp4wDl6Aa+Ax283gghmj+vj7feE2KBBRMW3FzOpLOADl0Isb5587h/U4gGvkt5v60Z1VLG8BhYjbzRwyQZemwAd6cCR5/XFWLYZRIMpX39AR0tjaGGiGzLVyhse5C9RKC6ai42ppWPKiBagOvaYk8lO7DajerabOZP46Lby5wKjw1HCRx7p9sVMOWGzb/vA1hwiWc6jm3MvQDTogQkiqIhJV0nBQBTU+3okKCFDy9WwferkHjtxib7t3xIUQtHxnIwtx4mpg26/HfwVNVDb4oI9RHmx5WGelRVlrtiw43zboCLaxv46AZeB3IlTkwouebTr1y2NjSpHz68WNFjHvupy3q8TFn3Hos2IAk4Ju5dCo8B3wP7VPr/FGaKiG+T+v+TQqIrOqMTL1VdWV1DdmcbO8KXBz6esmYWYKPwDL5b5FA1a0hwapHiom0r/cKaoqr+27/XcrS5UwSMbQAAAABJRU5ErkJggg==" alt="Project Documentation">
    </a>
</p>

The **Clock Pattern** is a Python 🐍 package that turns time into an injectable dependency 🧩. Instead of scattering
`datetime.now()` or `date.today()` through application code, domain services depend on a small `Clock` interface. That
keeps time-sensitive logic deterministic in tests, makes timezone choices explicit, and lets production code swap clock
implementations without touching business rules.
<br><br>

## Table of Contents

- [📥 Installation](#installation)
- [📚 Documentation](#documentation)
- [⚡ Quick Start](#quick-start)
- [🧩 Why Inject a Clock?](#why-inject-a-clock)
- [📚 Available Clocks](#available-clocks)
- [🌍 Timezone Behavior](#timezone-behavior)
- [🧪 Testing Time-Sensitive Code](#testing-time-sensitive-code)
- [🎄 Real-Life Case: Christmas Detector Service](#real-life-case-christmas-detector-service)
- [🤝 Contributing](#contributing)
- [🔑 License](#license)

<p align="right">
    <a href="#readme-top">🔼 Back to top</a>
</p><br><br>

<a name="installation"></a>

## 📥 Installation

You can install **Clock Pattern** using `pip`:

```bash
pip install clock-pattern
```

You can install the companion AI-agent skill from [skills.sh](https://www.skills.sh/) with Vercel's `skills` CLI:

```bash
npx skills add adriamontoto/clock-pattern
```

Review the skill source in [`skills/clock-pattern`](skills/clock-pattern) before installing it in sensitive
environments.

<p align="right">
    <a href="#readme-top">🔼 Back to top</a>
</p><br><br>

<a name="documentation"></a>

## 📚 Documentation

The root README is the entry point. Deeper guides live in this repository and are linked here:

- [`docs/README.md`](docs/README.md): Documentation hub.
- [`docs/usage/README.md`](docs/usage/README.md): Core usage patterns and service composition.
- [`docs/timezones/README.md`](docs/timezones/README.md): Timezone behavior, UTC defaults, and date-boundary guidance.
- [`docs/testing/README.md`](docs/testing/README.md): `FixedClock`, `MockClock`, and deterministic test patterns.

This [project's DeepWiki documentation](https://deepwiki.com/adriamontoto/clock-pattern) is also available for generated
repository navigation.

<p align="right">
    <a href="#readme-top">🔼 Back to top</a>
</p><br><br>

<a name="quick-start"></a>

## ⚡ Quick Start

Inject a `Clock` into code that needs the current time. Production code can pass a real clock, while tests can pass a
fixed or mock clock.

```python
from clock_pattern import Clock, UtcClock


class TimestampService:
    def __init__(self, *, clock: Clock) -> None:
        self._clock = clock

    def issued_at(self) -> str:
        return self._clock.now().isoformat()


service = TimestampService(clock=UtcClock())
print(service.issued_at())
```

Use [`SystemClock`](https://github.com/adriamontoto/clock-pattern/blob/master/clock_pattern/clocks/system_clock.py) when
you need a specific timezone:

```python
from clock_pattern import SystemClock

clock = SystemClock(timezone='Europe/Madrid')
print(clock.now())
# >>> 2025-06-16 15:57:26.210964+02:00
```

<p align="right">
    <a href="#readme-top">🔼 Back to top</a>
</p><br><br>

<a name="why-inject-a-clock"></a>

## 🧩 Why Inject a Clock?

Time is global state. Reading it directly from the operating system makes behavior depend on the moment a test happens
to run, the machine timezone, daylight-saving transitions, and the speed of the test suite.

Clock Pattern keeps those decisions explicit:

- Domain code depends on `Clock`, not on Python's global datetime functions.
- Tests can choose exact dates and datetimes without monkeypatching built-in modules.
- Production wiring decides whether the application uses UTC or another timezone.
- Custom clocks can be introduced for logical time, simulation, replay, or high-precision infrastructure.

The package exposes two methods:

| Method | Returns | Typical use |
| --- | --- | --- |
| `now()` | `datetime` | Timestamps, expiration windows, audit fields, elapsed-time calculations. |
| `today()` | `date` | Calendar rules, billing days, holiday checks, date-only decisions. |

<p align="right">
    <a href="#readme-top">🔼 Back to top</a>
</p><br><br>

<a name="available-clocks"></a>

## 📚 Available Clocks

The package offers several clock implementations to suit different needs:

| Clock | Import path | Purpose |
| --- | --- | --- |
| [`Clock`](https://github.com/adriamontoto/clock-pattern/blob/master/clock_pattern/clocks/models/clock.py) | `from clock_pattern import Clock` | Abstract contract for code that needs `now()` or `today()`. |
| [`SystemClock`](https://github.com/adriamontoto/clock-pattern/blob/master/clock_pattern/clocks/system_clock.py) | `from clock_pattern import SystemClock` | Production clock backed by system time in a configured timezone. |
| [`UtcClock`](https://github.com/adriamontoto/clock-pattern/blob/master/clock_pattern/clocks/utc_clock.py) | `from clock_pattern import UtcClock` | Production clock fixed to UTC. |
| `MonotonicClock` | `from clock_pattern import MonotonicClock` | Abstract contract for elapsed-time sources. |
| `SystemMonotonicClock` | `from clock_pattern import SystemMonotonicClock` | Production monotonic clock for elapsed-time measurement. |
| `SystemSleeper` / `SystemSleeperAsync` | `from clock_pattern import SystemSleeper, SystemSleeperAsync` | Injectable sync and async sleeping. |
| `Stopwatch` | `from clock_pattern import Stopwatch` | Measure elapsed seconds with `.start()`, `.end()`, or a context manager. |
| [`FixedClock`](https://github.com/adriamontoto/clock-pattern/blob/master/clock_pattern/clocks/testing/fixed_clock.py) | `from clock_pattern.clocks.testing import FixedClock` | Test clock that always returns the same datetime and derived date. |
| [`MockClock`](https://github.com/adriamontoto/clock-pattern/blob/master/clock_pattern/clocks/testing/mock_clock.py) | `from clock_pattern.clocks.testing import MockClock` | Test clock with prepared return values and call assertions. |

Use the top-level package for production clocks and `clock_pattern.clocks.testing` for test-only clocks.

<p align="right">
    <a href="#readme-top">🔼 Back to top</a>
</p><br><br>

<a name="timezone-behavior"></a>

## 🌍 Timezone Behavior

`SystemClock` accepts either an IANA timezone string or a `tzinfo` instance. It stores the timezone with `ZoneInfo` and
uses it for both `now()` and `today()`.

```python
from datetime import UTC

from clock_pattern import SystemClock

utc_clock = SystemClock(timezone=UTC)
madrid_clock = SystemClock(timezone='Europe/Madrid')

print(utc_clock.timezone)
# >>> UTC
print(madrid_clock.timezone)
# >>> Europe/Madrid
```

`UtcClock` is a convenience clock for the common production choice of UTC.

`today()` is calculated in the clock timezone. Around midnight, `SystemClock(timezone='UTC').today()` and
`SystemClock(timezone='America/New_York').today()` may return different dates. For more details, see
[`docs/timezones/README.md`](docs/timezones/README.md).

<p align="right">
    <a href="#readme-top">🔼 Back to top</a>
</p><br><br>

<a name="testing-time-sensitive-code"></a>

## 🧪 Testing Time-Sensitive Code

Use `FixedClock` when the test only needs a stable instant:

```python
from datetime import datetime

from clock_pattern.clocks.testing import FixedClock

clock = FixedClock(instant=datetime(year=2025, month=1, day=1, hour=10, minute=30))

assert clock.now().isoformat() == '2025-01-01T10:30:00+00:00'
assert clock.today().isoformat() == '2025-01-01'
```

Use `MockClock` when the test also needs to prove that time was requested:

```python
from datetime import date

from clock_pattern.clocks.testing import MockClock

clock = MockClock()
clock.prepare_today_method_return_value(today=date(year=2025, month=1, day=7))

assert clock.today() == date(year=2025, month=1, day=7)
clock.assert_today_method_was_called_once()
clock.assert_now_method_was_not_called()
```

More testing recipes are available in [`docs/testing/README.md`](docs/testing/README.md).

<p align="right">
    <a href="#readme-top">🔼 Back to top</a>
</p><br><br>

<a name="real-life-case-christmas-detector-service"></a>

## 🎄 Real-Life Case: Christmas Detector Service

This service checks whether the current date falls within a Christmas holiday range. The service depends on `Clock`, so
production code can use [`UtcClock`](https://github.com/adriamontoto/clock-pattern/blob/master/clock_pattern/clocks/utc_clock.py)
and tests can use [`MockClock`](https://github.com/adriamontoto/clock-pattern/blob/master/clock_pattern/clocks/testing/mock_clock.py)
without changing the service.

```python
from datetime import date

from clock_pattern import Clock, UtcClock
from clock_pattern.clocks.testing import MockClock


class ChristmasDetectorService:
    def __init__(self, *, clock: Clock) -> None:
        self._clock = clock
        self._christmas_start = date(year=2024, month=12, day=24)
        self._christmas_end = date(year=2025, month=1, day=6)

    def is_christmas(self) -> bool:
        return self._christmas_start <= self._clock.today() <= self._christmas_end


clock = UtcClock()
service = ChristmasDetectorService(clock=clock)

print(service.is_christmas())
# >>> False


def test_christmas_detector_is_christmas() -> None:
    clock = MockClock()
    service = ChristmasDetectorService(clock=clock)

    today = date(year=2024, month=12, day=25)
    clock.prepare_today_method_return_value(today=today)

    assert service.is_christmas() is True
    clock.assert_today_method_was_called_once()


def test_christmas_detector_is_not_christmas() -> None:
    clock = MockClock()
    service = ChristmasDetectorService(clock=clock)

    today = date(year=2025, month=1, day=7)
    clock.prepare_today_method_return_value(today=today)

    assert service.is_christmas() is False
    clock.assert_today_method_was_called_once()
```

<p align="right">
    <a href="#readme-top">🔼 Back to top</a>
</p><br><br>

<a name="contributing"></a>

## 🤝 Contributing

We love community help! Before you open an issue or pull request, please read:

- [`🤝 How to Contribute`](https://github.com/adriamontoto/clock-pattern/blob/master/.github/CONTRIBUTING.md)
- [`🧭 Code of Conduct`](https://github.com/adriamontoto/clock-pattern/blob/master/.github/CODE_OF_CONDUCT.md)
- [`🔐 Security Policy`](https://github.com/adriamontoto/clock-pattern/blob/master/.github/SECURITY.md)

_Thank you for helping make **🕰️ Clock Pattern** package awesome! 🌟_

<p align="right">
    <a href="#readme-top">🔼 Back to top</a>
</p><br><br>

<a name="license"></a>

## 🔑 License

This project is licensed under the terms of the [`MIT license`](https://github.com/adriamontoto/clock-pattern/blob/master/LICENSE.md).

<p align="right">
    <a href="#readme-top">🔼 Back to top</a>
</p>
