Repository: getpelican/pelican

Issue:
Allow non zero padded date formats
When setting DEFAULT_DATE_FORMAT you can only use zero padded date formats. Arguably this is a bug in python (or even C89) but it would be nice to extend the available formats to allow nicer formats.



Discussion:
AFAIK `datetime.strftime` support other codes, but we would have to add them to our `pelican.utils.strftime` as it uses only C89 atm. So it is most likely doable, just portability is the problem.

Adding alternative formatting options that does `.lstrip('0')` is nearly trivial. If we decide on the format, I can add them. Some `srtftime` implementations use `-` prefix for that (e.g. `%-d`, `%-m`). It shouldn't be too hard to adopt `pelican.utils.strftime` to strip zeros for those.

That is also a possibility, but it might be simpler to extend the C89
identifiers to include e.g. `%e` as an alternative to `%d` which comes from
the Single Unix  specification, see **strftime(3)** for details.
`date.stfrtime` supports them already.

I'll tag this with the 3.4.1 milestone as our strftime change broke this for some people

But `strftime(3)` doesn't have an option for non-padded month. We need to add that in any case. Might as well do it for both in a consistent (and platform independent) way.

Alternatively, we can support both `%e` and `-` prefixed versions.

I agree with @avaris that the more options the user has the better, especially since our `pelican.utils.strftime` would make it easy to implement the `-` functionality.
Now it's just a question of which chars to add to the C89 set alrey used. I vote for using anything appearing in **strftime(3)**, i.e. SU, C99, etc.


Resolving patch:
diff --git a/pelican/utils.py b/pelican/utils.py
--- a/pelican/utils.py
+++ b/pelican/utils.py
@@ -42,8 +42,11 @@ def strftime(date, date_format):
     replacing formatted output back.
     '''
 
+    c89_directives = 'aAbBcdfHIjmMpSUwWxXyYzZ%'
+    strip_zeros = lambda x: x.lstrip('0') or '0'
+
     # grab candidate format options
-    format_options = '%.'
+    format_options = '%[-]?.'
     candidates = re.findall(format_options, date_format)
 
     # replace candidates with placeholders for later % formatting
@@ -56,14 +59,28 @@ def strftime(date, date_format):
     formatted_candidates = []
     for candidate in candidates:
         # test for valid C89 directives only
-        if candidate[1] in 'aAbBcdfHIjmMpSUwWxXyYzZ%':
+        if candidate[-1] in c89_directives:
+            # check for '-' prefix
+            if len(candidate) == 3:
+                # '-' prefix
+                candidate = '%{}'.format(candidate[-1])
+                conversion = strip_zeros
+            else:
+                conversion = None
+
+            # format date
             if isinstance(date, SafeDatetime):
                 formatted = date.strftime(candidate, safe=False)
             else:
                 formatted = date.strftime(candidate)
+
             # convert Py2 result to unicode
             if not six.PY3 and enc is not None:
                 formatted = formatted.decode(enc)
+
+            # strip zeros if '-' prefix is used
+            if conversion:
+                formatted = conversion(formatted)
         else:
             formatted = candidate
         formatted_candidates.append(formatted)


Test patch:
diff --git a/pelican/tests/test_utils.py b/pelican/tests/test_utils.py
--- a/pelican/tests/test_utils.py
+++ b/pelican/tests/test_utils.py
@@ -280,6 +280,13 @@ def test_strftime(self):
         self.assertEqual(utils.strftime(d, '%d/%m/%Y Øl trinken beim Besäufnis'),
                          '29/08/2012 Øl trinken beim Besäufnis')
 
+        # alternative formatting options
+        self.assertEqual(utils.strftime(d, '%-d/%-m/%y'), '29/8/12')
+        self.assertEqual(utils.strftime(d, '%-H:%-M:%-S'), '0:0:0')
+
+        d = utils.SafeDatetime(2012, 8, 9)
+        self.assertEqual(utils.strftime(d, '%-d/%-m/%y'), '9/8/12')
+
 
     # test the output of utils.strftime in a different locale
     # Turkish locale