Skip to content
This repository has been archived by the owner on Feb 12, 2024. It is now read-only.

Commit

Permalink
Fix inter-timezone schedule problems
Browse files Browse the repository at this point in the history
All of the following should work now:

Upload in America/Los_Angeles, view in America/Toronto
Upload in America/Toronto, view in America/Toronto
Upload in America/Los_Angeles, view in America/Los_Angeles
Upload in America/Toronto, view in America/Los_Angeles

Also updates to Moment.js 2.4.0
  • Loading branch information
jlfwong committed Nov 18, 2013
1 parent 7062b92 commit 864edc6
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 46 deletions.
4 changes: 2 additions & 2 deletions server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -834,8 +834,8 @@ def upload_schedule():
room=item.get('room'),
section_type=item['section_type'].upper(),
section_num=item['section_num'],
start_date=datetime.fromtimestamp(item['start_date']),
end_date=datetime.fromtimestamp(item['end_date']),
start_date=datetime.utcfromtimestamp(item['start_date']),
end_date=datetime.utcfromtimestamp(item['end_date']),
course_id=item['course_id'],
prof_id=prof_id,
term_id=term_id,
Expand Down
55 changes: 55 additions & 0 deletions server/static/js/ext/moment-timezone-data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
define(["moment-timezone"], function (moment) {
moment.tz.add({
"zones": {
"America/Toronto": [
"-5:17:32 - LMT 1895 -5:17:32",
"-5 Canada E%sT 1919 -5",
"-5 Toronto E%sT 1942_1_9_2 -5",
"-5 Canada E%sT 1946 -5",
"-5 Toronto E%sT 1974 -5",
"-5 Canada E%sT"
]
},
"rules": {
"Canada": [
"1918 1918 3 14 7 2 0 1 D",
"1918 1918 9 27 7 2 0 0 S",
"1942 1942 1 9 7 2 0 1 W",
"1945 1945 7 14 7 23 1 1 P",
"1945 1945 8 30 7 2 0 0 S",
"1974 1986 3 0 8 2 0 1 D",
"1974 2006 9 0 8 2 0 0 S",
"1987 2006 3 1 0 2 0 1 D",
"2007 9999 2 8 0 2 0 1 D",
"2007 9999 10 1 0 2 0 0 S"
],
"Toronto": [
"1919 1919 2 30 7 23:30 0 1 D",
"1919 1919 9 26 7 0 0 0 S",
"1920 1920 4 2 7 2 0 1 D",
"1920 1920 8 26 7 0 0 0 S",
"1921 1921 4 15 7 2 0 1 D",
"1921 1921 8 15 7 2 0 0 S",
"1922 1923 4 8 0 2 0 1 D",
"1922 1926 8 15 0 2 0 0 S",
"1924 1927 4 1 0 2 0 1 D",
"1927 1932 8 0 8 2 0 0 S",
"1928 1931 3 0 8 2 0 1 D",
"1932 1932 4 1 7 2 0 1 D",
"1933 1940 3 0 8 2 0 1 D",
"1933 1933 9 1 7 2 0 0 S",
"1934 1939 8 0 8 2 0 0 S",
"1945 1946 8 0 8 2 0 0 S",
"1946 1946 3 0 8 2 0 1 D",
"1947 1949 3 0 8 0 0 1 D",
"1947 1948 8 0 8 0 0 0 S",
"1949 1949 10 0 8 0 0 0 S",
"1950 1973 3 0 8 2 0 1 D",
"1950 1950 10 0 8 2 0 0 S",
"1951 1956 8 0 8 2 0 0 S",
"1957 1973 9 0 8 2 0 0 S"
]
},
"links": {}
});
});
1 change: 1 addition & 0 deletions server/static/js/ext/moment-timezone.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions server/static/js/ext/moment.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion server/static/js/index_page.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require(
['facebook', 'ext/jquery', 'util', 'sign_in', 'ext/cookie', 'ext/moment'],
['facebook', 'ext/jquery', 'util', 'sign_in', 'ext/cookie', 'rmc_moment'],
function(_facebook, $, _util, _sign_in, _cookie, _moment) {
$('.header-bg').css('opacity', 1.0);
$('.sign-up-box').addClass('animated');
Expand Down
15 changes: 8 additions & 7 deletions server/static/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,21 @@ require.config({
'ext/select2': 'ext/select2.min',
'ext/autosize': 'ext/jquery.autosize',
'ext/cookie': 'ext/jquery.cookie',
'ext/moment': 'ext/moment.min',
'ext/slimScroll': 'ext/slimScroll-0.6.0',
'ext/jqueryui': 'ext/jquery-ui-1.8.23.custom.min',
'ext/toastr': 'ext/toastr',
'ext/underscore': 'ext/underscore-1.3.3',
'ext/underscore.string': 'ext/underscore.string-2.0.0'
//'main': 'main.js?v=' + pageData.version
'ext/underscore.string': 'ext/underscore.string-2.0.0',

'moment': 'ext/moment.min',
'moment-timezone': 'ext/moment-timezone.min'
}
});

require(['ext/underscore', 'ext/underscore.string', 'util', 'ext/moment',
'ext/jquery', 'ext/underscore', 'ext/underscore.string', 'ext/backbone',
'ext/bootstrap', 'ext/cookie', 'ext/toastr', 'points', 'user', 'facebook'],
function(_, _s, util, moment, $, _, _s, Backbone, __, __, toastr, _points,
require(['ext/underscore', 'ext/underscore.string', 'util', 'rmc_moment',
'ext/jquery', 'ext/backbone', 'ext/bootstrap', 'ext/cookie', 'ext/toastr',
'points', 'user', 'facebook'],
function(_, _s, util, moment, $, Backbone, __, __, toastr, _points,
_user, _facebook) {

// Add helpers functions to all templates
Expand Down
7 changes: 7 additions & 0 deletions server/static/js/rmc_moment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
define(["moment", "moment-timezone", "ext/moment-timezone-data"], function (_moment, __, __) {
// Always use America/Toronto as the timezone.
return function() {
return (_moment.apply(moment, Array.prototype.slice.apply(arguments))
.tz("America/Toronto"));
};
});
64 changes: 34 additions & 30 deletions server/static/js/schedule.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
define(
['rmc_backbone', 'ext/jquery', 'ext/underscore', 'ext/underscore.string',
'ext/bootstrap', 'course', 'util', 'facebook', 'ext/moment'],
'ext/bootstrap', 'course', 'util', 'facebook',
'rmc_moment'],
function(RmcBackbone, $, _, _s, _bootstrap, _course, _util, _facebook, moment) {

// Cache a propery for a given instance.
var instancePropertyCache = function(getter) {
return _.memoize(getter, function() {
return this.cid;
});
};
var minutesSinceSod = function(date) {
var dateMoment = moment(date);
return dateMoment.diff(dateMoment.sod(), 'minutes');
return dateMoment.diff(dateMoment.clone().startOf('day'), 'minutes');
};

var isSameDay = function(firstDate, secondDate) {
var firstMoment = moment(firstDate);
var secondMoment = moment(secondDate);
return firstMoment.sod().diff(secondMoment.sod()) === 0;
return firstMoment.startOf('day').diff(secondMoment.startOf('day')) === 0;
};

// TODO(mack): rename UserScheduleItem to match the backend
Expand All @@ -30,21 +36,6 @@ function(RmcBackbone, $, _, _s, _bootstrap, _course, _util, _facebook, moment) {
term_id: ''
},

initialize: function() {
// Server time is UTC, but client's computer is some other timezone.
// Adjust to their timezone by adding moment.zone().
// FIXME(Sandy): This will break for people not in the same timezone as
// their university, but they might not be attending classes there anyway?

// FIXME(david): This is bugging out on prod but not local
//var timezoneShift = function(date) {
// mDate = moment(date);
// return mDate.add('minutes', mDate.zone()).toDate();
//};
//this.set('start_date', timezoneShift(this.get('start_date')));
//this.set('end_date', timezoneShift(this.get('end_date')));
},

referenceFields: {
'course': ['course_id', _course.CourseCollection]
},
Expand All @@ -62,13 +53,13 @@ function(RmcBackbone, $, _, _s, _bootstrap, _course, _util, _facebook, moment) {
(selfEnd >= otherStart && selfEnd <= otherEnd);
},

startMinutes: function() {
startMinutes: instancePropertyCache(function() {
return minutesSinceSod(this.get('start_date'));
},
}),

endMinutes: function() {
endMinutes: instancePropertyCache(function() {
return minutesSinceSod(this.get('end_date'));
}
})
});

var ScheduleItemCollection = RmcBackbone.Collection.extend({
Expand Down Expand Up @@ -346,7 +337,7 @@ function(RmcBackbone, $, _, _s, _bootstrap, _course, _util, _facebook, moment) {
},

setBestWeek: function() {
var startOfCurrWeek = moment().day(1).sod();
var startOfCurrWeek = moment().day(1).startOf('day');

// Find the closest week in the future with schedule items, or failing
// that the closest week in the past with schedule items
Expand All @@ -358,15 +349,15 @@ function(RmcBackbone, $, _, _s, _bootstrap, _course, _util, _facebook, moment) {
futureItems = _(futureItems).sortBy(function(item) {
return moment(item.get('start_date')).unix();
});
this.setWeek(moment(futureItems[0].get('start_date')).clone().day(1).sod().toDate());
this.setWeek(moment(futureItems[0].get('start_date')).clone().day(1).startOf('day').toDate());
} else {
var pastItems = this.get('schedule_items').filter(function(item) {
return startOfCurrWeek.unix() > moment(item.get('start_date')).unix();
});
pastItems = _(pastItems).sortBy(function(item) {
return moment(item.get('start_date')).unix();
});
this.setWeek(moment(pastItems[pastItems.length-1].get('start_date')).clone().day(1).sod().toDate());
this.setWeek(moment(pastItems[pastItems.length-1].get('start_date')).clone().day(1).startOf('day').toDate());
}
},

Expand All @@ -389,7 +380,7 @@ function(RmcBackbone, $, _, _s, _bootstrap, _course, _util, _facebook, moment) {
var currMoment = moment();

// Start the week on the Monday of the current week
this.setWeek(currMoment.day(1).sod().toDate());
this.setWeek(currMoment.day(1).startOf('day').toDate());
},

setNextWeek: function() {
Expand Down Expand Up @@ -923,9 +914,15 @@ function(RmcBackbone, $, _, _s, _bootstrap, _course, _util, _facebook, moment) {
hasClassOnDay[weekdayMap[day]] = true;
});

var timeFormats = ['YYYY-MM-DD h:mm A', 'MM/DD/YYYY h:mm A', 'DD/MM/YYYY H:mm'];
var firstStartMoment = moment(startDateStr + " " + startTimeStr, timeFormats);
var firstEndMoment = moment(startDateStr + " " + endTimeStr, timeFormats);
// Once we have the date of the item, figure out what the TZ offset is,
// then interpret the date using that offset
var tzOffsetStr = moment(startDateStr, [
"YYYY-MM-DD", "MM/DD/YYYY", "DD/MM/YYYY"
]).tz("America/Toronto").format("ZZ");

var timeFormats = ['YYYY-MM-DD h:mm A ZZ', 'MM/DD/YYYY h:mm A ZZ', 'DD/MM/YYYY H:mm ZZ'];
var firstStartMoment = moment(startDateStr + " " + startTimeStr + " " + tzOffsetStr, timeFormats);
var firstEndMoment = moment(startDateStr + " " + endTimeStr + " " + tzOffsetStr, timeFormats);

// Time delta between start and end time, in milliseconds
var timeDelta = firstEndMoment - firstStartMoment;
Expand All @@ -948,6 +945,13 @@ function(RmcBackbone, $, _, _s, _bootstrap, _course, _util, _facebook, moment) {
prof_name: profName
});
}
// When this crosses a DST line, it only changes the date, not the time

This comment has been minimized.

Copy link
@jswu

jswu Nov 18, 2013

Member

I wasn't going to comment on this, but I feel obligated to...

"it only changes the date" => "it changes only the date"

(but I'm not saying you need to actually go make the change :P)

This comment has been minimized.

Copy link
@divad12

divad12 Nov 18, 2013

Member

HAHAHAHAH.

This comment has been minimized.

Copy link
@jlfwong

jlfwong Nov 18, 2013

Author Member

That course was mental cancer.

This comment has been minimized.

Copy link
@divad12

divad12 Nov 18, 2013

Member

CRUCIAL BUG!!! WHAT IF SOMEONE ACCIDENTALLY SUBCONSCIOUSLY DISAMBIGUATES THIS COMMENT THE WRONG WAY??? AND THEY PUSH OUT WRONG CODE AND IT"S RIGHT AT THE TIME WHEN WE"RE SHOWING FLOW TO PRESIDENT OBAMA???

PRIORITY -Infinity BUG!!!

This comment has been minimized.

Copy link
@jswu

jswu Nov 18, 2013

Member

Ever since then, I'm reminded of that course every time I see the word "only". Almost all of the time it's used incorrectly, but academic/research papers usually get it right.

//
// > moment("2013-11-02 15:00").add('days', 0).tz("America/Toronto").format()
// "2013-11-02T18:00:00-04:00"
// > moment("2013-11-02 15:00").add('days', 1).tz("America/Toronto").format()
// "2013-11-03T18:00:00-05:00"
//
currMoment.add('days', 1);
}
return processedSlotItems;
Expand Down

0 comments on commit 864edc6

Please sign in to comment.