Skip to content

make DurationField store milliseconds instead of microseconds #62

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 1, 2024
Merged
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
1 change: 1 addition & 0 deletions .github/workflows/test-python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ jobs:
expressions.tests.ExpressionsTests.test_insensitive_patterns_escape
expressions.tests.ExpressionsTests.test_patterns_escape
expressions.tests.FieldTransformTests.test_transform_in_values
expressions.tests.FTimeDeltaTests.test_date_minus_duration
expressions.tests.NegatedExpressionTests
expressions_case
defer
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ Migrations for 'admin':

- Queries with joins aren't supported.

- `DateTimeField` doesn't support microsecond precision.
- `DateTimeField` doesn't support microsecond precision, and correspondingly,
`DurationField` stores milliseconds rather than microseconds.

- The following database functions aren't supported:
- `Chr`
Expand Down
3 changes: 3 additions & 0 deletions django_mongodb/expressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ def value(self, compiler, connection): # noqa: ARG001
elif isinstance(value, datetime.date):
# Turn dates into datetimes since BSON doesn't support dates.
value = datetime.datetime.combine(value, datetime.datetime.min.time())
elif isinstance(value, datetime.timedelta):
# DurationField stores milliseconds rather than microseconds.
value /= datetime.timedelta(milliseconds=1)
return {"$literal": value}
Copy link
Collaborator

@WaVEV WaVEV Jun 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 I am wondering if (value / timedelta(milliseconds=1)).total_seconds() works?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, except that timedelta / timedelta gives a float, so no need for total_seconds(). Do you see an advantage to that version?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree on no need of total_second I misunderstood the docs. https://docs.python.org/3/library/datetime.html#datetime.timedelta.total_seconds
But it recommended, by the docs, to use the division by time delta. I see no advantages, only the docs



Expand Down
2 changes: 2 additions & 0 deletions django_mongodb/fields/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from .auto import MongoAutoField
from .duration import register_duration_field
from .json import register_json_field

__all__ = ["register_fields", "MongoAutoField"]


def register_fields():
register_duration_field()
register_json_field()
15 changes: 15 additions & 0 deletions django_mongodb/fields/duration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from django.db.models.fields import DurationField

_get_db_prep_value = DurationField.get_db_prep_value


def get_db_prep_value(self, value, connection, prepared=False):
"""DurationField stores milliseconds rather than microseconds."""
value = _get_db_prep_value(self, value, connection, prepared)
if connection.vendor == "mongodb" and value is not None:
value //= 1000
return value


def register_duration_field():
DurationField.get_db_prep_value = get_db_prep_value
5 changes: 5 additions & 0 deletions django_mongodb/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ def convert_decimalfield_value(self, value, expression, connection):
value = value.to_decimal()
return value

def convert_durationfield_value(self, value, expression, connection):
if value is not None:
value = datetime.timedelta(milliseconds=value)
return value

def convert_jsonfield_value(self, value, expression, connection):
"""
Convert dict data to a string so that JSONField.from_db_value() can
Expand Down