Repository: getsentry/sentry

Issue:
Display dates in localized formats
Right now, we're always spitting out "AM/PM" style dates.

This is a bit annoying for users who use 24 hour time, for example. AKA, anyone not in the US. And me personally since I use 24 hour time. :)

I did some quick Googling, but couldn't figure out a reliable way to detect this. For example, on my computer:

``` javascript
> (new Date).toLocaleTimeString()
"3:49:17 PM"
```

/cc @mitsuhiko I feel like you might know this or have an opinion.



Discussion:
Just because you're not in the US doesnt mean you use 24 hour time. If anything this should be a configuration option.

Yeah, just generalizing to "whatever your locale is". If your locale is 24 hour, we should use 24 hr, and vice-versa.

Thanks for the reply Matt! My thought (in the getsentry feedback I posted) was that it could be a setting on the page where you set the timezone.

I believe that most of Europe uses 24 hour time, but I might be wrong about that.

I think we'd rather avoid adding a new setting just for that if it's able to be detected, personally.

IMO a setting is the right approach (I'm pretty sure you cant detect this in any friendly way). We already have a setting to choose locale, so a setting to choose time display seems fine.


Resolving patch:
diff --git a/src/sentry/api/serializers/models/user.py b/src/sentry/api/serializers/models/user.py
--- a/src/sentry/api/serializers/models/user.py
+++ b/src/sentry/api/serializers/models/user.py
@@ -37,6 +37,6 @@ def serialize(self, obj, attrs, user):
                 'language': options.get('language') or 'en',
                 'stacktraceOrder': stacktrace_order,
                 'timezone': options.get('timezone') or settings.SENTRY_DEFAULT_TIME_ZONE,
-
+                'clock24Hours': options.get('clock_24_hours') or False,
             }
         return d
diff --git a/src/sentry/web/forms/accounts.py b/src/sentry/web/forms/accounts.py
--- a/src/sentry/web/forms/accounts.py
+++ b/src/sentry/web/forms/accounts.py
@@ -335,6 +335,10 @@ class AppearanceSettingsForm(forms.Form):
     timezone = forms.ChoiceField(
         label=_('Time zone'), choices=TIMEZONE_CHOICES, required=False,
         widget=forms.Select(attrs={'class': 'input-xxlarge'}))
+    clock_24_hours = forms.BooleanField(
+        label=_('Use a 24-hour clock'),
+        required=False,
+    )
 
     def __init__(self, user, *args, **kwargs):
         self.user = user
@@ -365,6 +369,14 @@ def save(self):
             value=self.cleaned_data['timezone'],
         )
 
+        # Save clock 24 hours option
+        UserOption.objects.set_value(
+            user=self.user,
+            project=None,
+            key='clock_24_hours',
+            value=self.cleaned_data['clock_24_hours'],
+        )
+
         return self.user
 
 
diff --git a/src/sentry/web/frontend/accounts.py b/src/sentry/web/frontend/accounts.py
--- a/src/sentry/web/frontend/accounts.py
+++ b/src/sentry/web/frontend/accounts.py
@@ -151,6 +151,7 @@ def appearance_settings(request):
         'language': options.get('language') or request.LANGUAGE_CODE,
         'stacktrace_order': int(options.get('stacktrace_order', -1) or -1),
         'timezone': options.get('timezone') or settings.SENTRY_DEFAULT_TIME_ZONE,
+        'clock_24_hours': options.get('clock_24_hours') or False,
     })
     if form.is_valid():
         form.save()


Test patch:
diff --git a/tests/sentry/web/frontend/accounts/tests.py b/tests/sentry/web/frontend/accounts/tests.py
--- a/tests/sentry/web/frontend/accounts/tests.py
+++ b/tests/sentry/web/frontend/accounts/tests.py
@@ -34,6 +34,7 @@ def test_does_save_settings(self):
         resp = self.client.post(self.path, {
             'language': 'en',
             'stacktrace_order': '2',
+            'clock_24_hours': True
         })
         assert resp.status_code == 302
 
@@ -41,6 +42,7 @@ def test_does_save_settings(self):
 
         assert options.get('language') == 'en'
         assert options.get('stacktrace_order') == '2'
+        assert options.get('clock_24_hours') is True
 
 
 class SettingsTest(TestCase):