[FIX] res.lang: disallow non cross-platform datetime format directives
bzr revid: odo@openerp.com-20110112160608-ixrjyfsgib31nnx8
This commit is contained in:
parent
9367e29205
commit
4cc899b5a8
|
@ -19,18 +19,22 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
import locale
|
||||
import logging
|
||||
|
||||
from osv import fields, osv
|
||||
from locale import localeconv
|
||||
import tools
|
||||
from tools.safe_eval import safe_eval as eval
|
||||
from tools.translate import _
|
||||
import locale
|
||||
import logging
|
||||
|
||||
class lang(osv.osv):
|
||||
_name = "res.lang"
|
||||
_description = "Languages"
|
||||
|
||||
_disallowed_datetime_patterns = tools.DATETIME_FORMATS_MAP.keys()
|
||||
_disallowed_datetime_patterns.remove('%y') # this one is in fact allowed, just not good practice
|
||||
|
||||
def install_lang(self, cr, uid, **args):
|
||||
lang = tools.config.get('lang')
|
||||
if not lang:
|
||||
|
@ -73,13 +77,14 @@ class lang(osv.osv):
|
|||
return '\xc2\xa0'
|
||||
return s
|
||||
|
||||
def fix_time_format(format):
|
||||
"""Python's strftime does not support all the compound formats
|
||||
from C's strftime, as returned by locale.nl_langinfo().
|
||||
Under Ubuntu at least, we encounter %T or %r for some locales."""
|
||||
format = format.replace('%T', '%H:%M:%S')\
|
||||
.replace('%r', '%I:%M:%S %p')\
|
||||
.replace('%R', '%H:%M')
|
||||
def fix_datetime_format(format):
|
||||
"""Python's strftime supports only the format directives
|
||||
that are available on the platform's libc, so in order to
|
||||
be 100% cross-platform we map to the directives required by
|
||||
the C standard (1989 version), always available on platforms
|
||||
with a C standard implementation."""
|
||||
for pattern, replacement in tools.DATETIME_FORMATS_MAP.iteritems():
|
||||
format = format.replace(pattern, replacement)
|
||||
return str(format)
|
||||
|
||||
lang_info = {
|
||||
|
@ -87,8 +92,8 @@ class lang(osv.osv):
|
|||
'iso_code': iso_lang,
|
||||
'name': lang_name,
|
||||
'translatable': 1,
|
||||
'date_format' : str(locale.nl_langinfo(locale.D_FMT).replace('%y', '%Y')),
|
||||
'time_format' : fix_time_format(locale.nl_langinfo(locale.T_FMT)),
|
||||
'date_format' : fix_datetime_format(locale.nl_langinfo(locale.D_FMT)),
|
||||
'time_format' : fix_datetime_format(locale.nl_langinfo(locale.T_FMT)),
|
||||
'decimal_point' : fix_xa0(str(locale.localeconv()['decimal_point'])),
|
||||
'thousands_sep' : fix_xa0(str(locale.localeconv()['thousands_sep'])),
|
||||
}
|
||||
|
@ -99,6 +104,14 @@ class lang(osv.osv):
|
|||
tools.resetlocale()
|
||||
return lang_id
|
||||
|
||||
def _check_format(self, cr, uid, ids, context=None):
|
||||
for lang in self.browse(cr, uid, ids, context=context):
|
||||
for pattern in self._disallowed_datetime_patterns:
|
||||
if (lang.time_format and pattern in lang.time_format)\
|
||||
or (lang.date_format and pattern in lang.date_format):
|
||||
return False
|
||||
return True
|
||||
|
||||
def _get_default_date_format(self,cursor,user,context={}):
|
||||
return '%m/%d/%Y'
|
||||
|
||||
|
@ -133,6 +146,10 @@ class lang(osv.osv):
|
|||
('code_uniq', 'unique (code)', 'The code of the language must be unique !'),
|
||||
]
|
||||
|
||||
_constraints = [
|
||||
(_check_format, 'Invalid date/time format directive specified. Please refer to the list of allowed directives, displayed when you edit a language.', ['time_format', 'date_format'])
|
||||
]
|
||||
|
||||
@tools.cache(skiparg=3)
|
||||
def _lang_data_get(self, cr, uid, lang_id, monetary=False):
|
||||
conv = localeconv()
|
||||
|
|
|
@ -1352,6 +1352,51 @@ DEFAULT_SERVER_DATETIME_FORMAT = "%s %s" % (
|
|||
DEFAULT_SERVER_DATE_FORMAT,
|
||||
DEFAULT_SERVER_TIME_FORMAT)
|
||||
|
||||
# Python's strftime supports only the format directives
|
||||
# that are available on the platform's libc, so in order to
|
||||
# be cross-platform we map to the directives required by
|
||||
# the C standard (1989 version), always available on platforms
|
||||
# with a C standard implementation.
|
||||
DATETIME_FORMATS_MAP = {
|
||||
'%C': '', # century
|
||||
'%D': '%m/%d/%Y', # modified %y->%Y
|
||||
'%e': '%d',
|
||||
'%E': '', # special modifier
|
||||
'%F': '%Y-%m-%d',
|
||||
'%g': '%Y', # modified %y->%Y
|
||||
'%G': '%Y',
|
||||
'%h': '%b',
|
||||
'%k': '%H',
|
||||
'%l': '%I',
|
||||
'%n': '\n',
|
||||
'%O': '', # special modifier
|
||||
'%P': '%p',
|
||||
'%R': '%H:%M',
|
||||
'%r': '%I:%M:%S %p',
|
||||
'%s': '', #num of seconds since epoch
|
||||
'%T': '%H:%M:%S',
|
||||
'%t': ' ', # tab
|
||||
'%u': ' %w',
|
||||
'%V': '%W',
|
||||
'%y': '%Y', # Even if %y works, it's ambiguous, so we should use %Y
|
||||
'%+': '%Y-%m-%d %H:%M:%S',
|
||||
|
||||
# %Z is a special case that causes 2 problems at least:
|
||||
# - the timezone names we use (in res_user.context_tz) come
|
||||
# from pytz, but not all these names are recognized by
|
||||
# strptime(), so we cannot convert in both directions
|
||||
# when such a timezone is selected and %Z is in the format
|
||||
# - %Z is replaced by an empty string in strftime() when
|
||||
# there is not tzinfo in a datetime value (e.g when the user
|
||||
# did not pick a context_tz). The resulting string does not
|
||||
# parse back if the format requires %Z.
|
||||
# As a consequence, we strip it completely from format strings.
|
||||
# The user can always have a look at the context_tz in
|
||||
# preferences to check the timezone.
|
||||
'%z': '',
|
||||
'%Z': '',
|
||||
}
|
||||
|
||||
def server_to_local_timestamp(src_tstamp_str, src_format, dst_format, dst_tz_name,
|
||||
tz_offset=True, ignore_unparsable_time=True):
|
||||
"""
|
||||
|
|
Loading…
Reference in New Issue