From b525f403775cea068d9b76995d3b548d8ab6bf08 Mon Sep 17 00:00:00 2001 From: Jason Bau <jbau@stanford.edu> Date: Wed, 22 Jan 2014 17:11:29 -0800 Subject: [PATCH] Start datetime localization in LMS Currently just coerces the time displayed for due dates (accordion.html and progess.html) to settings.TIME_ZONE --- CHANGELOG.rst | 3 +++ .../xmodule/xmodule/tests/test_date_utils.py | 19 ++++++++++++++++++- common/lib/xmodule/xmodule/util/date_utils.py | 13 +++++++++++-- lms/envs/test.py | 1 + lms/templates/courseware/accordion.html | 3 ++- lms/templates/courseware/progress.html | 7 +++++-- 6 files changed, 40 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1e464d063a1..5006cb0cb22 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,9 @@ These are notable changes in edx-platform. This is a rolling list of changes, in roughly chronological order, most recent first. Add your entries at or near the top. Include a label indicating the component affected. +LMS: In left accordion and progress page, due dates are now displayed in time +zone specified by settings.TIME_ZONE, instead of UTC always + LMS: If the course start date is kept at the default studio value (Jan 1, 2030) and advertised_start is not set, the start date is not displayed in the /courses tile view, the course about page, or the dashboard diff --git a/common/lib/xmodule/xmodule/tests/test_date_utils.py b/common/lib/xmodule/xmodule/tests/test_date_utils.py index c5f71dfb56e..ae6fd7f109d 100644 --- a/common/lib/xmodule/xmodule/tests/test_date_utils.py +++ b/common/lib/xmodule/xmodule/tests/test_date_utils.py @@ -3,7 +3,7 @@ from nose.tools import assert_equals, assert_false # pylint: disable=E0611 from xmodule.util.date_utils import get_default_time_display, get_time_display, almost_same_datetime from datetime import datetime, timedelta, tzinfo -from pytz import UTC +from pytz import UTC, timezone def test_get_default_time_display(): @@ -42,6 +42,23 @@ def test_get_time_pass_through(): assert_equals("Mar 12, 1992 at 15:03 UTC", get_time_display(test_time, "%")) +def test_get_time_display_coerce(): + test_time_standard = datetime(1992, 1, 12, 15, 3, 30, tzinfo=UTC) + test_time_daylight = datetime(1992, 7, 12, 15, 3, 30, tzinfo=UTC) + assert_equals("Jan 12, 1992 at 07:03 PST", + get_time_display(test_time_standard, None, coerce_tz="US/Pacific")) + assert_equals("Jan 12, 1992 at 15:03 UTC", + get_time_display(test_time_standard, None, coerce_tz="NONEXISTENTTZ")) + assert_equals("Jan 12 07:03", + get_time_display(test_time_standard, '%b %d %H:%M', coerce_tz="US/Pacific")) + assert_equals("Jul 12, 1992 at 08:03 PDT", + get_time_display(test_time_daylight, None, coerce_tz="US/Pacific")) + assert_equals("Jul 12, 1992 at 15:03 UTC", + get_time_display(test_time_daylight, None, coerce_tz="NONEXISTENTTZ")) + assert_equals("Jul 12 08:03", + get_time_display(test_time_daylight, '%b %d %H:%M', coerce_tz="US/Pacific")) + + # pylint: disable=W0232 class NamelessTZ(tzinfo): """Static timezone for testing""" diff --git a/common/lib/xmodule/xmodule/util/date_utils.py b/common/lib/xmodule/xmodule/util/date_utils.py index aec4f20788a..a862bc7d310 100644 --- a/common/lib/xmodule/xmodule/util/date_utils.py +++ b/common/lib/xmodule/xmodule/util/date_utils.py @@ -2,7 +2,7 @@ Convenience methods for working with datetime objects """ from datetime import timedelta - +from pytz import timezone, UTC, UnknownTimeZoneError def get_default_time_display(dtime): """ @@ -25,7 +25,7 @@ def get_default_time_display(dtime): tz=timezone).strip() -def get_time_display(dtime, format_string=None): +def get_time_display(dtime, format_string=None, coerce_tz=None): """ Converts a datetime to a string representation. @@ -34,8 +34,17 @@ def get_time_display(dtime, format_string=None): If the format_string is None, or if format_string is improperly formatted, this method will return the value from `get_default_time_display`. + Coerces aware datetime to tz=coerce_tz if set. coerce_tz should be a pytz timezone string + like "US/Pacific", or None + format_string should be a unicode string that is a valid argument for datetime's strftime method. """ + if dtime is not None and dtime.tzinfo is not None and coerce_tz: + try: + to_tz = timezone(coerce_tz) + except UnknownTimeZoneError: + to_tz = UTC + dtime = to_tz.normalize(dtime.astimezone(to_tz)) if dtime is None or format_string is None: return get_default_time_display(dtime) try: diff --git a/lms/envs/test.py b/lms/envs/test.py index 1c48238b316..b2065e87b21 100644 --- a/lms/envs/test.py +++ b/lms/envs/test.py @@ -85,6 +85,7 @@ XQUEUE_INTERFACE = { } XQUEUE_WAITTIME_BETWEEN_REQUESTS = 5 # seconds +TIME_ZONE = 'UTC' # Don't rely on a real staff grading backend MOCK_STAFF_GRADING = True diff --git a/lms/templates/courseware/accordion.html b/lms/templates/courseware/accordion.html index 8784b27d716..d857fc3ba0a 100644 --- a/lms/templates/courseware/accordion.html +++ b/lms/templates/courseware/accordion.html @@ -2,6 +2,7 @@ from django.core.urlresolvers import reverse from xmodule.util.date_utils import get_time_display from django.utils.translation import ugettext as _ + from django.conf import settings %> <%def name="make_chapter(chapter)"> @@ -29,7 +30,7 @@ if section.get('due') is None: due_date = '' else: - formatted_string = get_time_display(section['due'], due_date_display_format) + formatted_string = get_time_display(section['due'], due_date_display_format, coerce_tz=settings.TIME_ZONE) due_date = '' if len(formatted_string)==0 else _('due {date}'.format(date=formatted_string)) %> <p class="subtitle">${section['format']} ${due_date}</p> diff --git a/lms/templates/courseware/progress.html b/lms/templates/courseware/progress.html index 1e3fe575ba2..7eeea8da596 100644 --- a/lms/templates/courseware/progress.html +++ b/lms/templates/courseware/progress.html @@ -16,7 +16,10 @@ from django.core.urlresolvers import reverse %> -<%! from xmodule.util.date_utils import get_time_display %> +<%! +from xmodule.util.date_utils import get_time_display +from django.conf import settings +%> <%block name="js_extra"> <script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.js')}"></script> @@ -74,7 +77,7 @@ ${progress_graph.body(grade_summary, course.grade_cutoffs, "grade-detail-graph", %if section.get('due') is not None: <% - formatted_string = get_time_display(section['due'], course.due_date_display_format) + formatted_string = get_time_display(section['due'], course.due_date_display_format, coerce_tz=settings.TIME_ZONE) due_date = '' if len(formatted_string)==0 else _(u'due {date}').format(date=formatted_string) %> <em> -- GitLab