How to Convert DateTime to String in Django/DRF While Testing

Viewed 914

I'm testing an endpoint which naturally returns a JSON containing the datetime as a string.

I compare the response content in test as such:

assert serializer_instance.data == {
    "created_at": str(model_instance.created_at),
    "updated_at": str(model_instance.updated_at),
}

created_at and updated_at are surely DateTimeFields. However, in this case, test fails saying:

E         Differing items:
E         {'created_at': '2020-06-24T12:42:03.578207+03:00'} != {'created_at': '2020-06-24 09:42:03.578207+00:00'}
E         {'updated_at': '2020-06-24T12:42:03.578231+03:00'} != {'updated_at': '2020-06-24 09:42:03.578231+00:00'}

So str uses a different formatting on datetimes. Sure, the test case can be passed successfully using strftime, but there should be an internal function that does it easily in either Django or Django Rest Framework and I'd like to learn it.

Thanks in advance.


Environment

  • Python 3.8.3
  • Django 2.2.12
  • Django Rest Framework 3.11.0
5 Answers

For DRF I normally use

obj.ts_updated.astimezone(timezone(settings.TIME_ZONE)).isoformat()

This matches the DRF format.

I am a bit late to the party, But, better late than never!

I am using this method to assert datetime response in DRF

from rest_framework.fields import DateTimeField

drf_str_datetime = DateTimeField().to_representation
assert serializer_instance.data == {
    "created_at": drf_str_datetime(model_instance.created_at),
    "updated_at": drf_str_datetime(model_instance.updated_at),
}

I've found a way. It uses parse_datetime method and, instead of converting DateTimeField fields on model instance with str, I thought it's better both stay as datetime.

from django.utils.dateparse import parse_datetime

data = serializer_instance.data
data["created_at"] = parse_datetime(data["created_at"])
# ... and the others ...

assert data == {
    # ... and the others ...
    "created_at": model_instance.created_at,
    # ... and the others ...
}

While this is okay, we mutate serializer_instance.data like this. I don't think it is going to be a problem in tests though.

you can use:

myDate.strftime('%m/%d/%Y')

or

'{:%m/%d/%Y}'.format(myDate)

For Django Rest Framework 3.11.0 you can use the following helper function to convert a Python datetime object into a string representation used by DRF:

from pytz import timezone as pytz_timezone

def convert_datetime_to_drf_str(date_time: datetime) -> str:
    return date_time.astimezone(pytz_timezone(settings.TIME_ZONE)).isoformat().replace("+00:00", "Z")

So, for your specific case it would be:

assert serializer_instance.data == {
    "created_at": convert_datetime_to_drf_str(model_instance.created_at),
    "updated_at": convert_datetime_to_drf_str(model_instance.updated_at),
}

or directly without the helper function:

from pytz import timezone as pytz_timezone

assert serializer_instance.data == {
    "created_at": model_instance.created_at.astimezone(pytz_timezone(settings.TIME_ZONE)).isoformat().replace("+00:00", "Z"),
    "updated_at": model_instance.updated_at.astimezone(pytz_timezone(settings.TIME_ZONE)).isoformat().replace("+00:00", "Z"),
}
Related