From 286843ac649c6b96c4cfd213c8d7e3c1277d5ee6 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Mon, 23 Jul 2018 06:20:01 -0600 Subject: [PATCH] avoid day long gaps in sample data (#20897) (#21070) * avoid day long gaps in sample data * avoid using toISOString to avoid an timezone problems * unskip sample test now that problem is fixed * use much better cj algorithm for translating time * cjcenizal review updates * update funtion name in install.js * push source reference date back a week --- .../sample_data/data_sets/flights/index.js | 2 +- src/server/sample_data/routes/install.js | 13 ++- .../routes/lib/adjust_timestamp.js | 48 -------- .../routes/lib/adjust_timestamp.test.js | 73 ------------ .../routes/lib/translate_timestamp.js | 75 ++++++++++++ .../routes/lib/translate_timestamp.test.js | 107 ++++++++++++++++++ test/functional/apps/home/_sample_data.js | 3 +- 7 files changed, 193 insertions(+), 128 deletions(-) delete mode 100644 src/server/sample_data/routes/lib/adjust_timestamp.js delete mode 100644 src/server/sample_data/routes/lib/adjust_timestamp.test.js create mode 100644 src/server/sample_data/routes/lib/translate_timestamp.js create mode 100644 src/server/sample_data/routes/lib/translate_timestamp.test.js diff --git a/src/server/sample_data/data_sets/flights/index.js b/src/server/sample_data/data_sets/flights/index.js index 2439e7b4a6507..dd2e477ccc98f 100644 --- a/src/server/sample_data/data_sets/flights/index.js +++ b/src/server/sample_data/data_sets/flights/index.js @@ -113,7 +113,7 @@ export function flightsSpecProvider() { } }, timeFields: ['timestamp'], - currentTimeMarker: '2018-01-02T00:00:00', + currentTimeMarker: '2018-01-09T00:00:00', preserveDayOfWeekTimeOfDay: true, savedObjects: savedObjects, }; diff --git a/src/server/sample_data/routes/install.js b/src/server/sample_data/routes/install.js index a466c690b04b2..8ebc768184f1a 100644 --- a/src/server/sample_data/routes/install.js +++ b/src/server/sample_data/routes/install.js @@ -21,7 +21,11 @@ import Joi from 'joi'; import { loadData } from './lib/load_data'; import { createIndexName } from './lib/create_index_name'; -import { adjustTimestamp } from './lib/adjust_timestamp'; +import { + dateToIso8601IgnoringTime, + translateTimeRelativeToDifference, + translateTimeRelativeToWeek +} from './lib/translate_timestamp'; export const createInstallRoute = () => ({ path: '/api/sample_data/{id}', @@ -81,12 +85,13 @@ export const createInstallRoute = () => ({ return reply(errMsg).code(err.status); } - const now = new Date(); - const currentTimeMarker = new Date(Date.parse(sampleDataset.currentTimeMarker)); + const nowReference = dateToIso8601IgnoringTime(new Date()); function updateTimestamps(doc) { sampleDataset.timeFields.forEach(timeFieldName => { if (doc[timeFieldName]) { - doc[timeFieldName] = adjustTimestamp(doc[timeFieldName], currentTimeMarker, now, sampleDataset.preserveDayOfWeekTimeOfDay); + doc[timeFieldName] = sampleDataset.preserveDayOfWeekTimeOfDay + ? translateTimeRelativeToWeek(doc[timeFieldName], sampleDataset.currentTimeMarker, nowReference) + : translateTimeRelativeToDifference(doc[timeFieldName], sampleDataset.currentTimeMarker, nowReference); } }); return doc; diff --git a/src/server/sample_data/routes/lib/adjust_timestamp.js b/src/server/sample_data/routes/lib/adjust_timestamp.js deleted file mode 100644 index 749b181cbe544..0000000000000 --- a/src/server/sample_data/routes/lib/adjust_timestamp.js +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - -const MILLISECONDS_IN_DAY = 86400000; - -/** - * Convert timestamp to timestamp that is relative to now - * - * @param {String} timestamp ISO8601 formated data string YYYY-MM-dd'T'HH:mm:ss.SSS - * @param {Date} currentTimeMarker "now" reference marker in sample dataset - * @param {Date} now - * @param {Boolean} preserveDayOfWeekTimeOfDay - * @return {String} ISO8601 formated data string YYYY-MM-dd'T'HH:mm:ss.SSS of timestamp adjusted to now - */ -export function adjustTimestamp(timestamp, currentTimeMarker, now, preserveDayOfWeekTimeOfDay) { - const timestampDate = new Date(Date.parse(timestamp)); - - if (!preserveDayOfWeekTimeOfDay) { - // Move timestamp relative to now, preserving distance between currentTimeMarker and timestamp - const timeDelta = timestampDate.getTime() - currentTimeMarker.getTime(); - return (new Date(now.getTime() + timeDelta)).toISOString(); - } - - // Move timestamp to current week, preserving day of week and time of day - const weekDelta = Math.round((timestampDate.getTime() - currentTimeMarker.getTime()) / (MILLISECONDS_IN_DAY * 7)); - const dayOfWeekDelta = timestampDate.getDay() - now.getDay(); - const daysDelta = dayOfWeekDelta * MILLISECONDS_IN_DAY + (weekDelta * MILLISECONDS_IN_DAY * 7); - const yearMonthDay = (new Date(now.getTime() + daysDelta)).toISOString().substring(0, 10); - return `${yearMonthDay}T${timestamp.substring(11)}`; - -} diff --git a/src/server/sample_data/routes/lib/adjust_timestamp.test.js b/src/server/sample_data/routes/lib/adjust_timestamp.test.js deleted file mode 100644 index ee74537058ece..0000000000000 --- a/src/server/sample_data/routes/lib/adjust_timestamp.test.js +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - -import { adjustTimestamp } from './adjust_timestamp'; - -const currentTimeMarker = new Date(Date.parse('2018-01-02T00:00:00Z')); -const now = new Date(Date.parse('2018-04-25T18:24:58.650Z')); // Wednesday - -describe('relative to now', () => { - test('adjusts time to 10 minutes in past from now', () => { - const originalTimestamp = '2018-01-01T23:50:00Z'; // -10 minutes relative to currentTimeMarker - const timestamp = adjustTimestamp(originalTimestamp, currentTimeMarker, now, false); - expect(timestamp).toBe('2018-04-25T18:14:58.650Z'); - }); - - test('adjusts time to 1 hour in future from now', () => { - const originalTimestamp = '2018-01-02T01:00:00Z'; // + 1 hour relative to currentTimeMarker - const timestamp = adjustTimestamp(originalTimestamp, currentTimeMarker, now, false); - expect(timestamp).toBe('2018-04-25T19:24:58.650Z'); - }); -}); - -describe('preserve day of week and time of day', () => { - test('adjusts time to monday of the same week as now', () => { - const originalTimestamp = '2018-01-01T23:50:00Z'; // Monday, same week relative to currentTimeMarker - const timestamp = adjustTimestamp(originalTimestamp, currentTimeMarker, now, true); - expect(timestamp).toBe('2018-04-23T23:50:00Z'); - }); - - test('adjusts time to friday of the same week as now', () => { - const originalTimestamp = '2017-12-29T23:50:00Z'; // Friday, same week relative to currentTimeMarker - const timestamp = adjustTimestamp(originalTimestamp, currentTimeMarker, now, true); - expect(timestamp).toBe('2018-04-27T23:50:00Z'); - }); - - test('adjusts time to monday of the previous week as now', () => { - const originalTimestamp = '2017-12-25T23:50:00Z'; // Monday, previous week relative to currentTimeMarker - const timestamp = adjustTimestamp(originalTimestamp, currentTimeMarker, now, true); - expect(timestamp).toBe('2018-04-16T23:50:00Z'); - }); - - test('adjusts time to friday of the week after now', () => { - const originalTimestamp = '2018-01-05T23:50:00Z'; // Friday, next week relative to currentTimeMarker - const timestamp = adjustTimestamp(originalTimestamp, currentTimeMarker, now, true); - expect(timestamp).toBe('2018-05-04T23:50:00Z'); - }); - - test('adjusts timestamp to correct day of week even when UTC day is on different day.', () => { - const currentTimeMarker = new Date(Date.parse('2018-01-02T00:00:00')); // Tuesday - const now = new Date(Date.parse('2018-06-14T10:38')); // Thurs - const originalTimestamp = '2018-01-01T17:57:25'; // Monday - const timestamp = adjustTimestamp(originalTimestamp, currentTimeMarker, now, true); - expect(timestamp).toBe('2018-06-11T17:57:25'); // Monday - }); -}); - diff --git a/src/server/sample_data/routes/lib/translate_timestamp.js b/src/server/sample_data/routes/lib/translate_timestamp.js new file mode 100644 index 0000000000000..f8d0f86e49709 --- /dev/null +++ b/src/server/sample_data/routes/lib/translate_timestamp.js @@ -0,0 +1,75 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +const MILLISECONDS_IN_DAY = 86400000; + +function iso8601ToDateIgnoringTime(iso8601) { + const split = iso8601.split('-'); + if (split.length < 3) { + throw new Error('Unexpected timestamp format, expecting YYYY-MM-DDTHH:mm:ss'); + } + const year = parseInt(split[0]); + const month = parseInt(split[1]) - 1; // javascript months are zero-based indexed + const date = parseInt(split[2]); + return new Date(year, month, date); +} + +export function dateToIso8601IgnoringTime(date) { + // not using "Date.toISOString" because only using Date methods that deal with local time + const year = date.getFullYear(); + const month = date.getMonth() + 1; + const monthString = month < 10 ? `0${month}` : `${month}`; + const dateString = date.getDate() < 10 ? `0${date.getDate()}` : `${date.getDate()}`; + return `${year}-${monthString}-${dateString}`; +} + +// Translate source timestamp by targetReference timestamp, +// perserving the distance between source and sourceReference +export function translateTimeRelativeToDifference(source, sourceReference, targetReference) { + const sourceDate = iso8601ToDateIgnoringTime(source); + const sourceReferenceDate = iso8601ToDateIgnoringTime(sourceReference); + const targetReferenceDate = iso8601ToDateIgnoringTime(targetReference); + + const timeDelta = sourceDate.getTime() - sourceReferenceDate.getTime(); + const translatedDate = (new Date(targetReferenceDate.getTime() + timeDelta)); + + return `${dateToIso8601IgnoringTime(translatedDate)}T${source.substring(11)}`; +} + +// Translate source timestamp by targetReference timestamp, +// perserving the week distance between source and sourceReference and day of week of the source timestamp +export function translateTimeRelativeToWeek(source, sourceReference, targetReference) { + const sourceReferenceDate = iso8601ToDateIgnoringTime(sourceReference); + const targetReferenceDate = iso8601ToDateIgnoringTime(targetReference); + + // If these dates were in the same week, how many days apart would they be? + const dayOfWeekDelta = sourceReferenceDate.getDay() - targetReferenceDate.getDay(); + + // If we pretend that the targetReference is actually the same day of the week as the + // sourceReference, then we can translate the source to the target while preserving their + // days of the week. + const normalizationDelta = dayOfWeekDelta * MILLISECONDS_IN_DAY; + const normalizedTargetReference = + dateToIso8601IgnoringTime(new Date(targetReferenceDate.getTime() + normalizationDelta)); + + return translateTimeRelativeToDifference( + source, + sourceReference, + normalizedTargetReference); +} diff --git a/src/server/sample_data/routes/lib/translate_timestamp.test.js b/src/server/sample_data/routes/lib/translate_timestamp.test.js new file mode 100644 index 0000000000000..348fd2b429167 --- /dev/null +++ b/src/server/sample_data/routes/lib/translate_timestamp.test.js @@ -0,0 +1,107 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +import { translateTimeRelativeToWeek } from './translate_timestamp'; + +describe('translateTimeRelativeToWeek', () => { + const sourceReference = '2018-01-02T00:00:00'; //Tuesday + const targetReference = '2018-04-25T18:24:58.650'; // Wednesday + + describe('2 weeks before', () => { + test('should properly adjust timestamp when day is before targetReference day of week', () => { + const source = '2017-12-18T23:50:00'; // Monday, -2 week relative to sourceReference + const timestamp = translateTimeRelativeToWeek(source, sourceReference, targetReference); + expect(timestamp).toBe('2018-04-09T23:50:00'); // Monday 2 week before targetReference week + }); + + test('should properly adjust timestamp when day is same as targetReference day of week', () => { + const source = '2017-12-20T23:50:00'; // Wednesday, -2 week relative to sourceReference + const timestamp = translateTimeRelativeToWeek(source, sourceReference, targetReference); + expect(timestamp).toBe('2018-04-11T23:50:00'); // Wednesday 2 week before targetReference week + }); + + test('should properly adjust timestamp when day is after targetReference day of week', () => { + const source = '2017-12-22T16:16:50'; // Friday, -2 week relative to sourceReference + const timestamp = translateTimeRelativeToWeek(source, sourceReference, targetReference); + expect(timestamp).toBe('2018-04-13T16:16:50'); // Friday 2 week before targetReference week + }); + }); + + describe('week before', () => { + test('should properly adjust timestamp when day is before targetReference day of week', () => { + const source = '2017-12-25T23:50:00'; // Monday, -1 week relative to sourceReference + const timestamp = translateTimeRelativeToWeek(source, sourceReference, targetReference); + expect(timestamp).toBe('2018-04-16T23:50:00'); // Monday 1 week before targetReference week + }); + + test('should properly adjust timestamp when day is same as targetReference day of week', () => { + const source = '2017-12-27T23:50:00'; // Wednesday, -1 week relative to sourceReference + const timestamp = translateTimeRelativeToWeek(source, sourceReference, targetReference); + expect(timestamp).toBe('2018-04-18T23:50:00'); // Wednesday 1 week before targetReference week + }); + + test('should properly adjust timestamp when day is after targetReference day of week', () => { + const source = '2017-12-29T16:16:50'; // Friday, -1 week relative to sourceReference + const timestamp = translateTimeRelativeToWeek(source, sourceReference, targetReference); + expect(timestamp).toBe('2018-04-20T16:16:50'); // Friday 1 week before targetReference week + }); + }); + + describe('same week', () => { + test('should properly adjust timestamp when day is before targetReference day of week', () => { + const source = '2018-01-01T23:50:00'; // Monday, same week relative to sourceReference + const timestamp = translateTimeRelativeToWeek(source, sourceReference, targetReference); + expect(timestamp).toBe('2018-04-23T23:50:00'); // Monday same week as targetReference + }); + + test('should properly adjust timestamp when day is same as targetReference day of week', () => { + const source = '2018-01-03T23:50:00'; // Wednesday, same week relative to sourceReference + const timestamp = translateTimeRelativeToWeek(source, sourceReference, targetReference); + expect(timestamp).toBe('2018-04-25T23:50:00'); // Wednesday same week as targetReference + }); + + test('should properly adjust timestamp when day is after targetReference day of week', () => { + const source = '2018-01-05T16:16:50'; // Friday, same week relative to sourceReference + const timestamp = translateTimeRelativeToWeek(source, sourceReference, targetReference); + expect(timestamp).toBe('2018-04-27T16:16:50'); // Friday same week as targetReference + }); + }); + + describe('week after', () => { + test('should properly adjust timestamp when day is before targetReference day of week', () => { + const source = '2018-01-08T23:50:00'; // Monday, 1 week after relative to sourceReference + const timestamp = translateTimeRelativeToWeek(source, sourceReference, targetReference); + expect(timestamp).toBe('2018-04-30T23:50:00'); // Monday 1 week after targetReference week + }); + + test('should properly adjust timestamp when day is same as targetReference day of week', () => { + const source = '2018-01-10T23:50:00'; // Wednesday, same week relative to sourceReference + const timestamp = translateTimeRelativeToWeek(source, sourceReference, targetReference); + expect(timestamp).toBe('2018-05-02T23:50:00'); // Wednesday 1 week after targetReference week + }); + + test('should properly adjust timestamp when day is after targetReference day of week', () => { + const source = '2018-01-12T16:16:50'; // Friday, same week relative to sourceReference + const timestamp = translateTimeRelativeToWeek(source, sourceReference, targetReference); + expect(timestamp).toBe('2018-05-04T16:16:50'); // Friday 1 week after targetReference week + }); + }); +}); + diff --git a/test/functional/apps/home/_sample_data.js b/test/functional/apps/home/_sample_data.js index c615ff5ea362a..48cc3cf509936 100644 --- a/test/functional/apps/home/_sample_data.js +++ b/test/functional/apps/home/_sample_data.js @@ -50,8 +50,7 @@ export default function ({ getService, getPageObjects }) { expect(isInstalled).to.be(true); }); - // Skipping issue # 20807 - describe.skip('dashboard', () => { + describe('dashboard', () => { after(async () => { await PageObjects.common.navigateToUrl('home', 'tutorial_directory/sampleData'); await PageObjects.header.waitUntilLoadingHasFinished();