Skip to main content

Utility class for working with POSIX timestamps in milliseconds.

Project description

milliseconds

PyPI - Version PyPI - Python Version CI

A lightweight, POSIX-compliant utility library for working with timestamps in milliseconds.


Features

  • Convert between datetime and milliseconds - Easy conversion to/from Python datetime objects
  • Floor and ceil operations - Round timestamps to specific time boundaries (second, minute, hour, day)
  • Boundary navigation - Jump to next/previous time boundaries
  • Validation - Check if timestamps align to specific time units
  • Arithmetic operations - Increment/decrement by seconds, minutes, hours, or days
  • Comparison utilities - Check if timestamps fall within the same time period
  • Full POSIX compliance - Supports negative timestamps (dates before 1970-01-01)
  • Zero dependencies - Only uses Python standard library
  • Type hints - Fully typed for better IDE support

Table of Contents

Installation

pip install milliseconds

Quick Start

from datetime import datetime
from zoneinfo import ZoneInfo
from milliseconds import milliseconds, constants

# Convert datetime to milliseconds
dt = datetime(2024, 1, 1, 12, 30, 45, tzinfo=ZoneInfo("UTC"))
ms = milliseconds.milliseconds(dt)
print(ms)  # 1704113445000

# Convert back to datetime
dt_back = milliseconds.time(ms, ZoneInfo("UTC"))
print(dt_back)  # 2024-01-01 12:30:45+00:00

# Floor to nearest hour
floored = milliseconds.floor(ms, constants.hour)
print(milliseconds.time(floored, ZoneInfo("UTC")))  # 2024-01-01 12:00:00+00:00

# Get next day boundary
next_day = milliseconds.next_day(ms)
print(milliseconds.time(next_day, ZoneInfo("UTC")))  # 2024-01-02 00:00:00+00:00

Usage Examples

Basic Conversion

from datetime import datetime
from zoneinfo import ZoneInfo
from milliseconds import milliseconds

# DateTime to milliseconds
dt = datetime(2024, 6, 15, 14, 30, 0, tzinfo=ZoneInfo("UTC"))
ms = milliseconds.milliseconds(dt)
print(ms)  # 1718460600000

# Milliseconds to datetime
dt_back = milliseconds.time(ms, ZoneInfo("America/New_York"))
print(dt_back)  # 2024-06-15 10:30:00-04:00 (EDT)

Floor and Ceil Operations

from milliseconds import milliseconds, constants

timestamp = 1704113445789  # 2024-01-01 12:30:45.789

# Floor operations (round down)
print(milliseconds.floor(timestamp, constants.second))  # 1704113445000 (12:30:45.000)
print(milliseconds.floor(timestamp, constants.minute))  # 1704113400000 (12:30:00.000)
print(milliseconds.floor(timestamp, constants.hour))    # 1704110400000 (12:00:00.000)
print(milliseconds.floor(timestamp, constants.day))     # 1704067200000 (00:00:00.000)

# Ceil operations (round up)
print(milliseconds.ceil(timestamp, constants.second))   # 1704113446000 (12:30:46.000)
print(milliseconds.ceil(timestamp, constants.minute))   # 1704113460000 (12:31:00.000)
print(milliseconds.ceil(timestamp, constants.hour))     # 1704114000000 (13:00:00.000)

Boundary Navigation

from milliseconds import milliseconds

timestamp = 1704113445789  # 2024-01-01 12:30:45.789

# Navigate to previous boundaries
print(milliseconds.last_second(timestamp))  # Previous second: 12:30:44.000
print(milliseconds.last_minute(timestamp))  # Previous minute: 12:29:00.000
print(milliseconds.last_hour(timestamp))    # Previous hour: 11:00:00.000
print(milliseconds.last_day(timestamp))     # Previous day: 2023-12-31 00:00:00

# Navigate to next boundaries
print(milliseconds.next_second(timestamp))  # Next second: 12:30:46.000
print(milliseconds.next_minute(timestamp))  # Next minute: 12:31:00.000
print(milliseconds.next_hour(timestamp))    # Next hour: 13:00:00.000
print(milliseconds.next_day(timestamp))     # Next day: 2024-01-02 00:00:00

Time Arithmetic

from milliseconds import milliseconds

timestamp = 1704067200000  # 2024-01-01 00:00:00

# Increment operations
plus_30_sec = milliseconds.increment_second(timestamp, 30)
plus_15_min = milliseconds.increment_minute(timestamp, 15)
plus_6_hours = milliseconds.increment_hour(timestamp, 6)
plus_7_days = milliseconds.increment_day(timestamp, 7)

# Decrement operations
minus_30_sec = milliseconds.decrement_second(timestamp, 30)
minus_15_min = milliseconds.decrement_minute(timestamp, 15)
minus_6_hours = milliseconds.decrement_hour(timestamp, 6)
minus_7_days = milliseconds.decrement_day(timestamp, 7)

# Fractional values are supported
plus_half_hour = milliseconds.increment_hour(timestamp, 0.5)
minus_quarter_day = milliseconds.decrement_day(timestamp, 0.25)

Validation

from milliseconds import milliseconds

# Check if timestamp aligns to boundaries
timestamp = 1704110400000  # 2024-01-01 12:00:00.000

print(milliseconds.is_valid_second(timestamp))  # True (no milliseconds)
print(milliseconds.is_valid_minute(timestamp))  # True (no seconds)
print(milliseconds.is_valid_hour(timestamp))    # True (no minutes)
print(milliseconds.is_valid_day(timestamp))     # False (not midnight UTC)

timestamp_with_ms = 1704110400500  # 12:00:00.500
print(milliseconds.is_valid_second(timestamp_with_ms))  # False (has milliseconds)

Comparison

from milliseconds import milliseconds

ts1 = 1704110455100  # 2024-01-01 12:00:55.100
ts2 = 1704110455900  # 2024-01-01 12:00:55.900
ts3 = 1704110460000  # 2024-01-01 12:01:00.000

# Check if timestamps are in the same period
print(milliseconds.is_same_second(ts1, ts2))  # True (both in second :55)
print(milliseconds.is_same_second(ts2, ts3))  # False (different seconds)

print(milliseconds.is_same_minute(ts1, ts3))  # True (both in minute 12:00)
print(milliseconds.is_same_hour(ts1, ts3))    # True (both in hour 12:00)
print(milliseconds.is_same_day(ts1, ts3))     # True (both on 2024-01-01)

Working with Negative Timestamps

POSIX timestamps support dates before the Unix epoch (1970-01-01). This library handles them correctly:

from datetime import datetime
from zoneinfo import ZoneInfo
from milliseconds import milliseconds

# Create a date before 1970
dt = datetime(1969, 12, 31, 23, 0, 0, tzinfo=ZoneInfo("UTC"))
ms = milliseconds.milliseconds(dt)
print(ms)  # -3600000

# Operations work correctly
last_hour = milliseconds.last_hour(ms)
print(milliseconds.time(last_hour, ZoneInfo("UTC")))  # 1969-12-31 22:00:00

# Arithmetic works naturally
earlier = milliseconds.decrement_day(ms, 1)
print(milliseconds.time(earlier, ZoneInfo("UTC")))  # 1969-12-30 23:00:00

API Reference

Constants

The constants IntEnum provides time unit values in milliseconds:

from milliseconds import constants

constants.second  # 1_000 - Milliseconds in one second
constants.minute  # 60_000 - Milliseconds in one minute
constants.hour    # 3_600_000 - Milliseconds in one hour
constants.day     # 86_400_000 - Milliseconds in one day

Conversion Methods

  • milliseconds(time: datetime) -> int - Convert datetime to milliseconds
  • time(milliseconds: int, timezone: ZoneInfo) -> datetime - Convert milliseconds to datetime

Rounding Methods

  • floor(milliseconds: int, factor: int = constants.hour) -> int - Round down to nearest factor
  • ceil(milliseconds: int, factor: int = constants.hour) -> int - Round up to nearest factor

Boundary Navigation

  • last_second(timestamp: int) -> int - Get start of previous second
  • next_second(timestamp: int) -> int - Get start of next second
  • last_minute(timestamp: int) -> int - Get start of previous minute
  • next_minute(timestamp: int) -> int - Get start of next minute
  • last_hour(timestamp: int) -> int - Get start of previous hour
  • next_hour(timestamp: int) -> int - Get start of next hour
  • last_day(timestamp: int) -> int - Get start of previous day (UTC)
  • next_day(timestamp: int) -> int - Get start of next day (UTC)

Validation Methods

  • is_valid_second(timestamp: int) -> bool - Check if aligned to second boundary
  • is_valid_minute(timestamp: int) -> bool - Check if aligned to minute boundary
  • is_valid_hour(timestamp: int) -> bool - Check if aligned to hour boundary
  • is_valid_day(timestamp: int) -> bool - Check if aligned to day boundary

Arithmetic Methods

  • increment_second(timestamp: int, n: float = 1) -> int - Add seconds
  • decrement_second(timestamp: int, n: float = 1) -> int - Subtract seconds
  • increment_minute(timestamp: int, n: float = 1) -> int - Add minutes
  • decrement_minute(timestamp: int, n: float = 1) -> int - Subtract minutes
  • increment_hour(timestamp: int, n: float = 1) -> int - Add hours
  • decrement_hour(timestamp: int, n: float = 1) -> int - Subtract hours
  • increment_day(timestamp: int, n: float = 1) -> int - Add days
  • decrement_day(timestamp: int, n: float = 1) -> int - Subtract days

Comparison Methods

  • is_same_second(ts1: int, ts2: int) -> bool - Check if in same second
  • is_same_minute(ts1: int, ts2: int) -> bool - Check if in same minute
  • is_same_hour(ts1: int, ts2: int) -> bool - Check if in same hour
  • is_same_day(ts1: int, ts2: int) -> bool - Check if in same day (UTC)

License

milliseconds is distributed under the terms of the MIT license.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

milliseconds-0.1.2.tar.gz (9.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

milliseconds-0.1.2-py3-none-any.whl (8.3 kB view details)

Uploaded Python 3

File details

Details for the file milliseconds-0.1.2.tar.gz.

File metadata

  • Download URL: milliseconds-0.1.2.tar.gz
  • Upload date:
  • Size: 9.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-httpx/0.28.1

File hashes

Hashes for milliseconds-0.1.2.tar.gz
Algorithm Hash digest
SHA256 4209ef5c306628ca335c07f10af54f5873e3de7adfe612630cb1addd600b1b9b
MD5 478d4426a35ab4532ce8eeb7616f60d7
BLAKE2b-256 2a77c17b1ef4bb8cbe2e1280822411d486f6b294ecaf560fd2d2fb4d02d7775b

See more details on using hashes here.

File details

Details for the file milliseconds-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: milliseconds-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 8.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-httpx/0.28.1

File hashes

Hashes for milliseconds-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 d82f781f8f90f545017478f011697d072794314a97f18e9d8d493e55b22b4fc6
MD5 11314d30e1a0f7ec31fa540eb1fb5fc4
BLAKE2b-256 5313418c5eaba0c610996ed3c6e1b54d80f17f8270c49574159fdb25799311c9

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page