Merge pull request #928 from wking/iso-8601

utils: Add some ISO 8601 forms to get_date()
This commit is contained in:
Justin Mayer 2013-06-14 08:27:37 -07:00
commit 6fcb6d3766
3 changed files with 75 additions and 33 deletions

View file

@ -286,7 +286,10 @@ by the directory in which the file resides. For example, a file located at
``python/foobar/myfoobar.rst`` will have a category of ``foobar``. If you would ``python/foobar/myfoobar.rst`` will have a category of ``foobar``. If you would
like to organize your files in other ways where the name of the subfolder would like to organize your files in other ways where the name of the subfolder would
not be a good category name, you can set the setting ``USE_FOLDER_AS_CATEGORY`` not be a good category name, you can set the setting ``USE_FOLDER_AS_CATEGORY``
to ``False``. to ``False``. When parsing dates given in the page metadata, Pelican supports
the W3C's `suggested subset ISO 8601`__.
__ `W3C ISO 8601`_
If you do not explicitly specify summary metadata for a given post, the If you do not explicitly specify summary metadata for a given post, the
``SUMMARY_MAX_LENGTH`` setting can be used to specify how many words from the ``SUMMARY_MAX_LENGTH`` setting can be used to specify how many words from the
@ -478,3 +481,4 @@ metadata. That article will then be output to the ``drafts`` folder and not
listed on the index page nor on any category page. listed on the index page nor on any category page.
.. _virtualenv: http://www.virtualenv.org/ .. _virtualenv: http://www.virtualenv.org/
.. _W3C ISO 8601: http://www.w3.org/TR/NOTE-datetime

View file

@ -6,9 +6,11 @@ import os
import datetime import datetime
import time import time
import locale import locale
from sys import platform from sys import platform, version_info
from tempfile import mkdtemp from tempfile import mkdtemp
import pytz
from pelican.generators import TemplatePagesGenerator from pelican.generators import TemplatePagesGenerator
from pelican.writers import Writer from pelican.writers import Writer
from pelican.settings import read_settings from pelican.settings import read_settings
@ -37,26 +39,44 @@ class TestUtils(LoggedTestCase):
def test_get_date(self): def test_get_date(self):
# valid ones # valid ones
date = datetime.datetime(year=2012, month=11, day=22) date = datetime.datetime(year=2012, month=11, day=22)
date_hour = datetime.datetime(year=2012, month=11, day=22, hour=22, date_hour = datetime.datetime(
minute=11) year=2012, month=11, day=22, hour=22, minute=11)
date_hour_sec = datetime.datetime(year=2012, month=11, day=22, hour=22, date_hour_sec = datetime.datetime(
minute=11, second=10) year=2012, month=11, day=22, hour=22, minute=11, second=10)
dates = {'2012-11-22': date, date_hour_sec_z = datetime.datetime(
'2012/11/22': date, year=2012, month=11, day=22, hour=22, minute=11, second=10,
'2012-11-22 22:11': date_hour, tzinfo=pytz.timezone('UTC'))
'2012/11/22 22:11': date_hour, date_hour_sec_est = datetime.datetime(
'22-11-2012': date, year=2012, month=11, day=22, hour=22, minute=11, second=10,
'22/11/2012': date, tzinfo=pytz.timezone('EST'))
'22.11.2012': date, date_hour_sec_frac_z = datetime.datetime(
'2012-22-11': date, year=2012, month=11, day=22, hour=22, minute=11, second=10,
'22.11.2012 22:11': date_hour, microsecond=123000, tzinfo=pytz.timezone('UTC'))
'2012-11-22 22:11:10': date_hour_sec} dates = {
'2012-11-22': date,
'2012/11/22': date,
'2012-11-22 22:11': date_hour,
'2012/11/22 22:11': date_hour,
'22-11-2012': date,
'22/11/2012': date,
'22.11.2012': date,
'22.11.2012 22:11': date_hour,
'2012-11-22 22:11:10': date_hour_sec,
'2012-11-22T22:11:10Z': date_hour_sec_z,
'2012-11-22T22:11:10-0500': date_hour_sec_est,
'2012-11-22T22:11:10.123Z': date_hour_sec_frac_z,
}
# invalid ones
invalid_dates = ['2010-110-12', 'yay']
if version_info < (3, 2):
dates.pop('2012-11-22T22:11:10-0500')
invalid_dates.append('2012-11-22T22:11:10-0500')
for value, expected in dates.items(): for value, expected in dates.items():
self.assertEqual(utils.get_date(value), expected, value) self.assertEqual(utils.get_date(value), expected, value)
# invalid ones
invalid_dates = ('2010-110-12', 'yay')
for item in invalid_dates: for item in invalid_dates:
self.assertRaises(ValueError, utils.get_date, item) self.assertRaises(ValueError, utils.get_date, item)

View file

@ -180,17 +180,39 @@ def get_date(string):
If no format matches the given date, raise a ValueError. If no format matches the given date, raise a ValueError.
""" """
string = re.sub(' +', ' ', string) string = re.sub(' +', ' ', string)
formats = ['%Y-%m-%d %H:%M', '%Y/%m/%d %H:%M', formats = [
'%Y-%m-%d', '%Y/%m/%d', # ISO 8601
'%d-%m-%Y', '%Y-%d-%m', # Weird ones '%Y',
'%d/%m/%Y', '%d.%m.%Y', '%Y-%m',
'%d.%m.%Y %H:%M', '%Y-%m-%d %H:%M:%S'] '%Y-%m-%d',
'%Y-%m-%dT%H:%M%z',
'%Y-%m-%dT%H:%MZ',
'%Y-%m-%dT%H:%M',
'%Y-%m-%dT%H:%M:%S%z',
'%Y-%m-%dT%H:%M:%SZ',
'%Y-%m-%dT%H:%M:%S',
'%Y-%m-%dT%H:%M:%S.%f%z',
'%Y-%m-%dT%H:%M:%S.%fZ',
'%Y-%m-%dT%H:%M:%S.%f',
# end ISO 8601 forms
'%Y-%m-%d %H:%M',
'%Y-%m-%d %H:%M:%S',
'%Y/%m/%d %H:%M',
'%Y/%m/%d',
'%d-%m-%Y',
'%d.%m.%Y %H:%M',
'%d.%m.%Y',
'%d/%m/%Y',
]
for date_format in formats: for date_format in formats:
try: try:
return datetime.strptime(string, date_format) date = datetime.strptime(string, date_format)
except ValueError: except ValueError:
pass continue
raise ValueError("'%s' is not a valid date" % string) if date_format.endswith('Z'):
date = date.replace(tzinfo=pytz.timezone('UTC'))
return date
raise ValueError('{0!r} is not a valid date'.format(string))
class pelican_open(object): class pelican_open(object):
@ -510,15 +532,11 @@ def file_watcher(path):
def set_date_tzinfo(d, tz_name=None): def set_date_tzinfo(d, tz_name=None):
""" Date without tzinfo shoudbe utc. """Set the timezone for dates that don't have tzinfo"""
This function set the right tz to date that aren't utc and don't have if tz_name and not d.tzinfo:
tzinfo.
"""
if tz_name is not None:
tz = pytz.timezone(tz_name) tz = pytz.timezone(tz_name)
return tz.localize(d) return tz.localize(d)
else: return d
return d
def mkdir_p(path): def mkdir_p(path):