1

Importing DateTime Error Message:

 RuntimeWarning: DateTimeField Entry.date received a naive datetime (2020-07-20 09:23:19.881763) while time zone support is active.
  RuntimeWarning)

Is there a way a user can select the datetime they are in or at least import the data with +00 added? Currently, I can't seem to be able to import once I add the datetime field.

Right now I'm trying this issue solution

resources.py

class TzDateTimeWidget(DateTimeWidget):

    def render(self, value, obj=None):
        if settings.USE_TZ:
            value = localtime(value)
        return super(TzDateTimeWidget, self).render(value)

class EntryResource(resources.ModelResource):
    date = fields.Field(
        column_name='date',
        attribute='datetime',
        widget=TzDateTimeWidget(format='"%Y-%m-%d %H:%M:%S"'))


    class Meta:
        model = Entry
        fields = ('date', 'entry_type', 'amount', 'price', 'fee', 'reg_fee', 'id',)
        import_order = fields
        skip_unchanged = False
        report_skipped = True

csv file

2020-07-17 7:42:39,,40,14.56,0,Entry,0
2020-07-17 7:47:16,,40,14.78,0,Entry,0
Alex Winkler
  • 469
  • 4
  • 25

3 Answers3

3

The issue is that the datetime in your csv file is not Timezone aware. There are a few ways to solve this.

Option 1 - all users are in one timezone

You don't need timezone information in the csv if you know that the supplied date is always going to be in your timezone, because it will be converted during import and have the correct timezone.

Option 2 - CSV contains TZ aware timestamps

If the supplied timestamps are timezone aware, then you can handle this during import:

csv:

2020-07-20 00:00:00+03:00,40,14.56,0,Entry,0

Widget:

class TzDateTimeWidget(widgets.DateTimeWidget):
    def clean(self, value, row=None, *args, **kwargs):
        if not value:
            return None
        if isinstance(value, datetime):
            return value
        for format in self.formats:
            try:
                if settings.USE_TZ:
                    dt = parse_datetime(value)
                return dt
            except (ValueError, TypeError):
                continue
        raise ValueError("Enter a valid date/time.")

Option 3 - store timezone per user and apply it during import

If your users can be in any timezone, but it is not possible to encode tz in the csv, then you can store the User's timezone (e.g. in a custom User model instance), and apply the conversion for the user during import.

A simplified version of this would be:

class UserDateTimeWidget(widgets.DateTimeWidget):
    def __init__(self, user_tz_dict):
        """pass in a dict mapping user_id to timezone"""
        super().__init__()
        self.user_dict = user_tz_dict

    def clean(self, value, row=None, *args, **kwargs):
        dt = super().clean(value, row, args, kwargs)
        # the row will need to contain a reference to the user id
        user_id = row.get("user_id")
        user_tz = self.user_dict.get(user_id)
        return make_aware(dt, timezone=user_tz)

It's important to note that this relies on the csv timestamp being in a consistent standard, such as UTC.

Note that there are other ways you could achieve the above, such as overriding the Model save() method to apply the User's timezone at the point of saving the instance. Obviously you have to link the User to the imported object.

As a side note, the TzDateTimeWidget you reference will only format the date in the defined timezone when the data is exported. This functionality is already present in DateTimeWidget.

Matthew Hegarty
  • 3,791
  • 2
  • 27
  • 42
  • Thanks Matthew for the very detailed response! Still working on it. I like the different options, actually tried option 2 but had some issues. Auto added +00 to the end of all datetime. Should try it again. Ideal solution would be option 3. If I save user tz in their profile (like so: https://stackoverflow.com/a/45867250/8315752) where do I call it? I'm not sure if I fully understand the user_tz_dict, is that a custom field or default from django user model when USE_TZ = True in setings? – Alex Winkler Jul 21 '20 at 07:33
  • Also a very common issue I am having across the board on all my test is getting balnk data imported although the csv has all the fields properly filled. There's no error message here which makes it hard to debug but here's a screenshot from the admin import confirmation page: https://i.imgur.com/dRjhRZ4.png – Alex Winkler Jul 21 '20 at 07:56
  • Happy to chat about this if you like: https://chat.stackoverflow.com/rooms/218260/django-import-export – Matthew Hegarty Jul 21 '20 at 08:03
  • The current solution so far has been commenting out the USE_TZ = True in settings, doesn't seem perfect but a step to move forward from. Check out the chat link above for more. – Alex Winkler Jul 23 '20 at 06:57
  • It should be fine with [`USE_TZ`](https://github.com/django-import-export/django-import-export/blob/master/import_export/widgets.py#L214) and handle the datetime conversion for you. I would suggest set a debugger and see if you can see what is going on. – Matthew Hegarty Jul 23 '20 at 09:20
0

The fault is in your object. Here's how a proper datetime object looks:

>>> from django.utils import timezone
>>> import pytz
>>> timezone.now()
datetime.datetime(2013, 11, 20, 20, 8, 7, 127325, tzinfo=pytz.UTC)

Here's a naive object:

>>> from datetime import datetime
>>> datetime.now()
datetime.datetime(2013, 11, 20, 20, 9, 26, 423063)

I'm assuming that the error occurs when you tried to convert the csv file directly. What you should do it to separate the values, assign them to variables, and then add them in one by one into a datetime object.

Research

crimsonpython24
  • 2,223
  • 2
  • 11
  • 27
0

If you are exporting data with django-import-export and datetimes are not exported timezone aware, then simply change datetime input format in settings:

DATETIME_INPUT_FORMATS = ("%Y-%m-%dT%H:%M:%S%Z",)