We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Datetime shown not localized.
As one of my student complaints, his browser is using en_US locale, however, the datetime shown in RELATE is in zh_CN format. Although he can understand Chinese, however, that will cause problem in other circumstances. 

The reason of problem lies in [this PR](https://github.com/inducer/relate/pull/39) I provided. It uses setting.LANGUAGE_CODE to determine the locale show in browser. 

I found I've made it too complicated in that PR, and it quite simple to modify that method using built-in method `django.utils.formats`, and the result is itself locale aware.

I'll create a PR later to fix it.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `relate/utils.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 
3 from __future__ import division
4 
5 __copyright__ = "Copyright (C) 2014 Andreas Kloeckner"
6 
7 __license__ = """
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14 
15 The above copyright notice and this permission notice shall be included in
16 all copies or substantial portions of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 THE SOFTWARE.
25 """
26 
27 
28 import six
29 import django.forms as forms
30 
31 
32 class StyledForm(forms.Form):
33     def __init__(self, *args, **kwargs):
34         from crispy_forms.helper import FormHelper
35         self.helper = FormHelper()
36         self.helper.form_class = "form-horizontal"
37         self.helper.label_class = "col-lg-2"
38         self.helper.field_class = "col-lg-8"
39 
40         super(StyledForm, self).__init__(*args, **kwargs)
41 
42 
43 class StyledInlineForm(forms.Form):
44     def __init__(self, *args, **kwargs):
45         from crispy_forms.helper import FormHelper
46         self.helper = FormHelper()
47         self.helper.form_class = "form-inline"
48         self.helper.label_class = "sr-only"
49 
50         super(StyledInlineForm, self).__init__(*args, **kwargs)
51 
52 
53 class StyledModelForm(forms.ModelForm):
54     def __init__(self, *args, **kwargs):
55         from crispy_forms.helper import FormHelper
56         self.helper = FormHelper()
57         self.helper.form_class = "form-horizontal"
58         self.helper.label_class = "col-lg-2"
59         self.helper.field_class = "col-lg-8"
60 
61         super(StyledModelForm, self).__init__(*args, **kwargs)
62 
63 
64 def settings_context_processor(request):
65     from django.conf import settings
66     return {
67         "student_sign_in_view": "relate-sign_in_choice",
68         "relate_sign_in_by_email_enabled":
69         settings.RELATE_SIGN_IN_BY_EMAIL_ENABLED,
70         "relate_registration_enabled":
71         settings.RELATE_REGISTRATION_ENABLED,
72         "relate_sign_in_by_exam_tickets_enabled":
73         settings.RELATE_SIGN_IN_BY_EXAM_TICKETS_ENABLED,
74         "relate_sign_in_by_saml2_enabled":
75         settings.RELATE_SIGN_IN_BY_SAML2_ENABLED,
76         "maintenance_mode": settings.RELATE_MAINTENANCE_MODE,
77         "site_announcement": getattr(settings, "RELATE_SITE_ANNOUNCEMENT", None),
78         }
79 
80 
81 def as_local_time(datetime):
82     """Takes an timezone-aware datetime and applies the server timezone."""
83     from django.conf import settings
84     from pytz import timezone
85     tz = timezone(settings.TIME_ZONE)
86     return datetime.astimezone(tz)
87 
88 
89 def localize_datetime(datetime):
90     """Takes an timezone-naive datetime and applies the server timezone."""
91     from django.conf import settings
92     from pytz import timezone
93     tz = timezone(settings.TIME_ZONE)
94     return tz.localize(datetime)
95 
96 
97 def local_now():
98     from django.conf import settings
99     from pytz import timezone
100     tz = timezone(settings.TIME_ZONE)
101     from datetime import datetime
102     return tz.localize(datetime.now())
103 
104 
105 def format_datetime_local(datetime, format='medium'):
106     """Format the output of a datetime object to a localized string"""
107     from babel.dates import format_datetime
108     from django.conf import settings
109     from django.utils.translation.trans_real import to_locale
110     # See http://babel.pocoo.org/docs/api/dates/#date-and-time-formatting
111     # for customizing the output format.
112     try:
113         locale = to_locale(settings.LANGUAGE_CODE)
114     except ValueError:
115         locale = "en_US"
116 
117     result = format_datetime(datetime, format, locale=locale)
118 
119     return result
120 
121 
122 # {{{ dict_to_struct
123 
124 class Struct(object):
125     def __init__(self, entries):
126         for name, val in six.iteritems(entries):
127             self.__dict__[name] = val
128 
129     def __repr__(self):
130         return repr(self.__dict__)
131 
132 
133 def dict_to_struct(data):
134     if isinstance(data, list):
135         return [dict_to_struct(d) for d in data]
136     elif isinstance(data, dict):
137         return Struct({k: dict_to_struct(v) for k, v in six.iteritems(data)})
138     else:
139         return data
140 
141 
142 def struct_to_dict(data):
143     return dict(
144             (name, val)
145             for name, val in six.iteritems(data.__dict__)
146             if not name.startswith("_"))
147 
148 # }}}
149 
150 
151 def retry_transaction(f, args, kwargs={}, max_tries=None, serializable=None):
152     from django.db import transaction
153     from django.db.utils import OperationalError
154 
155     if max_tries is None:
156         max_tries = 5
157     if serializable is None:
158         serializable = False
159 
160     assert max_tries > 0
161     while True:
162         try:
163             with transaction.atomic():
164                 if serializable:
165                     from django.db import connections, DEFAULT_DB_ALIAS
166                     conn = connections[DEFAULT_DB_ALIAS]
167                     if conn.vendor == "postgresql":
168                         cursor = conn.cursor()
169                         cursor.execute(
170                                 "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;")
171 
172                 return f(*args, **kwargs)
173         except OperationalError:
174             max_tries -= 1
175             if not max_tries:
176                 raise
177 
178 
179 class retry_transaction_decorator(object):
180     def __init__(self, max_tries=None, serializable=None):
181         self.max_tries = max_tries
182         self.serializable = serializable
183 
184     def __call__(self, f):
185         from functools import update_wrapper
186 
187         def wrapper(*args, **kwargs):
188             return retry_transaction(f, args, kwargs,
189                     max_tries=self.max_tries,
190                     serializable=self.serializable)
191 
192         update_wrapper(wrapper, f)
193         return wrapper
194 
195 
196 # {{{ hang debugging
197 
198 def dumpstacks(signal, frame):
199     import threading
200     import sys
201     import traceback
202 
203     id2name = dict([(th.ident, th.name) for th in threading.enumerate()])
204     code = []
205     for threadId, stack in sys._current_frames().items():
206         code.append("\n# Thread: %s(%d)" % (id2name.get(threadId, ""), threadId))
207         for filename, lineno, name, line in traceback.extract_stack(stack):
208             code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
209             if line:
210                 code.append("  %s" % (line.strip()))
211     print("\n".join(code))
212 
213 if 0:
214     import signal
215     import os
216     print("*** HANG DUMP HANDLER ACTIVATED: 'kill -USR1 %s' to dump stacks"
217             % os.getpid())
218     signal.signal(signal.SIGUSR1, dumpstacks)
219 
220 # }}}
221 
222 
223 # {{{ convert django language name to js styled language name
224 
225 def to_js_lang_name(dj_lang_name):
226     """
227     Turns a django language name (en-us) into a js styled language
228     name (en-US).
229     """
230     p = dj_lang_name.find('-')
231     if p >= 0:
232         return dj_lang_name[:p].lower() + '-' + dj_lang_name[p + 1:].upper()
233     else:
234         return dj_lang_name.lower()
235 
236 # }}}
237 
238 # vim: foldmethod=marker
239
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/relate/utils.py b/relate/utils.py
--- a/relate/utils.py
+++ b/relate/utils.py
@@ -102,21 +102,29 @@
     return tz.localize(datetime.now())
 
 
-def format_datetime_local(datetime, format='medium'):
-    """Format the output of a datetime object to a localized string"""
-    from babel.dates import format_datetime
-    from django.conf import settings
-    from django.utils.translation.trans_real import to_locale
-    # See http://babel.pocoo.org/docs/api/dates/#date-and-time-formatting
-    # for customizing the output format.
-    try:
-        locale = to_locale(settings.LANGUAGE_CODE)
-    except ValueError:
-        locale = "en_US"
+def format_datetime_local(datetime, format='DATETIME_FORMAT'):
+    """
+    Format a datetime object to a localized string via python.
+
+    Note: The datetime rendered in template is itself locale aware.
+    A custom format must be defined in settings.py. 
+    When a custom format uses a same name with an existing built-in
+    format, it will be overrided by built-in format if l10n
+    is enabled.
+    """
+
+    fmt = format
 
-    result = format_datetime(datetime, format, locale=locale)
+    from django.utils import formats
+    from django.utils.dateformat import format
 
-    return result
+    try:
+        return formats.date_format(datetime, fmt)
+    except AttributeError:
+        try:
+            return format(datetime, fmt)
+        except AttributeError:
+            return formats.date_format(datetime, "DATETIME_FORMAT")
 
 
 # {{{ dict_to_struct

{"golden_diff": "diff --git a/relate/utils.py b/relate/utils.py\n--- a/relate/utils.py\n+++ b/relate/utils.py\n@@ -102,21 +102,29 @@\n     return tz.localize(datetime.now())\n \n \n-def format_datetime_local(datetime, format='medium'):\n-    \"\"\"Format the output of a datetime object to a localized string\"\"\"\n-    from babel.dates import format_datetime\n-    from django.conf import settings\n-    from django.utils.translation.trans_real import to_locale\n-    # See http://babel.pocoo.org/docs/api/dates/#date-and-time-formatting\n-    # for customizing the output format.\n-    try:\n-        locale = to_locale(settings.LANGUAGE_CODE)\n-    except ValueError:\n-        locale = \"en_US\"\n+def format_datetime_local(datetime, format='DATETIME_FORMAT'):\n+    \"\"\"\n+    Format a datetime object to a localized string via python.\n+\n+    Note: The datetime rendered in template is itself locale aware.\n+    A custom format must be defined in settings.py. \n+    When a custom format uses a same name with an existing built-in\n+    format, it will be overrided by built-in format if l10n\n+    is enabled.\n+    \"\"\"\n+\n+    fmt = format\n \n-    result = format_datetime(datetime, format, locale=locale)\n+    from django.utils import formats\n+    from django.utils.dateformat import format\n \n-    return result\n+    try:\n+        return formats.date_format(datetime, fmt)\n+    except AttributeError:\n+        try:\n+            return format(datetime, fmt)\n+        except AttributeError:\n+            return formats.date_format(datetime, \"DATETIME_FORMAT\")\n \n \n # {{{ dict_to_struct\n", "issue": "Datetime shown not localized.\nAs one of my student complaints, his browser is using en_US locale, however, the datetime shown in RELATE is in zh_CN format. Although he can understand Chinese, however, that will cause problem in other circumstances. \n\nThe reason of problem lies in [this PR](https://github.com/inducer/relate/pull/39) I provided. It uses setting.LANGUAGE_CODE to determine the locale show in browser. \n\nI found I've made it too complicated in that PR, and it quite simple to modify that method using built-in method `django.utils.formats`, and the result is itself locale aware.\n\nI'll create a PR later to fix it.\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\nfrom __future__ import division\n\n__copyright__ = \"Copyright (C) 2014 Andreas Kloeckner\"\n\n__license__ = \"\"\"\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\"\"\"\n\n\nimport six\nimport django.forms as forms\n\n\nclass StyledForm(forms.Form):\n    def __init__(self, *args, **kwargs):\n        from crispy_forms.helper import FormHelper\n        self.helper = FormHelper()\n        self.helper.form_class = \"form-horizontal\"\n        self.helper.label_class = \"col-lg-2\"\n        self.helper.field_class = \"col-lg-8\"\n\n        super(StyledForm, self).__init__(*args, **kwargs)\n\n\nclass StyledInlineForm(forms.Form):\n    def __init__(self, *args, **kwargs):\n        from crispy_forms.helper import FormHelper\n        self.helper = FormHelper()\n        self.helper.form_class = \"form-inline\"\n        self.helper.label_class = \"sr-only\"\n\n        super(StyledInlineForm, self).__init__(*args, **kwargs)\n\n\nclass StyledModelForm(forms.ModelForm):\n    def __init__(self, *args, **kwargs):\n        from crispy_forms.helper import FormHelper\n        self.helper = FormHelper()\n        self.helper.form_class = \"form-horizontal\"\n        self.helper.label_class = \"col-lg-2\"\n        self.helper.field_class = \"col-lg-8\"\n\n        super(StyledModelForm, self).__init__(*args, **kwargs)\n\n\ndef settings_context_processor(request):\n    from django.conf import settings\n    return {\n        \"student_sign_in_view\": \"relate-sign_in_choice\",\n        \"relate_sign_in_by_email_enabled\":\n        settings.RELATE_SIGN_IN_BY_EMAIL_ENABLED,\n        \"relate_registration_enabled\":\n        settings.RELATE_REGISTRATION_ENABLED,\n        \"relate_sign_in_by_exam_tickets_enabled\":\n        settings.RELATE_SIGN_IN_BY_EXAM_TICKETS_ENABLED,\n        \"relate_sign_in_by_saml2_enabled\":\n        settings.RELATE_SIGN_IN_BY_SAML2_ENABLED,\n        \"maintenance_mode\": settings.RELATE_MAINTENANCE_MODE,\n        \"site_announcement\": getattr(settings, \"RELATE_SITE_ANNOUNCEMENT\", None),\n        }\n\n\ndef as_local_time(datetime):\n    \"\"\"Takes an timezone-aware datetime and applies the server timezone.\"\"\"\n    from django.conf import settings\n    from pytz import timezone\n    tz = timezone(settings.TIME_ZONE)\n    return datetime.astimezone(tz)\n\n\ndef localize_datetime(datetime):\n    \"\"\"Takes an timezone-naive datetime and applies the server timezone.\"\"\"\n    from django.conf import settings\n    from pytz import timezone\n    tz = timezone(settings.TIME_ZONE)\n    return tz.localize(datetime)\n\n\ndef local_now():\n    from django.conf import settings\n    from pytz import timezone\n    tz = timezone(settings.TIME_ZONE)\n    from datetime import datetime\n    return tz.localize(datetime.now())\n\n\ndef format_datetime_local(datetime, format='medium'):\n    \"\"\"Format the output of a datetime object to a localized string\"\"\"\n    from babel.dates import format_datetime\n    from django.conf import settings\n    from django.utils.translation.trans_real import to_locale\n    # See http://babel.pocoo.org/docs/api/dates/#date-and-time-formatting\n    # for customizing the output format.\n    try:\n        locale = to_locale(settings.LANGUAGE_CODE)\n    except ValueError:\n        locale = \"en_US\"\n\n    result = format_datetime(datetime, format, locale=locale)\n\n    return result\n\n\n# {{{ dict_to_struct\n\nclass Struct(object):\n    def __init__(self, entries):\n        for name, val in six.iteritems(entries):\n            self.__dict__[name] = val\n\n    def __repr__(self):\n        return repr(self.__dict__)\n\n\ndef dict_to_struct(data):\n    if isinstance(data, list):\n        return [dict_to_struct(d) for d in data]\n    elif isinstance(data, dict):\n        return Struct({k: dict_to_struct(v) for k, v in six.iteritems(data)})\n    else:\n        return data\n\n\ndef struct_to_dict(data):\n    return dict(\n            (name, val)\n            for name, val in six.iteritems(data.__dict__)\n            if not name.startswith(\"_\"))\n\n# }}}\n\n\ndef retry_transaction(f, args, kwargs={}, max_tries=None, serializable=None):\n    from django.db import transaction\n    from django.db.utils import OperationalError\n\n    if max_tries is None:\n        max_tries = 5\n    if serializable is None:\n        serializable = False\n\n    assert max_tries > 0\n    while True:\n        try:\n            with transaction.atomic():\n                if serializable:\n                    from django.db import connections, DEFAULT_DB_ALIAS\n                    conn = connections[DEFAULT_DB_ALIAS]\n                    if conn.vendor == \"postgresql\":\n                        cursor = conn.cursor()\n                        cursor.execute(\n                                \"SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;\")\n\n                return f(*args, **kwargs)\n        except OperationalError:\n            max_tries -= 1\n            if not max_tries:\n                raise\n\n\nclass retry_transaction_decorator(object):\n    def __init__(self, max_tries=None, serializable=None):\n        self.max_tries = max_tries\n        self.serializable = serializable\n\n    def __call__(self, f):\n        from functools import update_wrapper\n\n        def wrapper(*args, **kwargs):\n            return retry_transaction(f, args, kwargs,\n                    max_tries=self.max_tries,\n                    serializable=self.serializable)\n\n        update_wrapper(wrapper, f)\n        return wrapper\n\n\n# {{{ hang debugging\n\ndef dumpstacks(signal, frame):\n    import threading\n    import sys\n    import traceback\n\n    id2name = dict([(th.ident, th.name) for th in threading.enumerate()])\n    code = []\n    for threadId, stack in sys._current_frames().items():\n        code.append(\"\\n# Thread: %s(%d)\" % (id2name.get(threadId, \"\"), threadId))\n        for filename, lineno, name, line in traceback.extract_stack(stack):\n            code.append('File: \"%s\", line %d, in %s' % (filename, lineno, name))\n            if line:\n                code.append(\"  %s\" % (line.strip()))\n    print(\"\\n\".join(code))\n\nif 0:\n    import signal\n    import os\n    print(\"*** HANG DUMP HANDLER ACTIVATED: 'kill -USR1 %s' to dump stacks\"\n            % os.getpid())\n    signal.signal(signal.SIGUSR1, dumpstacks)\n\n# }}}\n\n\n# {{{ convert django language name to js styled language name\n\ndef to_js_lang_name(dj_lang_name):\n    \"\"\"\n    Turns a django language name (en-us) into a js styled language\n    name (en-US).\n    \"\"\"\n    p = dj_lang_name.find('-')\n    if p >= 0:\n        return dj_lang_name[:p].lower() + '-' + dj_lang_name[p + 1:].upper()\n    else:\n        return dj_lang_name.lower()\n\n# }}}\n\n# vim: foldmethod=marker\n", "path": "relate/utils.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\nfrom __future__ import division\n\n__copyright__ = \"Copyright (C) 2014 Andreas Kloeckner\"\n\n__license__ = \"\"\"\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\"\"\"\n\n\nimport six\nimport django.forms as forms\n\n\nclass StyledForm(forms.Form):\n    def __init__(self, *args, **kwargs):\n        from crispy_forms.helper import FormHelper\n        self.helper = FormHelper()\n        self.helper.form_class = \"form-horizontal\"\n        self.helper.label_class = \"col-lg-2\"\n        self.helper.field_class = \"col-lg-8\"\n\n        super(StyledForm, self).__init__(*args, **kwargs)\n\n\nclass StyledInlineForm(forms.Form):\n    def __init__(self, *args, **kwargs):\n        from crispy_forms.helper import FormHelper\n        self.helper = FormHelper()\n        self.helper.form_class = \"form-inline\"\n        self.helper.label_class = \"sr-only\"\n\n        super(StyledInlineForm, self).__init__(*args, **kwargs)\n\n\nclass StyledModelForm(forms.ModelForm):\n    def __init__(self, *args, **kwargs):\n        from crispy_forms.helper import FormHelper\n        self.helper = FormHelper()\n        self.helper.form_class = \"form-horizontal\"\n        self.helper.label_class = \"col-lg-2\"\n        self.helper.field_class = \"col-lg-8\"\n\n        super(StyledModelForm, self).__init__(*args, **kwargs)\n\n\ndef settings_context_processor(request):\n    from django.conf import settings\n    return {\n        \"student_sign_in_view\": \"relate-sign_in_choice\",\n        \"relate_sign_in_by_email_enabled\":\n        settings.RELATE_SIGN_IN_BY_EMAIL_ENABLED,\n        \"relate_registration_enabled\":\n        settings.RELATE_REGISTRATION_ENABLED,\n        \"relate_sign_in_by_exam_tickets_enabled\":\n        settings.RELATE_SIGN_IN_BY_EXAM_TICKETS_ENABLED,\n        \"relate_sign_in_by_saml2_enabled\":\n        settings.RELATE_SIGN_IN_BY_SAML2_ENABLED,\n        \"maintenance_mode\": settings.RELATE_MAINTENANCE_MODE,\n        \"site_announcement\": getattr(settings, \"RELATE_SITE_ANNOUNCEMENT\", None),\n        }\n\n\ndef as_local_time(datetime):\n    \"\"\"Takes an timezone-aware datetime and applies the server timezone.\"\"\"\n    from django.conf import settings\n    from pytz import timezone\n    tz = timezone(settings.TIME_ZONE)\n    return datetime.astimezone(tz)\n\n\ndef localize_datetime(datetime):\n    \"\"\"Takes an timezone-naive datetime and applies the server timezone.\"\"\"\n    from django.conf import settings\n    from pytz import timezone\n    tz = timezone(settings.TIME_ZONE)\n    return tz.localize(datetime)\n\n\ndef local_now():\n    from django.conf import settings\n    from pytz import timezone\n    tz = timezone(settings.TIME_ZONE)\n    from datetime import datetime\n    return tz.localize(datetime.now())\n\n\ndef format_datetime_local(datetime, format='DATETIME_FORMAT'):\n    \"\"\"\n    Format a datetime object to a localized string via python.\n\n    Note: The datetime rendered in template is itself locale aware.\n    A custom format must be defined in settings.py. \n    When a custom format uses a same name with an existing built-in\n    format, it will be overrided by built-in format if l10n\n    is enabled.\n    \"\"\"\n\n    fmt = format\n\n    from django.utils import formats\n    from django.utils.dateformat import format\n\n    try:\n        return formats.date_format(datetime, fmt)\n    except AttributeError:\n        try:\n            return format(datetime, fmt)\n        except AttributeError:\n            return formats.date_format(datetime, \"DATETIME_FORMAT\")\n\n\n# {{{ dict_to_struct\n\nclass Struct(object):\n    def __init__(self, entries):\n        for name, val in six.iteritems(entries):\n            self.__dict__[name] = val\n\n    def __repr__(self):\n        return repr(self.__dict__)\n\n\ndef dict_to_struct(data):\n    if isinstance(data, list):\n        return [dict_to_struct(d) for d in data]\n    elif isinstance(data, dict):\n        return Struct({k: dict_to_struct(v) for k, v in six.iteritems(data)})\n    else:\n        return data\n\n\ndef struct_to_dict(data):\n    return dict(\n            (name, val)\n            for name, val in six.iteritems(data.__dict__)\n            if not name.startswith(\"_\"))\n\n# }}}\n\n\ndef retry_transaction(f, args, kwargs={}, max_tries=None, serializable=None):\n    from django.db import transaction\n    from django.db.utils import OperationalError\n\n    if max_tries is None:\n        max_tries = 5\n    if serializable is None:\n        serializable = False\n\n    assert max_tries > 0\n    while True:\n        try:\n            with transaction.atomic():\n                if serializable:\n                    from django.db import connections, DEFAULT_DB_ALIAS\n                    conn = connections[DEFAULT_DB_ALIAS]\n                    if conn.vendor == \"postgresql\":\n                        cursor = conn.cursor()\n                        cursor.execute(\n                                \"SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;\")\n\n                return f(*args, **kwargs)\n        except OperationalError:\n            max_tries -= 1\n            if not max_tries:\n                raise\n\n\nclass retry_transaction_decorator(object):\n    def __init__(self, max_tries=None, serializable=None):\n        self.max_tries = max_tries\n        self.serializable = serializable\n\n    def __call__(self, f):\n        from functools import update_wrapper\n\n        def wrapper(*args, **kwargs):\n            return retry_transaction(f, args, kwargs,\n                    max_tries=self.max_tries,\n                    serializable=self.serializable)\n\n        update_wrapper(wrapper, f)\n        return wrapper\n\n\n# {{{ hang debugging\n\ndef dumpstacks(signal, frame):\n    import threading\n    import sys\n    import traceback\n\n    id2name = dict([(th.ident, th.name) for th in threading.enumerate()])\n    code = []\n    for threadId, stack in sys._current_frames().items():\n        code.append(\"\\n# Thread: %s(%d)\" % (id2name.get(threadId, \"\"), threadId))\n        for filename, lineno, name, line in traceback.extract_stack(stack):\n            code.append('File: \"%s\", line %d, in %s' % (filename, lineno, name))\n            if line:\n                code.append(\"  %s\" % (line.strip()))\n    print(\"\\n\".join(code))\n\nif 0:\n    import signal\n    import os\n    print(\"*** HANG DUMP HANDLER ACTIVATED: 'kill -USR1 %s' to dump stacks\"\n            % os.getpid())\n    signal.signal(signal.SIGUSR1, dumpstacks)\n\n# }}}\n\n\n# {{{ convert django language name to js styled language name\n\ndef to_js_lang_name(dj_lang_name):\n    \"\"\"\n    Turns a django language name (en-us) into a js styled language\n    name (en-US).\n    \"\"\"\n    p = dj_lang_name.find('-')\n    if p >= 0:\n        return dj_lang_name[:p].lower() + '-' + dj_lang_name[p + 1:].upper()\n    else:\n        return dj_lang_name.lower()\n\n# }}}\n\n# vim: foldmethod=marker\n", "path": "relate/utils.py"}]}