#1059363 gbp-import-dsc crashes when changelog contains leap seconds ("Sun, 1 Jan 2006, 00:59:60 +0100")

#1059363#5
Date:
2023-12-23 15:48:51 UTC
From:
To:
Dear git-buildpackage maintainer,

the gbp-import-dsc script crashes while parsing changelogs that include
leap seconds.

For example, while parsing the changelog of unicode/5.0, gbp-import-dsc
crashes with

```
   File "/usr/lib/python3/dist-packages/gbp/scripts/import_dsc.py", line
116, in get_author_from_changelog
     date = rfc822_date_to_git(dch.date, fuzzy=True)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/usr/lib/python3/dist-packages/gbp/git/__init__.py", line 44,
in rfc822_date_to_git
     d = dateutil.parser.parse(rfc822_date, fuzzy=fuzzy)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/usr/lib/python3/dist-packages/dateutil/parser/_parser.py",
line 1368, in parse
     return DEFAULTPARSER.parse(timestr, **kwargs)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/usr/lib/python3/dist-packages/dateutil/parser/_parser.py",
line 651, in parse
     six.raise_from(ParserError(str(e) + ": %s", timestr), e)
   File "<string>", line 3, in raise_from
dateutil.parser._parser.ParserError: second must be in 0..59: Sun,  1
Jan 2006 00:59:60 +0100
```

Leap seconds (:60) are explicitly permitted by Debian Policy [1] and RFC
5322 [2] and produced by `date -R`.

As of 2023-12 there is an open issue asking for support for leap seconds
in dateutils [3].

A possible solution to this issue, suggested by olasd, would to parse
the date using the stdlib method `email.utils.parsedate_tz` and handle
the leap seconds manually:

```
import email, datetime

add_leap_second = False
dateinfo = list(email.utils.parsedate_tz(rfc822_date))
if dateinfo[5] == 60:
     dateinfo[5] = 59
     add_leap_second = True

date = datetime.datetime(*dateinfo[:6])

if add_leap_second:
     date += datetime.timedelta(seconds=1)
```

Alternatively:

```
dhc_date = dch.date.replace(":60 ", ":59 ")
date = rfc822_date_to_git(dch.date, fuzzy=True)
if dch_date != dch.date:
     date += datetime.timedelta(seconds=1)
```

Regards,

[1] «ss is the two-digit seconds (00-60)»
https://www.debian.org/doc/debian-policy/ch-source.html#s-dpkgchangelog

[2] «the time-of-day MUST be in the range 00:00:00 through 23:59:60 (the
number of seconds allowing for a leap second; see [RFC1305])»
https://datatracker.ietf.org/doc/html/rfc5322#section-3.3

[3] https://github.com/dateutil/dateutil/issues/1018

#1059363#10
Date:
2023-12-23 15:57:59 UTC
From:
To:
Hi,

This looks like a bug in dateutil, can you reassign there?
Cheers,
 -- Guido

#1059363#15
Date:
2023-12-23 16:09:48 UTC
From:
To:
Hi Guido,

Not really:

That issue has been open for almost three years. The dateutils
developers say that Python's datetime does not handle leap seconds, so
they are not going to mess around with it.

In order to deal with Debian policy's request to support :60,
application-level workarounds are needed.

Please find attached a small patch that fix this issue.

Regards,

#1059363#22
Date:
2023-12-30 10:27:00 UTC
From:
To:
Hi,

Ah...I missed that one. We should work around it in gbp then.

That works. Could you add a line to the doctest in that function too so
we check for and don't break it on accident again. Otherwise I can do it
when applying the patch.

Cheers,
 -- Guido

#1059363#27
Date:
2023-12-30 21:40:52 UTC
From:
To:
Thanks for accepting the patch.

PS: Beware: the indentation may be wrong.

Regards,