RFC #822 and RFC #3339 dates in Perl
October 9, 2019
When adding a JSON feed and an RSS feed to
tumblelog I needed a publication date and
time for each article published. As I don't have an actual publication
time I decided to use the end of day, as explained in A Matter of
Time.
Edit: this blog post has been updated with additional code to make the RFC #822 solution work for a non-USA locale.
The end of day
In order to obtain a Time::Piece Perl object for the local end of
day for a given date I came up with the following idea:
- parse the date with a time of 23:59:59 attached to it
- create a new object using this result but in the local time zone
using the
localtimeconstructor
I accomplished this in Perl as follows:
sub get_end_of_day {
return Time::Piece->localtime(
Time::Piece->strptime( shift . ' 23:59:59', '%Y-%m-%d %H:%M:%S' )
);
}
RFC #822
For the RSS feed I needed the pubDate to be in RFC #822
format, which I obtained by as follows:
my @MON_LIST = qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec );
my @DAY_LIST = qw( Sun Mon Tue Wed Thu Fri Sat );
my $pub_date = $DAY_LIST[ $end_of_day->_wday() ]
. sprintf( ', %02d ', $end_of_day->mday() )
. $MON_LIST[ $end_of_day->_mon ]
. $end_of_day->strftime( ' %Y %H:%M:%S %z' );
Note that the short month name and the short day name are both looked
up instead of returned by strftime. The reason for this is that
strftime returns those names in the current locale while RFC #822
requires the USA locale.
Moreover, it's tempting to use %Z instead of %z but note that, for
example, CEST is not valid according to the RSS feed
validator, which refers to section
5.1 of RFC
#822. Hence, why
digits must be used instead for a general solution.
An example of a $pub_date value is:
Wed, 09 Oct 2019 23:59:59 +0200
RFC #3339
For the JSON feed I needed a date_published in RFC #3339 format. I
also used the strftime method, which almost gives the correct result
except that the time returned by %z doesn't contain a colon, so the
substitution operator is used to insert this required character.
( my $date_published = $end_of_day->strftime( '%Y-%m-%dT%H:%M:%S%z' ) )
=~ s/(\d\d)$/:$1/;
An example of a $date_published value is:
2019-10-09T23:59:59+02:00
See Also
- Time::Piece — Object Oriented time objects
- RFC #822 — Standard for ARPA Internet Text Messages
- RFC #3339 — Date and Time on the Internet: Timestamps
- Hand coding an RSS 2.0 feed in Perl
- RFC #822 and RFC #3339 dates in Python