Repository: voxel51/fiftyone

Issue:
Wrong DateField value loaded from MongoDB
### Describe the problem

I load a persistent dataset from MongoDB with the instruction:
`dataset = fo.load_dataset(dataset_name)`

This is the print from the first sample:
```
print(f"{sample['filepath']}\n{sample['date']} - {sample['datetime']}") 
/root/fiftyone/global/2023/2023-09-08/d30adad1335f04da4bf928c0f023768374fafeca15d94dc94f0265c8a73de8630e3c37fcf972a43059d4b5897061fdff82605d2f03675d8e90862b6cee94415e.jpg
2023-09-07 - 2023-09-08 11:36:17
```
where the date value 2023-09-07 is wrong. It must be 2023-09-08.

Checking the same sample directly into MongoDB I get these values that seems correct:
```
{
    "_id": {
        "$oid": "662266926a533ff7fe32ddef"
    },
    "filepath": "/root/fiftyone/global/2023/2023-09-08/d30adad1335f04da4bf928c0f023768374fafeca15d94dc94f0265c8a73de8630e3c37fcf972a43059d4b5897061fdff82605d2f03675d8e90862b6cee94415e.jpg",
    "tags": [],
    "_media_type": "image",
    "_rand": 0.9997939277596051,
    "ground_truth": {
        "_id": {
            "$oid": "662266916a533ff7fe32ddee"
        },
        "_cls": "Classification",
        "tags": [],
        "label": "Lifted Electrode"
    },
    "datetime": {
        "$date": {
            "$numberLong": "1694172977000"
        }
    },
    "year": 2023,
    "date": {
        "$date": {
            "$numberLong": "1694131200000"
        }
    },
    "_dataset_id": {
        "$oid": "662266916a533ff7fe32dded"
    }
}
```

### Code to reproduce issue

I don't know if my localization in Rome could be a possible problem.

### System information

-   Linux Ubuntu 22.04
-   Python version 3.9.16
-   FiftyOne version 0.23.8

### Other info/logs


### Willingness to contribute

The FiftyOne Community encourages bug fix contributions. Would you or another
member of your organization be willing to contribute a fix for this bug to the
FiftyOne codebase?

-   [ ] Yes. I can contribute a fix for this bug independently
-   [ ] Yes. I would be willing to contribute a fix for this bug with guidance
        from the FiftyOne community
-   [x] No. I cannot contribute a bug fix at this time



Discussion:
Indeed,
`1694131200000` should translate to `Fri Sep 08 2023 00:00:00 GMT+0000`
and `1694172977000` to `Fri Sep 08 2023 11:36:17 GMT+0000`


@rikirolly thanks for the report I think I found the issue hold tight!!

Resolving patch:
diff --git a/fiftyone/core/fields.py b/fiftyone/core/fields.py
--- a/fiftyone/core/fields.py
+++ b/fiftyone/core/fields.py
@@ -516,8 +516,14 @@ def to_python(self, value):
 
         # Explicitly converting to UTC is important here because PyMongo loads
         # everything as `datetime`, which will respect `fo.config.timezone`,
-        # but we always need UTC here for the conversion back to `date`
-        return value.astimezone(pytz.utc).date()
+        # but we always need UTC here for the conversion back to `date` because
+        # we write to the DB in UTC time.
+        # If value is timezone unaware, then do not convert because it will be
+        # assumed to be in local timezone and date will be wrong for GMT+
+        # localities.
+        if value.tzinfo is not None:
+            value = value.astimezone(pytz.utc)
+        return value.date()
 
     def validate(self, value):
         if not isinstance(value, date):
diff --git a/fiftyone/core/odm/database.py b/fiftyone/core/odm/database.py
--- a/fiftyone/core/odm/database.py
+++ b/fiftyone/core/odm/database.py
@@ -422,7 +422,7 @@ def get_async_db_conn(use_global=False):
 def _apply_options(db):
     timezone = fo.config.timezone
 
-    if not timezone or timezone.lower() == "utc":
+    if not timezone:
         return db
 
     if timezone.lower() == "local":


Test patch:
diff --git a/tests/unittests/dataset_tests.py b/tests/unittests/dataset_tests.py
--- a/tests/unittests/dataset_tests.py
+++ b/tests/unittests/dataset_tests.py
@@ -5,6 +5,7 @@
 | `voxel51.com <https://voxel51.com/>`_
 |
 """
+import time
 from copy import deepcopy, copy
 from datetime import date, datetime, timedelta
 import gc
@@ -558,6 +559,22 @@ def test_date_fields(self):
         self.assertEqual(type(sample.date), date)
         self.assertEqual(int((sample.date - date1).total_seconds()), 0)
 
+        # Now change system time to something GMT+
+        system_timezone = os.environ.get("TZ")
+        try:
+            os.environ["TZ"] = "Europe/Madrid"
+            time.tzset()
+            dataset.reload()
+        finally:
+            if system_timezone is None:
+                del os.environ["TZ"]
+            else:
+                os.environ["TZ"] = system_timezone
+            time.tzset()
+
+        self.assertEqual(type(sample.date), date)
+        self.assertEqual(int((sample.date - date1).total_seconds()), 0)
+
     @drop_datasets
     def test_datetime_fields(self):
         dataset = fo.Dataset()