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
localtime
constructor
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