🐛 UTC offset for scheduled posts when changing timezone (#8356)

no issue

- the UTC offset diff of the current and previous timezone must switch
- i have added more tests and more example case descriptions to understand why
This commit is contained in:
Katharina Irrgang 2017-04-19 10:26:33 +02:00 committed by GitHub
parent d704387482
commit f7393686f8
2 changed files with 102 additions and 14 deletions

View File

@ -43,7 +43,7 @@ events.on('user.deactivated', function (userModel) {
events.on('settings.activeTimezone.edited', function (settingModel) {
var newTimezone = settingModel.attributes.value,
previousTimezone = settingModel._updatedAttributes.value,
timezoneOffsetDiff = moment.tz(newTimezone).utcOffset() - moment.tz(previousTimezone).utcOffset();
timezoneOffsetDiff = moment.tz(previousTimezone).utcOffset() - moment.tz(newTimezone).utcOffset();
// CASE: TZ was updated, but did not change
if (previousTimezone === newTimezone) {

View File

@ -17,11 +17,8 @@ describe('Models: listeners', function () {
scope = {
posts: [],
publishedAtFutureMoment1: moment().add(2, 'days').startOf('hour'),
publishedAtFutureMoment3: moment().add(10, 'hours').startOf('hour'),
// calculate the offset dynamically, because of DST
timezoneOffset: moment.tz.zone('Europe/London').offset(now) - moment.tz.zone('America/Los_Angeles').offset(now),
newTimezone: 'America/Los_Angeles',
oldTimezone: 'Europe/London'
publishedAtFutureMoment2: moment().add(2, 'hours').startOf('hour'),
publishedAtFutureMoment3: moment().add(10, 'hours').startOf('hour')
};
before(testUtils.teardown);
@ -46,7 +43,6 @@ describe('Models: listeners', function () {
describe('db has scheduled posts', function () {
beforeEach(function (done) {
// will get rescheduled
scope.posts.push(testUtils.DataGenerator.forKnex.createPost({
published_at: scope.publishedAtFutureMoment1.toDate(),
status: 'scheduled',
@ -54,15 +50,13 @@ describe('Models: listeners', function () {
slug: '1'
}));
// will get drafted
scope.posts.push(testUtils.DataGenerator.forKnex.createPost({
published_at: moment().add(2, 'hours').toDate(),
published_at: scope.publishedAtFutureMoment2.toDate(),
status: 'scheduled',
title: '2',
slug: '2'
}));
// will get rescheduled
scope.posts.push(testUtils.DataGenerator.forKnex.createPost({
published_at: scope.publishedAtFutureMoment3.toDate(),
status: 'scheduled',
@ -81,9 +75,30 @@ describe('Models: listeners', function () {
});
});
it('activeTimezone changes change', function (done) {
it('activeTimezone changes from London to Los Angeles', function (done) {
var timeout;
/**
* From London +1
* To Los Angeles -7
*
* We expect +420 minutes if DST. (otherwise +480)
*
* Image it's 11AM London time. 10AM UTC.
* Imagine the post is scheduled for 8PM London time.
* The database UTC string is e.g. 2017-04-18 19:00:00.
* You switch the timezone to Los Angeles.
* It's 3AM in the morning in Los Angeles.
* If we don't change the database UTC string, the post is scheduled at 11AM in the morning! (19-7)
* The post should be still scheduled for 8PM Los Angeles time.
* So the database UTC string must be 2017-04-19 03:00:00. (-7 hours === 8 o'clock in Los Angeles)
*/
// calculate the offset dynamically, because of DST
scope.timezoneOffset = moment.tz.zone('America/Los_Angeles').offset(now) - moment.tz.zone('Europe/London').offset(now);
scope.newTimezone = 'America/Los_Angeles';
scope.oldTimezone = 'Europe/London';
eventsToRemember['settings.activeTimezone.edited']({
attributes: {value: scope.newTimezone},
_updatedAttributes: {value: scope.oldTimezone}
@ -104,9 +119,10 @@ describe('Models: listeners', function () {
if (results.models.length === posts.length &&
post1.get('status') === 'scheduled' &&
post2.get('status') === 'draft' &&
post2.get('status') === 'scheduled' &&
post3.get('status') === 'scheduled' &&
moment(post1.get('published_at')).diff(scope.publishedAtFutureMoment1.clone().add(scope.timezoneOffset, 'minutes')) === 0 &&
moment(post2.get('published_at')).diff(scope.publishedAtFutureMoment2.clone().add(scope.timezoneOffset, 'minutes')) === 0 &&
moment(post3.get('published_at')).diff(scope.publishedAtFutureMoment3.clone().add(scope.timezoneOffset, 'minutes')) === 0) {
return done();
}
@ -118,10 +134,25 @@ describe('Models: listeners', function () {
})();
});
it('activeTimezone changes change: from a TZ to UTC', function (done) {
it('activeTimezone changes from Baghdad to UTC', function (done) {
var timeout;
scope.timezoneOffset = -180;
/**
* From Baghdad +3
* To UTC +/-0
*
* We expect +180 minutes.
*
* Image it's 11AM Baghdad time.
* Imagine the post is scheduled for 8PM Baghdad time.
* The database UTC string is e.g. 2017-04-18 17:00:00.
* You switch the timezone to UTC.
* It's 9AM in the morning in UTC.
* If we don't change the database UTC string, the post is scheduled at 5PM in the evening!
* The post should be still scheduled for 8PM UTC time.
* So the database UTC string must be 2017-04-19 20:00:00.
*/
scope.timezoneOffset = 180;
scope.oldTimezone = 'Asia/Baghdad';
scope.newTimezone = 'Etc/UTC';
@ -130,6 +161,63 @@ describe('Models: listeners', function () {
_updatedAttributes: {value: scope.oldTimezone}
});
(function retry() {
models.Post.findAll({context: {internal: true}})
.then(function (results) {
var post1 = _.find(results.models, function (post) {
return post.get('title') === '1';
}),
post2 = _.find(results.models, function (post) {
return post.get('title') === '2';
}),
post3 = _.find(results.models, function (post) {
return post.get('title') === '3';
});
if (results.models.length === posts.length &&
post1.get('status') === 'scheduled' &&
post2.get('status') === 'scheduled' &&
post3.get('status') === 'scheduled' &&
moment(post1.get('published_at')).diff(scope.publishedAtFutureMoment1.clone().add(scope.timezoneOffset, 'minutes')) === 0 &&
moment(post2.get('published_at')).diff(scope.publishedAtFutureMoment2.clone().add(scope.timezoneOffset, 'minutes')) === 0 &&
moment(post3.get('published_at')).diff(scope.publishedAtFutureMoment3.clone().add(scope.timezoneOffset, 'minutes')) === 0) {
return done();
}
clearTimeout(timeout);
timeout = setTimeout(retry, 500);
})
.catch(done);
})();
});
it('activeTimezone changes from Amsterdam to Seoul', function (done) {
var timeout;
/**
* From Amsterdam +2
* To Seoul +9
*
* We expect -420 minutes.
*
* Image it's 11AM Amsterdam time. 9AM UTC.
* Imagine the post is scheduled for 8PM Amsterdam time.
* The database UTC string is e.g. 2017-04-18 18:00:00.
* You switch the timezone to Seoul timezone.
* It's 6PM in the evening in Seoul timezone.
* If we don't change the database UTC string, the post is scheduled at 3AM in the evening on the next day!
* The post should be still scheduled for 8PM UTC time.
* So the database UTC string must be 2017-04-18 11:00:00.
*/
scope.timezoneOffset = -420;
scope.oldTimezone = 'Europe/Amsterdam';
scope.newTimezone = 'Asia/Seoul';
eventsToRemember['settings.activeTimezone.edited']({
attributes: {value: scope.newTimezone},
_updatedAttributes: {value: scope.oldTimezone}
});
(function retry() {
models.Post.findAll({context: {internal: true}})
.then(function (results) {