Repository: django-import-export/django-import-export

Issue:
datetime field localtime() issue
**Describe the bug**
Django DateTime Import

**To Reproduce**
Import DateTime data and you'll hit a "localtime() cannot be applied to a naive datetime", I've been using the package for a while now and use the admin import page as well as a custom import page for users. Both work fine for non-datetime data.

I've tried this with adding with tz +00 and without
2020-07-17 7:42:39
2020-07-17 7:42:39+00

I've tried the DateTimeWidget where
format="%Y-%m-%d %H:%M:%S"
format="%Y-%m-%d %H:%M:%S$z"
format=None

I've posted a SOF question regarding it
https://stackoverflow.com/questions/62990575/django-import-export-datetime-naive-datetime-error

And had a convo specific to it on SOF
https://chat.stackoverflow.com/rooms/218260/django-import-export

The end result seems that the issue may be in the django-import-export package.

**Versions (please complete the following information):**
 - django-import-export==2.2.0
 - Python 3.7.4
 - Django==3.0.2

settings.py
```
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
```

**Expected behavior**
I was expecting the datetime to import the dates in my csv file

**Screenshots**
View 2 links above

**Additional context**
View 2 links above



Discussion:
Alex and I discussed this on SO chat.  The issue seemed to be that when a naive datetime was imported via the Admin console, then it couldn't be displayed because the `render()` method in `DateTimeWidget` couldn't handle a naive datetime.
However I couldn't reproduce this issue.  I'll do some more research, but my current thinking is that it is not a bug.
If i leave Time_Zone = 'UTC' but comment out Use_TZ = True
With this data
date,id,amount,price,fee,entry_type,reg_fee
2020-07-17 7:42:39,,40,14.56,0,Entry,0
2020-07-17 7:42:39,,40,14.56,0,Entry,0
Then it imports. Still not sure where the issue lies with USE_TZ=True is not commented out
In that case you have disabled Timezone support, so there is no [conversion of a naive datetime to tz aware](https://github.com/django-import-export/django-import-export/blob/master/import_export/widgets.py#L214).  This is saying that you are ok with naive datetimes in your database, which could cause you problems down the line, depending on the nature of your app.  You'll need to think carefully if you want to disable timezones (more info [here](https://docs.djangoproject.com/en/3.0/topics/i18n/timezones/)).  


This code reproduces your issue, but this shouldn't happen in normal operations, because `render()` should never be passed a naive datetime:

```python
    w = widgets.DateTimeWidget(format="%Y-%m-%d %H:%M:%S")
    print(w.render(parse_datetime('2020-07-20 0:00:00')))
```
Results in:
```
django/utils/timezone.py", line 207, in localtime
    raise ValueError("localtime() cannot be applied to a naive datetime")
```

However, this error shouldn't occur because the [`clean()`](https://github.com/django-import-export/django-import-export/blob/master/import_export/widgets.py#L214) method will apply a default `datetime` with a timezone during import.

So this means that somehow this is being missed, and a naive datetime is being passed to `render()`.

> In that case you have disabled Timezone support, so there is no [conversion of a naive datetime to tz aware](https://github.com/django-import-export/django-import-export/blob/master/import_export/widgets.py#L214). This is saying that you are ok with naive datetimes in your database, which could cause you problems down the line, depending on the nature of your app. You'll need to think carefully if you want to disable timezones (more info [here](https://docs.djangoproject.com/en/3.0/topics/i18n/timezones/)).

The imported datetimes are showing up as 2020-07-21 07:25:56+00 in the database although in the csv file are 2020-07-21 07:25:56

Does that not mean they are NOT naive? As the have tz attached since my TIME_ZONE = 'UTC' ?

---

Thanks for helping me with this and awesome that you were able to recreate the issue. I'm really wondering where the discrepancies happen.
If `USE_TZ` is not set, then it is disabled by default.  So having `TIME_ZONE` set won't make any difference (at least for `django-import-export`).  It depends on your database, but storage could be in UTC by default ([Postgres](https://docs.djangoproject.com/en/3.0/topics/i18n/timezones/#postgresql) does this).
Hi @MrAlexWinkler I couldn't reproduce this issue using the Admin console.  Is there anything you would like to add or can I close the issue?
I guess we could close it for now. However, the original issue is still not solved. 
If I have new info should I add it here after the ticket is closed?
Yes, my view is that it is an issue with your project, rather than with `django-import-export`, because I was unable to reproduce it with the information you supplied.  If you can reproduce it, then please provide details here and I'll look into it.
I was able to reproduce it, and needed to comment out USE_TZ
is it a package problem or a database issue?

Can you reproduce this using the test application?
I think this happens when the server time zone and local time zone are different
had the same problem today. exported data, deleted data, imported and got that error.
> had the same problem today. exported data, deleted data, imported and got that error.

did you find a fix?
I've tried commenting #USE_TZ = True

and work
> this shouldn't happen in normal operations, because render() should never be passed a naive datetime

I have encountered at least one path in which `render` is indeed passed a naive datetime, as the output of `clean` while showing a diff as mentioned in the original bug-report. Namely, when the original file contains actual datetimes rather than strings:

https://github.com/django-import-export/django-import-export/blob/2c1dac5747c732cb1100bf59fea4b5f13370b00b/import_export/widgets.py#L218

Resolving patch:
diff --git a/import_export/widgets.py b/import_export/widgets.py
--- a/import_export/widgets.py
+++ b/import_export/widgets.py
@@ -212,21 +212,21 @@ def __init__(self, format=None):
         self.formats = formats
 
     def clean(self, value, row=None, *args, **kwargs):
+        dt = None
         if not value:
             return None
         if isinstance(value, datetime):
-            return value
-        for format in self.formats:
-            try:
-                dt = datetime.strptime(value, format)
-                if settings.USE_TZ:
-                    # make datetime timezone aware so we don't compare
-                    # naive datetime to an aware one
-                    dt = timezone.make_aware(dt,
-                                             timezone.get_default_timezone())
-                return dt
-            except (ValueError, TypeError):
-                continue
+            dt = value
+        else:
+            for format_ in self.formats:
+                try:
+                    dt = datetime.strptime(value, format_)
+                except (ValueError, TypeError):
+                    continue
+        if dt:
+            if settings.USE_TZ:
+                dt = timezone.make_aware(dt)
+            return dt
         raise ValueError("Enter a valid date/time.")
 
     def render(self, value, obj=None):


Test patch:
diff --git a/tests/core/tests/test_widgets.py b/tests/core/tests/test_widgets.py
--- a/tests/core/tests/test_widgets.py
+++ b/tests/core/tests/test_widgets.py
@@ -107,6 +107,12 @@ def test_use_tz(self):
         self.assertEqual(self.widget.render(utc_dt), "13.08.2012 20:00:00")
         self.assertEqual(self.widget.clean("13.08.2012 20:00:00"), utc_dt)
 
+    @override_settings(USE_TZ=True, TIME_ZONE='Europe/Ljubljana')
+    def test_clean_returns_tz_aware_datetime_when_naive_datetime_passed(self):
+        # issue 1165
+        target_dt = timezone.make_aware(self.datetime, pytz.timezone('Europe/Ljubljana'))
+        self.assertEqual(target_dt, self.widget.clean(self.datetime))
+
     @override_settings(DATETIME_INPUT_FORMATS=None)
     def test_default_format(self):
         self.widget = widgets.DateTimeWidget()