Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion django_ledger/io/io_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ def validate_io_timestamp(
are enabled.
- String inputs are first attempted to be parsed into `date` objects before
attempting to parse them into `datetime` objects if the initial attempt fails.
Parsed datetimes retain their time and UTC offset; date-only strings use midnight.
- When `no_parse_localdate` is True, the function defaults to returning the
local time for cases where parsing is not possible.
"""
Expand All @@ -374,8 +375,9 @@ def validate_io_timestamp(
fdt = parse_datetime(dt)
if not fdt:
raise InvalidDateInputError(message=f'Could not parse date from {dt}')
elif is_naive(fdt):
elif global_settings.USE_TZ and is_naive(fdt):
fdt = make_aware(fdt)
return fdt
if global_settings.USE_TZ:
return make_aware(
datetime.combine(
Expand Down
59 changes: 58 additions & 1 deletion django_ledger/tests/test_io.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,73 @@
from datetime import timedelta, datetime
from decimal import Decimal
from random import randint
from zoneinfo import ZoneInfo

from django.conf import settings
from django.test import SimpleTestCase, override_settings

from django_ledger.io.io_core import IOValidationError
from django_ledger.io.io_core import IOValidationError, validate_io_timestamp
from django_ledger.models import EntityModel
from django_ledger.tests.base import DjangoLedgerBaseTest


@override_settings(TIME_ZONE='America/New_York')
class IOTimestampTest(SimpleTestCase):

@override_settings(USE_TZ=True)
def test_datetime_strings_preserve_time_and_offset(self):
for timestamp in (
'2024-07-01T14:35:27.123456Z',
'2024-07-01T00:35:27.123456+10:00',
'2024-07-01T23:35:27.123456-05:00',
):
with self.subTest(timestamp=timestamp):
expected = datetime.fromisoformat(timestamp)
actual = validate_io_timestamp(timestamp)
self.assertEqual(actual, expected)
self.assertEqual(actual.utcoffset(), expected.utcoffset())

def test_naive_datetime_strings_preserve_time(self):
timestamp = '2024-07-01T14:35:27.123456'
for use_tz in (True, False):
with self.subTest(use_tz=use_tz), self.settings(USE_TZ=use_tz):
expected = datetime.fromisoformat(timestamp)
if use_tz:
expected = expected.replace(tzinfo=ZoneInfo(settings.TIME_ZONE))
self.assertEqual(validate_io_timestamp(timestamp), expected)

def test_date_strings_still_use_local_midnight(self):
for use_tz in (True, False):
with self.subTest(use_tz=use_tz), self.settings(USE_TZ=use_tz):
expected = datetime(2024, 7, 1)
if use_tz:
expected = expected.replace(tzinfo=ZoneInfo(settings.TIME_ZONE))
self.assertEqual(validate_io_timestamp('2024-07-01'), expected)


class IOTest(DjangoLedgerBaseTest):

def test_commit_txs_preserves_datetime_string(self):
entity_model = self.get_random_entity_model()
ledger_model = entity_model.create_ledger(name='Timestamp regression')
timestamp = '2024-07-01T00:35:27.123456+10:00'
transactions = [
{
'account': self.get_random_account(entity_model, balance_type=tx_type),
'amount': Decimal('10.00'),
'tx_type': tx_type,
'description': 'Timestamp regression',
}
for tx_type in ('debit', 'credit')
]

journal_entry, _ = ledger_model.commit_txs(
je_timestamp=timestamp,
je_txs=transactions,
)
journal_entry.refresh_from_db()
self.assertEqual(journal_entry.timestamp, datetime.fromisoformat(timestamp))

def test_digest_dttm__dttm(self):
self.assertTrue(settings.USE_TZ, msg='Timezone not enabled.')

Expand Down