Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions cms/djangoapps/contentstore/views/course.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
from openedx.core.djangoapps.credit.tasks import update_credit_course_requirements
from openedx.core.djangoapps.models.course_details import CourseDetails
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from openedx.core.djangoapps.user_api.models import UserPreference
from openedx.core.djangolib.js_utils import dump_js_escaped_json
from openedx.core.lib.course_tabs import CourseTabPluginManager
from openedx.core.lib.courses import course_image_url
Expand Down Expand Up @@ -1224,6 +1225,12 @@ def settings_handler(request, course_key_string): # lint-amnesty, pylint: disab
elif 'application/json' in request.META.get('HTTP_ACCEPT', ''):
if request.method == 'GET':
course_details = CourseDetails.fetch(course_key)

# Fetch the prefered timezone setup by the user
# and pass it as part of Json response
user_timezone = UserPreference.get_value(request.user, 'time_zone')
course_details.user_timezone = user_timezone

return JsonResponse(
course_details,
# encoder serializes dates, old locations, and instances
Expand Down
1 change: 1 addition & 0 deletions cms/static/cms/js/spec/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
'jquery.simulate': 'xmodule_js/common_static/js/vendor/jquery.simulate',
'datepair': 'xmodule_js/common_static/js/vendor/timepicker/datepair',
'date': 'xmodule_js/common_static/js/vendor/date',
'moment-timezone': 'common/js/vendor/moment-timezone-with-data',
moment: 'common/js/vendor/moment-with-locales',
'text': 'xmodule_js/common_static/js/vendor/requirejs/text',
'underscore': 'common/js/vendor/underscore',
Expand Down
61 changes: 59 additions & 2 deletions cms/static/js/utils/date_utils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
define(['jquery', 'date', 'js/utils/change_on_enter', 'jquery.ui', 'jquery.timepicker'],
function($, date, TriggerChangeEventOnEnter) {
define(['jquery', 'date', 'js/utils/change_on_enter', 'moment-timezone', 'jquery.ui', 'jquery.timepicker'],
function($, date, TriggerChangeEventOnEnter, moment) {
'use strict';

function getDate(datepickerInput, timepickerInput) {
Expand Down Expand Up @@ -67,14 +67,54 @@ function($, date, TriggerChangeEventOnEnter) {
return obj;
}

/**
* Calculates the utc offset in miliseconds for given
* timezone and subtracts it from given localized time
* to get time in UTC
*
* @param {Date} localTime JS Date object in Local Time
* @param {string} timezone IANA timezone name ex. "Australia/Brisbane"
* @returns JS Date object in UTC
*/
function convertLocalizedDateToUTC(localTime, timezone) {
const localTimeMS = localTime.getTime();
const utcOffset = moment.tz(localTime, timezone)._offset;
return new Date(localTimeMS - (utcOffset * 60 *1000));
}

/**
* Returns the timezone abbreviation for given
* timezone name
*
* @param {string} timezone IANA timezone name ex. "Australia/Brisbane"
* @returns Timezone abbreviation ex. "AEST"
*/
function getTZAbbreviation(timezone) {
return moment(new Date()).tz(timezone).format('z');
}

/**
* Converts the given datetime string from UTC to localized time
*
* @param {string} utcDateTime JS Date object with UTC datetime
* @param {string} timezone IANA timezone name ex. "Australia/Brisbane"
* @returns Formatted datetime string with localized timezone
*/
function getLocalizedCurrentDate(utcDateTime, timezone) {
const localDateTime = moment(utcDateTime).tz(timezone);
return localDateTime.format('YYYY-MM-DDTHH[:]mm[:]ss');
}

function setupDatePicker(fieldName, view, index) {
var cacheModel;
var div;
var datefield;
var timefield;
var tzfield;
var cacheview;
var setfield;
var currentDate;
var timezone;
if (typeof index !== 'undefined' && view.hasOwnProperty('collection')) {
cacheModel = view.collection.models[index];
div = view.$el.find('#' + view.collectionSelector(cacheModel.cid));
Expand All @@ -84,10 +124,18 @@ function($, date, TriggerChangeEventOnEnter) {
}
datefield = $(div).find('input.date');
timefield = $(div).find('input.time');
tzfield = $(div).find('span.timezone');
cacheview = view;

timezone = cacheModel.get('user_timezone');

setfield = function(event) {
var newVal = getDate(datefield, timefield);

if (timezone) {
newVal = convertLocalizedDateToUTC(newVal, timezone);
}

// Setting to null clears the time as well, as date and time are linked.
// Note also that the validation logic prevents us from clearing the start date
// (start date is required by the back end).
Expand All @@ -109,8 +157,17 @@ function($, date, TriggerChangeEventOnEnter) {
if (cacheModel) {
currentDate = cacheModel.get(fieldName);
}

if (timezone) {
const tz = getTZAbbreviation(timezone);
$(tzfield).text("("+tz+")");
}

// timepicker doesn't let us set null, so check that we have a time
if (currentDate) {
if (timezone) {
currentDate = getLocalizedCurrentDate(currentDate, timezone);
}
setDate(datefield, timefield, currentDate);
} else {
// but reset fields either way
Expand Down