Repository: sdispater/tomlkit

Issue:
Parser fails on datetime followed by space
The tomlkit parser rejects datetime values in certain cases.
All of the following examples trigger an error:
```python
import tomlkit
tomlkit.parse("d = 2013-01-24 13:48:01.123456 ")
tomlkit.parse("d = 2013-01-24 13:48:01.123456 \n")
tomlkit.parse("d = 2013-01-24 13:48:01 \n")
tomlkit.parse("d = 2013-01-24 13:48:01Z \n")
tomlkit.parse("d = [2013-01-24 13:48:01 ]\n")
tomlkit.parse("d = [2013-01-24 13:48:01 , 2013-01-25 13:56:01]\n")
tomlkit.parse("d = { a = 2013-01-24 13:48:01 }\n")
```
with the parser typically raising:
```
tomlkit.exceptions.InvalidDateError: Invalid date at line 1 col 31
```

It looks like this issue is triggered only if there is a space (instead of "T") between the date and the time, __and__ another space appears immediately after the time.

This issue applies to the latest commit 6512eaa3937a6eb2136face6a6704a52aa33e6e3 on master as well as the latest release v0.11.6.

I'm experimenting with a TOML fuzzer which revealed this issue. I guess most normal applications are not likely to hit this case, so I understand if this gets low priority. It still seems worthwhile to fix it though.

Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 59b335e..1d6ac55 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@
 
 - Parse empty table name if it is quoted. ([#258](https://github.com/sdispater/tomlkit/issues/258))
 - Fix a bug that remove last element of an Inline Table leaves a comma. ([#259](https://github.com/sdispater/tomlkit/issues/259))
+- Parse datetime when it is followed by a space. ([#260](https://github.com/sdispater/tomlkit/issues/260))
 - Fix the `unwrap()` method for `Container` children values which sometimes returns an internal object if the table is an out-of-order table. ([#264](https://github.com/sdispater/tomlkit/issues/264))
 
 ## [0.11.6] - 2022-10-27
diff --git a/tomlkit/parser.py b/tomlkit/parser.py
index 478834c..097aceb 100644
--- a/tomlkit/parser.py
+++ b/tomlkit/parser.py
@@ -497,11 +497,12 @@ class Parser:
                             pass
 
                         time_raw = self.extract()
-                        if not time_raw.strip():
-                            trivia.comment_ws = time_raw
+                        time_part = time_raw.rstrip()
+                        trivia.comment_ws = time_raw[len(time_part) :]
+                        if not time_part:
                             return date
 
-                        dt = parse_rfc3339(raw + time_raw)
+                        dt = parse_rfc3339(raw + time_part)
                         assert isinstance(dt, datetime.datetime)
                         return DateTime(
                             dt.year,
@@ -513,7 +514,7 @@ class Parser:
                             dt.microsecond,
                             dt.tzinfo,
                             trivia,
-                            raw + time_raw,
+                            raw + time_part,
                         )
                     except ValueError:
                         raise self.parse_error(InvalidDateError)


Test patch:
diff --git a/tests/test_items.py b/tests/test_items.py
index dfb632e..6ac06d8 100644
--- a/tests/test_items.py
+++ b/tests/test_items.py
@@ -677,6 +677,17 @@ def test_dates_behave_like_dates():
     assert doc.as_string() == "dt = 2018-07-23 # Comment"
 
 
+def test_parse_datetime_followed_by_space():
+    # issue #260
+    doc = parse("dt = 2018-07-22 ")
+    assert doc["dt"] == date(2018, 7, 22)
+    assert doc.as_string() == "dt = 2018-07-22 "
+
+    doc = parse("dt = 2013-01-24 13:48:01.123456 ")
+    assert doc["dt"] == datetime(2013, 1, 24, 13, 48, 1, 123456)
+    assert doc.as_string() == "dt = 2013-01-24 13:48:01.123456 "
+
+
 def test_times_behave_like_times():
     i = item(time(12, 34, 56))