changeset 2599:5b26033c49a8

tools (common): moved date_fmt function from template filters to new date_utils module, so it can be used everywhere.
author Goffi <goffi@goffi.org>
date Fri, 01 Jun 2018 12:04:06 +0200
parents 0b6adc2672d9
children 947c4c4c5c53
files sat/core/constants.py sat/tools/common/date_utils.py sat/tools/common/template.py
diffstat 3 files changed, 99 insertions(+), 73 deletions(-) [+]
line wrap: on
line diff
--- a/sat/core/constants.py	Fri Jun 01 12:02:09 2018 +0200
+++ b/sat/core/constants.py	Fri Jun 01 12:04:06 2018 +0200
@@ -368,6 +368,10 @@
     KEY_PROGRESS_ID = u'progress_id'
 
 
+    #internationalisation
+    DEFAULT_LOCALE = u'en_GB'
+
+
     ## Misc ##
     SAVEFILE_DATABASE = APP_NAME_FILE + ".db"
     IQ_SET = '/iq[@type="set"]'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat/tools/common/date_utils.py	Fri Jun 01 12:04:06 2018 +0200
@@ -0,0 +1,84 @@
+#!/usr/bin/env python2
+# -*- coding: utf-8 -*-
+
+# SAT: a jabber client
+# Copyright (C) 2009-2018 Jérôme Poisson (goffi@goffi.org)
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""tools to help manipulating time and dates"""
+
+from sat.core.constants import Const as C
+import datetime
+from babel import dates
+import time
+
+
+def date_fmt(timestamp, fmt='short', date_only=False, auto_limit=7, auto_old_fmt='short', auto_new_fmt='relative', locale_str=C.DEFAULT_LOCALE):
+    """format date according to locale
+
+    @param timestamp(basestring, int): unix time
+    @param fmt(str): one of:
+        - short: e.g. u'31/12/17'
+        - medium: e.g. u'Apr 1, 2007'
+        - long: e.g. u'April 1, 2007'
+        - full: e.g. u'Sunday, April 1, 2007'
+        - relative: format in relative time
+            e.g.: 3 hours
+            note that this format is not precise
+        - iso: ISO 8601 format
+            e.g.: u'2007-04-01T19:53:23Z'
+        - auto: use auto_old_fmt if date is older than auto_limit
+            else use auto_new_fmt
+        - auto_day: shorcut to set auto format with change on day
+            old format will be short, and new format will be time only
+        or a free value which is passed to babel.dates.format_datetime
+    @param date_only(bool): if True, only display date (not datetime)
+    @param auto_limit (int): limit in days before using auto_old_fmt
+        use 0 to have a limit at last midnight (day change)
+    @param auto_old_fmt(unicode): format to use when date is older than limit
+    @param auto_new_fmt(unicode): format to use when date is equal to or more recent
+        than limit
+
+    """
+    if fmt == 'auto_day':
+        fmt, auto_limit, auto_old_fmt, auto_new_fmt = 'auto', 0, 'short', 'HH:mm'
+    if fmt == 'auto':
+        if auto_limit == 0:
+            today = time.mktime(datetime.date.today().timetuple())
+            if int(timestamp) < today:
+                fmt = auto_old_fmt
+            else:
+                fmt = auto_new_fmt
+        else:
+            days_delta = (time.time() - int(timestamp)) / 3600
+            if days_delta > (auto_limit or 7):
+                fmt = auto_old_fmt
+            else:
+                fmt = auto_new_fmt
+
+    if fmt == 'relative':
+        delta = int(timestamp) - time.time()
+        return dates.format_timedelta(delta, granularity="minute", add_direction=True, locale=locale_str)
+    elif fmt in ('short', 'long'):
+        formatter = dates.format_date if date_only else dates.format_datetime
+        return formatter(int(timestamp), format=fmt, locale=locale_str)
+    elif fmt == 'iso':
+        if date_only:
+            fmt = 'yyyy-MM-dd'
+        else:
+            fmt = "yyyy-MM-ddTHH:mm:ss'Z'"
+        return dates.format_datetime(int(timestamp), format=fmt)
+    else:
+        return dates.format_datetime(int(timestamp), format=fmt, locale=locale_str)
--- a/sat/tools/common/template.py	Fri Jun 01 12:02:09 2018 +0200
+++ b/sat/tools/common/template.py	Fri Jun 01 12:04:06 2018 +0200
@@ -22,17 +22,16 @@
 from sat.core.constants import Const as C
 from sat.core.i18n import _
 from sat.core import exceptions
+from sat.tools.common import date_utils
 from sat.core.log import getLogger
 log = getLogger(__name__)
 import os.path
 from xml.sax.saxutils import quoteattr
-import datetime
 import time
 import re
 from babel import support
 from babel import Locale
 from babel.core import UnknownLocaleError
-from babel import dates
 import pygments
 from pygments import lexers
 from pygments import formatters
@@ -53,7 +52,6 @@
 from lxml import etree
 
 HTML_EXT = ('html', 'xhtml')
-DEFAULT_LOCALE = u'en_GB'
 RE_ATTR_ESCAPE = re.compile(r'[^a-z_-]')
 # TODO: handle external path (an additional search path for templates should be settable by user
 # TODO: handle absolute URL (should be used for trusted use cases) only (e.g. jp) for security reason
@@ -205,7 +203,7 @@
             lstrip_blocks=True,
             extensions=['jinja2.ext.i18n'],
             )
-        self._locale_str = DEFAULT_LOCALE
+        self._locale_str = C.DEFAULT_LOCALE
         self._locale = Locale.parse(self._locale_str)
         self.installTranslations()
         # we want to have access to SàT constants in templates
@@ -258,22 +256,22 @@
             locale = Locale.parse(locale_str)
         except ValueError as e:
             log.warning(_(u"invalid locale value: {msg}").format(msg=e))
-            locale_str = self._locale_str = DEFAULT_LOCALE
+            locale_str = self._locale_str = C.DEFAULT_LOCALE
             locale = Locale.parse(locale_str)
 
         locale_str = unicode(locale)
-        if locale_str != DEFAULT_LOCALE:
+        if locale_str != C.DEFAULT_LOCALE:
             try:
                 translations = self.translations[locale]
             except KeyError:
                 log.warning(_(u"Can't find locale {locale}".format(locale=locale)))
-                locale_str = DEFAULT_LOCALE
+                locale_str = C.DEFAULT_LOCALE
                 locale = Locale.parse(self._locale_str)
             else:
                 self.env.install_gettext_translations(translations, True)
                 log.debug(_(u'Switched to {lang}').format(lang=locale.english_name))
 
-        if locale_str == DEFAULT_LOCALE:
+        if locale_str == C.DEFAULT_LOCALE:
             self.env.install_null_translations(True)
 
         self._locale = locale
@@ -366,75 +364,15 @@
         return value if not current else u"{}_{}".format(value, current)
 
     def _date_fmt(self, timestamp, fmt='short', date_only=False, auto_limit=None, auto_old_fmt=None):
+        if is_undefined(fmt):
+            fmt = u'short'
+
         try:
-            return self.date_fmt(timestamp, fmt, date_only, auto_limit, auto_old_fmt)
+            return date_utils.date_fmt(timestamp, fmt, date_only, auto_limit, auto_old_fmt)
         except Exception as e:
             log.warning(_(u"Can't parse date: {msg}").format(msg=e))
             return timestamp
 
-    def date_fmt(self, timestamp, fmt='short', date_only=False, auto_limit=7, auto_old_fmt='short', auto_new_fmt='relative'):
-        """format date according to locale
-
-        @param timestamp(basestring, int): unix time
-        @param fmt(str): one of:
-            - short: e.g. u'31/12/17'
-            - medium: e.g. u'Apr 1, 2007'
-            - long: e.g. u'April 1, 2007'
-            - full: e.g. u'Sunday, April 1, 2007'
-            - relative: format in relative time
-                e.g.: 3 hours
-                note that this format is not precise
-            - iso: ISO 8601 format
-                e.g.: u'2007-04-01T19:53:23Z'
-            - auto: use auto_old_fmt if date is older than auto_limit
-                else use auto_new_fmt
-            - auto_day: shorcut to set auto format with change on day
-                old format will be short, and new format will be time only
-            or a free value which is passed to babel.dates.format_datetime
-        @param date_only(bool): if True, only display date (not datetime)
-        @param auto_limit (int): limit in days before using auto_old_fmt
-            use 0 to have a limit at last midnight (day change)
-        @param auto_old_fmt(unicode): format to use when date is older than limit
-        @param auto_new_fmt(unicode): format to use when date is equal to or more recent
-            than limit
-
-        """
-        if is_undefined(fmt):
-            fmt = u'short'
-
-        if (auto_limit is not None or auto_old_fmt is not None) and fmt != 'auto':
-            raise ValueError(u'auto argument can only be used with auto fmt')
-        if fmt == 'auto_day':
-            fmt, auto_limit, auto_old_fmt, auto_new_fmt = 'auto', 0, 'short', 'HH:mm'
-        if fmt == 'auto':
-            if auto_limit == 0:
-                today = time.mktime(datetime.date.today().timetuple())
-                if int(timestamp) < today:
-                    fmt = auto_old_fmt
-                else:
-                    fmt = auto_new_fmt
-            else:
-                days_delta = (time.time() - int(timestamp)) / 3600
-                if days_delta > (auto_limit or 7):
-                    fmt = auto_old_fmt
-                else:
-                    fmt = auto_new_fmt
-
-        if fmt == 'relative':
-            delta = int(timestamp) - time.time()
-            return dates.format_timedelta(delta, granularity="minute", add_direction=True, locale=self._locale_str)
-        elif fmt in ('short', 'long'):
-            formatter = dates.format_date if date_only else dates.format_datetime
-            return formatter(int(timestamp), format=fmt, locale=self._locale_str)
-        elif fmt == 'iso':
-            if date_only:
-                fmt = 'yyyy-MM-dd'
-            else:
-                fmt = "yyyy-MM-ddTHH:mm:ss'Z'"
-            return dates.format_datetime(int(timestamp), format=fmt)
-        else:
-            return dates.format_datetime(int(timestamp), format=fmt, locale=self._locale_str)
-
     def attr_escape(self, text):
         """escape a text to a value usable as an attribute
 
@@ -595,7 +533,7 @@
             name=name,
             cls=(' ' + cls) if cls else ''))
 
-    def render(self, template, theme=None, locale=DEFAULT_LOCALE, root_path=u'', media_path=u'', css_files=None, css_inline=False, **kwargs):
+    def render(self, template, theme=None, locale=C.DEFAULT_LOCALE, root_path=u'', media_path=u'', css_files=None, css_inline=False, **kwargs):
         """render a template
 .
         @param template(unicode): template to render (e.g. blog/articles.html)