# Uuidv7Chrono
Convert between dates/datetimes and UUIDv7 for time-based Ecto database queries.
UUIDv7 encodes a Unix timestamp in its most significant bits, making primary keys naturally time-ordered. This library lets you generate UUIDv7 boundary values from a `Date` or `DateTime`, so you can efficiently filter records by time using simple primary key comparisons — no extra `inserted_at` index needed.
## Installation
Add `uuidv7_chrono` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:uuidv7_chrono, "~> 0.1.0"}
]
end
```
## Usage
### Filter Ecto queries by time
```elixir
yesterday = Date.utc_today() |> Date.add(-1)
# Records created after yesterday
from(u in User, where: u.id > ^Uuidv7Chrono.to_uuid(yesterday))
# Records created before a specific timestamp
cutoff = ~U[2026-01-01 00:00:00Z]
from(o in Order, where: o.id < ^Uuidv7Chrono.to_uuid(cutoff))
```
### Extract timestamps from UUIDv7
```elixir
Uuidv7Chrono.to_datetime("019d2566-fe40-7000-8000-000000000000")
#=> ~U[2026-03-25 14:30:00.000Z]
Uuidv7Chrono.to_date("019d2566-fe40-7000-8000-000000000000")
#=> ~D[2026-03-25]
```
Both `to_datetime/1` and `to_date/1` accept string UUIDs (`"019d2566-fe40-..."`) and raw 16-byte binary UUIDs.
### Database partitioning
If your table is range-partitioned on a UUIDv7 primary key, these boundary values enable partition pruning — the database skips partitions that can't contain matching rows:
```elixir
# Query only hits the Q1 2026 partition
from(o in Order,
where: o.id >= ^Uuidv7Chrono.to_uuid(~D[2026-01-01])
and o.id < ^Uuidv7Chrono.to_uuid(~D[2026-04-01])
)
```
### Postgres-compatible aliases
If you prefer names that mirror the `pg_uuidv7` Postgres extension:
```elixir
Uuidv7Chrono.uuid_generate_v7(~U[2026-03-25 14:30:00Z])
Uuidv7Chrono.uuid_v7_to_timestamptz("019d2566-fe40-7000-8000-000000000000")
```
## API
| Function | Description |
|---|---|
| `to_uuid(Date.t() \| DateTime.t())` | Date/DateTime to UUIDv7 string |
| `to_datetime(String.t() \| binary())` | UUIDv7 to DateTime |
| `to_date(String.t() \| binary())` | UUIDv7 to Date |
| `uuid_generate_v7/1` | Alias for `to_uuid/1` (pg_uuidv7 compat) |
| `uuid_v7_to_timestamptz/1` | Alias for `to_datetime/1` (pg_uuidv7 compat) |
## How it works
`to_uuid/1` encodes the timestamp as the first 48 bits of a UUIDv7 and fills the remaining bits with zeros. This produces the **lowest possible** UUIDv7 for that point in time, making it ideal as a boundary value in range queries.
Zero dependencies. Pure Elixir.
## License
Apache-2.0