diff --git a/common/lib/xmodule/xmodule/course_module.py b/common/lib/xmodule/xmodule/course_module.py index de4f9fe80e..5d66956461 100644 --- a/common/lib/xmodule/xmodule/course_module.py +++ b/common/lib/xmodule/xmodule/course_module.py @@ -954,10 +954,9 @@ class CourseDescriptor(CourseFields, SequenceDescriptor): """Return the course_id for this course""" return self.location.course_key - @property - def start_date_text(self): + def start_datetime_text(self, format_string="SHORT_DATE"): """ - Returns the desired text corresponding the course's start date. Prefers .advertised_start, + Returns the desired text corresponding the course's start date and time in UTC. Prefers .advertised_start, then falls back to .start """ i18n = self.runtime.service(self, "i18n") @@ -970,7 +969,9 @@ class CourseDescriptor(CourseFields, SequenceDescriptor): if result is None: result = text.title() else: - result = strftime(result, "SHORT_DATE") + result = strftime(result, format_string) + if format_string == "DATE_TIME": + result = self._add_timezone_string(result) except ValueError: result = text.title() @@ -984,7 +985,11 @@ class CourseDescriptor(CourseFields, SequenceDescriptor): return _('TBD') else: when = self.advertised_start or self.start - return strftime(when, "SHORT_DATE") + + if format_string == "DATE_TIME": + return self._add_timezone_string(strftime(when, format_string)) + + return strftime(when, format_string) @property def start_date_is_still_default(self): @@ -994,10 +999,9 @@ class CourseDescriptor(CourseFields, SequenceDescriptor): """ return self.advertised_start is None and self.start == CourseFields.start.default - @property - def end_date_text(self): + def end_datetime_text(self, format_string="SHORT_DATE"): """ - Returns the end date for the course formatted as a string. + Returns the end date or date_time for the course formatted as a string. If the course does not have an end date set (course.end is None), an empty string will be returned. """ @@ -1005,7 +1009,14 @@ class CourseDescriptor(CourseFields, SequenceDescriptor): return '' else: strftime = self.runtime.service(self, "i18n").strftime - return strftime(self.end, "SHORT_DATE") + date_time = strftime(self.end, format_string) + return date_time if format_string == "SHORT_DATE" else self._add_timezone_string(date_time) + + def _add_timezone_string(self, date_time): + """ + Adds 'UTC' string to the end of start/end date and time texts. + """ + return date_time + u" UTC" @property def forum_posts_allowed(self): diff --git a/common/lib/xmodule/xmodule/tests/test_course_module.py b/common/lib/xmodule/xmodule/tests/test_course_module.py index c430d672c8..ab15eb3a17 100644 --- a/common/lib/xmodule/xmodule/tests/test_course_module.py +++ b/common/lib/xmodule/xmodule/tests/test_course_module.py @@ -185,13 +185,13 @@ class IsNewCourseTestCase(unittest.TestCase): assertion(a_score, b_score) start_advertised_settings = [ - # start, advertised, result, is_still_default - ('2012-12-02T12:00', None, 'Dec 02, 2012', False), - ('2012-12-02T12:00', '2011-11-01T12:00', 'Nov 01, 2011', False), - ('2012-12-02T12:00', 'Spring 2012', 'Spring 2012', False), - ('2012-12-02T12:00', 'November, 2011', 'November, 2011', False), - (xmodule.course_module.CourseFields.start.default, None, 'TBD', True), - (xmodule.course_module.CourseFields.start.default, 'January 2014', 'January 2014', False), + # start, advertised, result, is_still_default, date_time_result + ('2012-12-02T12:00', None, 'Dec 02, 2012', False, u'Dec 02, 2012 at 12:00 UTC'), + ('2012-12-02T12:00', '2011-11-01T12:00', 'Nov 01, 2011', False, u'Nov 01, 2011 at 12:00 UTC'), + ('2012-12-02T12:00', 'Spring 2012', 'Spring 2012', False, 'Spring 2012'), + ('2012-12-02T12:00', 'November, 2011', 'November, 2011', False, 'November, 2011'), + (xmodule.course_module.CourseFields.start.default, None, 'TBD', True, 'TBD'), + (xmodule.course_module.CourseFields.start.default, 'January 2014', 'January 2014', False, 'January 2014'), ] @patch('xmodule.course_module.datetime.now') @@ -200,7 +200,15 @@ class IsNewCourseTestCase(unittest.TestCase): for s in self.start_advertised_settings: d = get_dummy_course(start=s[0], advertised_start=s[1]) print "Checking start=%s advertised=%s" % (s[0], s[1]) - self.assertEqual(d.start_date_text, s[2]) + self.assertEqual(d.start_datetime_text(), s[2]) + + @patch('xmodule.course_module.datetime.now') + def test_start_date_time_text(self, gmtime_mock): + gmtime_mock.return_value = NOW + for setting in self.start_advertised_settings: + course = get_dummy_course(start=setting[0], advertised_start=setting[1]) + print "Checking start=%s advertised=%s" % (setting[0], setting[1]) + self.assertEqual(course.start_datetime_text("DATE_TIME"), setting[4]) def test_start_date_is_default(self): for s in self.start_advertised_settings: @@ -242,10 +250,18 @@ class IsNewCourseTestCase(unittest.TestCase): def test_end_date_text(self): # No end date set, returns empty string. d = get_dummy_course('2012-12-02T12:00') - self.assertEqual('', d.end_date_text) + self.assertEqual('', d.end_datetime_text()) d = get_dummy_course('2012-12-02T12:00', end='2014-9-04T12:00') - self.assertEqual('Sep 04, 2014', d.end_date_text) + self.assertEqual('Sep 04, 2014', d.end_datetime_text()) + + def test_end_date_time_text(self): + # No end date set, returns empty string. + course = get_dummy_course('2012-12-02T12:00') + self.assertEqual('', course.end_datetime_text("DATE_TIME")) + + course = get_dummy_course('2012-12-02T12:00', end='2014-9-04T12:00') + self.assertEqual('Sep 04, 2014 at 12:00 UTC', course.end_datetime_text("DATE_TIME")) class DiscussionTopicsTestCase(unittest.TestCase): diff --git a/lms/djangoapps/shoppingcart/models.py b/lms/djangoapps/shoppingcart/models.py index 2b27dcc252..14ce5e39df 100644 --- a/lms/djangoapps/shoppingcart/models.py +++ b/lms/djangoapps/shoppingcart/models.py @@ -250,7 +250,7 @@ class Order(models.Model): course_id = item.course_id course = get_course_by_id(getattr(item, 'course_id'), depth=0) registration_codes = CourseRegistrationCode.objects.filter(course_id=course_id, order=self) - course_info.append((course.display_name, ' (' + course.start_date_text + '-' + course.end_date_text + ')')) + course_info.append((course.display_name, ' (' + course.start_datetime_text() + '-' + course.end_datetime_text() + ')')) for registration_code in registration_codes: redemption_url = reverse('register_code_redemption', args=[registration_code.code]) url = '{base_url}{redemption_url}'.format(base_url=site_name, redemption_url=redemption_url) @@ -1156,7 +1156,7 @@ class CertificateItem(OrderItem): "course_name": course.display_name_with_default, "course_org": course.display_org_with_default, "course_num": course.display_number_with_default, - "course_start_date_text": course.start_date_text, + "course_start_date_text": course.start_datetime_text(), "course_has_started": course.start > datetime.today().replace(tzinfo=pytz.utc), "course_root_url": reverse( 'course_root', diff --git a/lms/templates/course.html b/lms/templates/course.html index a0dc6ea6f5..a67f157662 100644 --- a/lms/templates/course.html +++ b/lms/templates/course.html @@ -27,7 +27,7 @@ from courseware.courses import course_image_url, get_course_about_section
${get_course_about_section(course, 'university')} % if not course.start_date_is_still_default: - ${course.start_date_text} + ${course.start_datetime_text()} % endif
diff --git a/lms/templates/courseware/course_about.html b/lms/templates/courseware/course_about.html index cf5a3cbfb1..24d162cad1 100644 --- a/lms/templates/courseware/course_about.html +++ b/lms/templates/courseware/course_about.html @@ -292,7 +292,7 @@
  1. ${_("Course Number")}

    ${course.display_number_with_default | h}
  2. % if not course.start_date_is_still_default: -
  3. ${_("Classes Start")}

    ${course.start_date_text}
  4. +
  5. ${_("Classes Start")}

    ${course.start_datetime_text()}
  6. % endif ## We plan to ditch end_date (which is not stored in course metadata), ## but for backwards compatibility, show about/end_date blob if it exists. @@ -303,7 +303,7 @@ % if get_course_about_section(course, "end_date"): ${get_course_about_section(course, "end_date")} % else: - ${course.end_date_text} + ${course.end_datetime_text()} % endif diff --git a/lms/templates/dashboard/_dashboard_course_listing.html b/lms/templates/dashboard/_dashboard_course_listing.html index dc2279f9e4..21c6ae879c 100644 --- a/lms/templates/dashboard/_dashboard_course_listing.html +++ b/lms/templates/dashboard/_dashboard_course_listing.html @@ -73,13 +73,13 @@

    % if course.has_ended(): - ${_("Course Completed - {end_date}").format(end_date=course.end_date_text)} + ${_("Course Completed - {end_date}").format(end_date=course.end_datetime_text("DATE_TIME"))} % elif course.has_started(): - ${_("Course Started - {start_date}").format(start_date=course.start_date_text)} + ${_("Course Started - {start_date}").format(start_date=course.start_datetime_text("DATE_TIME"))} % elif course.start_date_is_still_default: # Course start date TBD ${_("Course has not yet started")} % else: # hasn't started yet - ${_("Course Starts - {start_date}").format(start_date=course.start_date_text)} + ${_("Course Starts - {start_date}").format(start_date=course.start_datetime_text("DATE_TIME"))} % endif

    ${get_course_about_section(course, 'university')}

    @@ -239,4 +239,4 @@ }); } }); - \ No newline at end of file + diff --git a/lms/templates/shoppingcart/receipt.html b/lms/templates/shoppingcart/receipt.html index fac1ef230d..448766758d 100644 --- a/lms/templates/shoppingcart/receipt.html +++ b/lms/templates/shoppingcart/receipt.html @@ -278,7 +278,11 @@ from courseware.courses import course_image_url, get_course_about_section, get_c

    ${_("Registration for")}: - % if course.start_date_text or course.end_date_text: + <% + course_start_time = course.start_datetime_text() + course_end_time = course.end_datetime_text() + %> + % if course_start_time or course_end_time: ${_("Course Dates")}: %endif @@ -286,12 +290,12 @@ from courseware.courses import course_image_url, get_course_about_section, get_c

    ${_(" {course_name} ").format(course_name=course.display_name)} - % if course.start_date_text: - ${course.start_date_text} + % if course_start_time: + ${course_start_time} %endif - - % if course.end_date_text: - ${course.end_date_text} + % if course_end_time: + ${course_end_time} %endif

    diff --git a/lms/templates/shoppingcart/registration_code_receipt.html b/lms/templates/shoppingcart/registration_code_receipt.html index e119f4b82a..c9bb5da476 100644 --- a/lms/templates/shoppingcart/registration_code_receipt.html +++ b/lms/templates/shoppingcart/registration_code_receipt.html @@ -30,7 +30,7 @@ from courseware.courses import course_image_url, get_course_about_section

    ${_("{course_name}").format(course_name=course.display_name)} - ${_("{start_date}").format(start_date=course.start_date_text)} - ${_("{end_date}").format(end_date=course.end_date_text)} + ${_("{start_date}").format(start_date=course.start_datetime_text())} - ${_("{end_date}").format(end_date=course.end_datetime_text())}

    diff --git a/lms/templates/shoppingcart/shopping_cart.html b/lms/templates/shoppingcart/shopping_cart.html index 0bd92f3882..ad1344bed0 100644 --- a/lms/templates/shoppingcart/shopping_cart.html +++ b/lms/templates/shoppingcart/shopping_cart.html @@ -34,7 +34,7 @@ from django.utils.translation import ugettext as _

    ${_('Registration for:')} ${_('Course Dates:')}

    -

    ${ course.display_name }${course.start_date_text} - ${course.end_date_text}

    +

    ${ course.display_name }${course.start_datetime_text()} - ${course.end_datetime_text()}