Repository: sunpy/sunpy

Issue:
Issue with parse_time and formats
### Describe the bug

I have come across this issue when trying to parse a time string using parse time, when it's in this format  "%d-%b-%Y %H:%M:%S.%f",  # Example 04-May-2007 21:08:12.999999 

In this case it works:
```python 
parse_time('30-Mar-2022 17:25:14.500')
<Time object: scale='utc' format='isot' value=2022-03-30T17:25:14.500>
```
but doesn't in this:

```python
parse_time('30-Mar-2022 17:25:14.000')
ValueError: Input values did not match any of the formats where the format keyword is optional: {'datetime': TypeError('Input values for datetime class must be datetime objects'), 'ymdhms': ValueError('input must be dict or table-like'), 'iso': ValueError('Time 30-Mar-2022 17:25:14 does not match iso format'), 'isot': ValueError('Time 30-Mar-2022 17:25:14 does not match isot format'), 'yday': ValueError('Time 30-Mar-2022 17:25:14 does not match yday format'), 'datetime64': TypeError('Input values for datetime64 class must be datetime64 objects'), 'fits': ValueError('Time 30-Mar-2022 17:25:14 does not match fits format'), 'byear_str': ValueError('Time 30-Mar-2022 17:25:14 does not match byear_str format'), 'jyear_str': ValueError('Time 30-Mar-2022 17:25:14 does not match jyear_str format'), 'astropy_time': TypeError('Input values for astropy_time class must all be same astropy Time type.')}
```
Seems to be related to the zero after the decimal point.

### System Details

sunpy 4.0.6  
astropy 5.0 



Discussion:
ayshih: The issue in the wild is that `parse_time("10-Oct-2010 00:00:00.0")` errors, while `parse_time("10-Oct-2010 00:00:00.1")` works fine.  That's because for the first string, the final `.0` gets stripped, and there happens to be a silly omission in the defined time string formats.  The issue in the wild can be fixed by simply adding the missing time string format, but we really shouldn't be always stripping out part of the string without considering whether the stripped digits are actually part of a microsecond field.

Patch:
diff --git a/changelog/6581.bugfix.rst b/changelog/6581.bugfix.rst
new file mode 100644
index 000000000..9800c592d
--- /dev/null
+++ b/changelog/6581.bugfix.rst
@@ -0,0 +1,1 @@
+Fixed a bug where :func:`~sunpy.time.parse_time` would always disregard the remainder of a time string starting with the final period if it was followed by only zeros, which could affect the parsing of the time string.
diff --git a/sunpy/time/time.py b/sunpy/time/time.py
index 9e2a71faa..f94cc22a5 100644
--- a/sunpy/time/time.py
+++ b/sunpy/time/time.py
@@ -49,12 +49,14 @@ TIME_FORMAT_LIST = [
     "%Y-%m-%d %H:%M:%S.%f",  # Example 2007-05-04 21:08:12.999999
     "%Y-%m-%d %H:%M:%S",  # Example 2007-05-04 21:08:12
     "%Y-%m-%d %H:%M",  # Example 2007-05-04 21:08
+    "%Y-%b-%d %H:%M:%S.%f",  # Example 2007-May-04 21:08:12.999999
     "%Y-%b-%d %H:%M:%S",  # Example 2007-May-04 21:08:12
     "%Y-%b-%d %H:%M",  # Example 2007-May-04 21:08
     "%Y-%b-%d",  # Example 2007-May-04
     "%Y-%m-%d",  # Example 2007-05-04
     "%Y/%m/%d",  # Example 2007/05/04
     "%d-%b-%Y",  # Example 04-May-2007
+    "%d-%b-%Y %H:%M:%S",  # Example 04-May-2007 21:08:12
     "%d-%b-%Y %H:%M:%S.%f",  # Example 04-May-2007 21:08:12.999999
     "%Y%m%d_%H%M%S",  # Example 20070504_210812
     "%Y:%j:%H:%M:%S",  # Example 2012:124:21:08:12
@@ -102,18 +104,28 @@ def _regex_parse_time(inp, format):
     match = re.match(format, inp)
     if match is None:
         return None, None
-    try:
-        hour = match.group("hour")
-    except IndexError:
-        return inp, False
-    if hour == "24":
+
+    found_groups = match.groupdict()
+
+    # Special handling to strip any excess zeros beyond the six digits of the microsecond field
+    if "microsecond" in found_groups and re.match(r"\d{6}0+", match.group("microsecond")):
+        from_, to = match.span("microsecond")
+        inp = inp[:from_] + match.group("microsecond")[:6] + inp[to:]
+        match = re.match(format, inp)
+
+    # Special handling to add a day if the hour is 24 and the minute/second/microsecond are all zero
+    add_one_day = False
+    if "hour" in found_groups and match.group("hour") == "24":
         if not all(
                 _n_or_eq(_group_or_none(match, g, int), 00)
                 for g in ["minute", "second", "microsecond"]):
             raise ValueError
         from_, to = match.span("hour")
-        return inp[:from_] + "00" + inp[to:], True
-    return inp, False
+        inp = inp[:from_] + "00" + inp[to:]
+        add_one_day = True
+        match = re.match(format, inp)
+
+    return inp, add_one_day
 
 
 def find_time(string, format):
@@ -215,11 +227,6 @@ def convert_time_list(time_list, format=None, **kwargs):
 
 @convert_time.register(str)
 def convert_time_str(time_string, **kwargs):
-    # remove trailing zeros and the final dot to allow any
-    # number of zeros. This solves issue #289
-    if '.' in time_string:
-        time_string = time_string.rstrip("0").rstrip(".")
-
     if 'TAI' in time_string:
         kwargs['scale'] = 'tai'
 


Test patch:
diff --git a/sunpy/time/tests/test_time.py b/sunpy/time/tests/test_time.py
index 09990bc16..c42d82c12 100644
--- a/sunpy/time/tests/test_time.py
+++ b/sunpy/time/tests/test_time.py
@@ -27,13 +27,20 @@ def test_parse_time_24_2():
     assert dt.scale == 'utc'
 
 
-def test_parse_time_trailing_zeros():
-    # see issue #289 at https://github.com/sunpy/sunpy/issues/289
-    dt = parse_time('2010-10-10T00:00:00.00000000')
-    assert dt == Time('2010-10-10')
+def test_parse_time_microseconds_excess_trailing_zeros():
+    dt = parse_time('2010-Oct-10 00:00:00.1234560')
+    assert dt == Time('2010-10-10 00:00:00.123456')
     assert dt.format == 'isot'
     assert dt.scale == 'utc'
 
+    # Excess digits beyond 6 digits should error if they are not zeros
+    with pytest.raises(ValueError):
+        dt = parse_time('2010-Oct-10 00:00:00.1234567')
+
+    # An ending run of zeros should still error if they are not a microsecond field
+    with pytest.raises(ValueError):
+        dt = parse_time('10-Oct-2010.0000000')
+
 
 def test_parse_time_tuple():
     dt = parse_time((1966, 2, 3))