161 lines
5.1 KiB
Python
161 lines
5.1 KiB
Python
"""Tests for timestamp utilities."""
|
|
|
|
import pytest
|
|
from datetime import datetime, timezone, timedelta
|
|
|
|
from exchange_data_manager.utils.timestamps import (
|
|
to_millis,
|
|
from_millis,
|
|
to_seconds,
|
|
from_seconds,
|
|
ensure_tz_aware,
|
|
now_millis,
|
|
now_seconds,
|
|
)
|
|
|
|
|
|
class TestToMillis:
|
|
"""Tests for to_millis function."""
|
|
|
|
def test_from_seconds(self):
|
|
"""Test converting seconds to milliseconds."""
|
|
assert to_millis(1709337600) == 1709337600000
|
|
|
|
def test_from_milliseconds(self):
|
|
"""Test that milliseconds pass through unchanged."""
|
|
assert to_millis(1709337600000) == 1709337600000
|
|
|
|
def test_from_float_seconds(self):
|
|
"""Test converting float seconds."""
|
|
assert to_millis(1709337600.5) == 1709337600500
|
|
|
|
def test_from_datetime_utc(self):
|
|
"""Test converting UTC datetime."""
|
|
dt = datetime(2024, 3, 2, 0, 0, 0, tzinfo=timezone.utc)
|
|
assert to_millis(dt) == 1709337600000
|
|
|
|
def test_from_naive_datetime(self):
|
|
"""Test converting naive datetime (assumes UTC)."""
|
|
dt = datetime(2024, 3, 2, 0, 0, 0)
|
|
# Naive datetime treated as UTC
|
|
assert to_millis(dt) == 1709337600000
|
|
|
|
def test_threshold_detection(self):
|
|
"""Test automatic detection of seconds vs milliseconds."""
|
|
# Values with realistic Unix-second magnitude are treated as seconds
|
|
assert to_millis(1709337600) == 1709337600000
|
|
# Large values (including pre-2001 ms) are treated as milliseconds
|
|
assert to_millis(999999999999) == 999999999999
|
|
assert to_millis(1000000000000) == 1000000000000
|
|
|
|
|
|
class TestFromMillis:
|
|
"""Tests for from_millis function."""
|
|
|
|
def test_to_datetime(self):
|
|
"""Test converting milliseconds to datetime."""
|
|
dt = from_millis(1709337600000)
|
|
assert dt.year == 2024
|
|
assert dt.month == 3
|
|
assert dt.day == 2
|
|
assert dt.hour == 0
|
|
assert dt.minute == 0
|
|
assert dt.second == 0
|
|
|
|
def test_timezone_aware(self):
|
|
"""Test that result is timezone-aware."""
|
|
dt = from_millis(1709337600000)
|
|
assert dt.tzinfo is not None
|
|
assert dt.tzinfo == timezone.utc
|
|
|
|
|
|
class TestToSeconds:
|
|
"""Tests for to_seconds function."""
|
|
|
|
def test_from_seconds(self):
|
|
"""Test that seconds pass through unchanged."""
|
|
assert to_seconds(1709337600) == 1709337600
|
|
|
|
def test_from_milliseconds(self):
|
|
"""Test converting milliseconds to seconds."""
|
|
assert to_seconds(1709337600000) == 1709337600
|
|
|
|
def test_historical_milliseconds_detected(self):
|
|
"""Test that historical ms timestamps are not misclassified as seconds."""
|
|
assert to_seconds(999999999999) == 999999999
|
|
|
|
def test_from_datetime(self):
|
|
"""Test converting datetime to seconds."""
|
|
dt = datetime(2024, 3, 2, 0, 0, 0, tzinfo=timezone.utc)
|
|
assert to_seconds(dt) == 1709337600
|
|
|
|
|
|
class TestFromSeconds:
|
|
"""Tests for from_seconds function."""
|
|
|
|
def test_to_datetime(self):
|
|
"""Test converting seconds to datetime."""
|
|
dt = from_seconds(1709337600)
|
|
assert dt.year == 2024
|
|
assert dt.month == 3
|
|
assert dt.day == 2
|
|
|
|
def test_timezone_aware(self):
|
|
"""Test that result is timezone-aware."""
|
|
dt = from_seconds(1709337600)
|
|
assert dt.tzinfo == timezone.utc
|
|
|
|
|
|
class TestEnsureTzAware:
|
|
"""Tests for ensure_tz_aware function."""
|
|
|
|
def test_naive_becomes_utc(self):
|
|
"""Test that naive datetime becomes UTC."""
|
|
dt = datetime(2024, 3, 2, 0, 0, 0)
|
|
result = ensure_tz_aware(dt)
|
|
assert result.tzinfo == timezone.utc
|
|
|
|
def test_aware_unchanged(self):
|
|
"""Test that aware datetime is unchanged."""
|
|
dt = datetime(2024, 3, 2, 0, 0, 0, tzinfo=timezone.utc)
|
|
result = ensure_tz_aware(dt)
|
|
assert result == dt
|
|
|
|
def test_different_timezone_normalized_to_utc(self):
|
|
"""Test that non-UTC timezone is normalized to UTC."""
|
|
tz = timezone(timedelta(hours=5))
|
|
dt = datetime(2024, 3, 2, 0, 0, 0, tzinfo=tz)
|
|
result = ensure_tz_aware(dt)
|
|
assert result.tzinfo == timezone.utc
|
|
assert result.year == 2024
|
|
assert result.month == 3
|
|
assert result.day == 1
|
|
assert result.hour == 19
|
|
|
|
|
|
class TestNowFunctions:
|
|
"""Tests for now_millis and now_seconds functions."""
|
|
|
|
def test_now_millis_reasonable(self):
|
|
"""Test that now_millis returns a reasonable value."""
|
|
ms = now_millis()
|
|
# Should be after 2024-01-01 in milliseconds
|
|
assert ms > 1704067200000
|
|
# Should be a large number (milliseconds)
|
|
assert ms >= 1e12
|
|
|
|
def test_now_seconds_reasonable(self):
|
|
"""Test that now_seconds returns a reasonable value."""
|
|
s = now_seconds()
|
|
# Should be after 2024-01-01 in seconds
|
|
assert s > 1704067200
|
|
# Should be a smaller number (seconds)
|
|
assert s < 1e12
|
|
|
|
def test_consistency(self):
|
|
"""Test that now_millis and now_seconds are consistent."""
|
|
ms = now_millis()
|
|
s = now_seconds()
|
|
# Should be within 1 second of each other
|
|
assert abs(ms // 1000 - s) <= 1
|