From 322c2aff540393c967e2f7712c4866b7ecd27ecf Mon Sep 17 00:00:00 2001 From: Anton Date: Tue, 4 Jun 2019 11:34:05 +0800 Subject: [PATCH 01/13] added 2 new blocks for date/time conversion --- .../view/blockly/blocks/tools/time/index.js | 2 ++ .../blockly/blocks/tools/time/todatetime.js | 25 ++++++++++++++++++ .../blockly/blocks/tools/time/totimestamp.js | 26 +++++++++++++++++++ static/xml/toolbox.xml | 14 ++++++++++ 4 files changed, 67 insertions(+) create mode 100644 src/botPage/view/blockly/blocks/tools/time/todatetime.js create mode 100644 src/botPage/view/blockly/blocks/tools/time/totimestamp.js diff --git a/src/botPage/view/blockly/blocks/tools/time/index.js b/src/botPage/view/blockly/blocks/tools/time/index.js index 2c41b91b5b..6dc16d8fa4 100644 --- a/src/botPage/view/blockly/blocks/tools/time/index.js +++ b/src/botPage/view/blockly/blocks/tools/time/index.js @@ -1,3 +1,5 @@ import './epoch'; import './timeout'; import './interval'; +import './todatetime'; +import './totimestamp'; diff --git a/src/botPage/view/blockly/blocks/tools/time/todatetime.js b/src/botPage/view/blockly/blocks/tools/time/todatetime.js new file mode 100644 index 0000000000..37063c5bcc --- /dev/null +++ b/src/botPage/view/blockly/blocks/tools/time/todatetime.js @@ -0,0 +1,25 @@ +// https://blockly-demo.appspot.com/static/demos/blockfactory/index.html#wupwb4 +import { translate } from '../../../../../../common/i18n'; +// import { disable } from '../../../utils'; + +Blockly.Blocks.todatetime = { + init: function init() { + this.appendDummyInput(); + this.appendValueInput('TIMESTAMP').appendField(translate('To Date/Time')); + this.setInputsInline(true); + this.setOutput(true, 'String'); + this.setColour('#dedede'); + this.setTooltip( + translate( + 'Convert a string representing a date/time string into seconds since Epoch. Input format: yyyy-mm-dd hh:mm:ss' + ) + ); + // this.setHelpUrl('https://github.com/binary-com/binary-bot/wiki'); + }, +}; + +Blockly.JavaScript.todatetime = block => { + const timestamp = Blockly.JavaScript.valueToCode(block, 'TIMESTAMP', Blockly.JavaScript.ORDER_ATOMIC); + const code = `Bot.timestampToDateTimeString(${timestamp})`; + return [code, Blockly.JavaScript.ORDER_ATOMIC]; +}; diff --git a/src/botPage/view/blockly/blocks/tools/time/totimestamp.js b/src/botPage/view/blockly/blocks/tools/time/totimestamp.js new file mode 100644 index 0000000000..028b9a03ea --- /dev/null +++ b/src/botPage/view/blockly/blocks/tools/time/totimestamp.js @@ -0,0 +1,26 @@ +// https://blockly-demo.appspot.com/static/demos/blockfactory/index.html#wupwb4 +import { translate } from '../../../../../../common/i18n'; +import { dateToTimeString } from 'binary-utils/lib'; +// import { disable } from '../../../utils'; + +Blockly.Blocks.totimestamp = { + init: function init() { + this.appendDummyInput(); + this.appendValueInput('DATETIME').appendField(translate('To Timestamp')); + this.setInputsInline(true); + this.setOutput(true, 'Number'); + this.setColour('#dedede'); + this.setTooltip( + translate( + 'Convert a string representing a date/time string into seconds since Epoch. Input format: yyyy-mm-dd hh:mm:ss' + ) + ); + // this.setHelpUrl('https://github.com/binary-com/binary-bot/wiki'); + }, +}; + +Blockly.JavaScript.totimestamp = block => { + const dString = Blockly.JavaScript.valueToCode(block, 'DATETIME', Blockly.JavaScript.ORDER_ATOMIC); + const code = `Bot.dateTimeStringToTimestamp('${dString}')`; + return [code, Blockly.JavaScript.ORDER_NONE]; +}; diff --git a/static/xml/toolbox.xml b/static/xml/toolbox.xml index d19db21264..776f5c8831 100644 --- a/static/xml/toolbox.xml +++ b/static/xml/toolbox.xml @@ -409,6 +409,20 @@ + + + + yyyy-mm-dd hh:mm:ss + + + + + + + 0 + + + From 4b35fb0a7868ac967534f4c905d1f002dd738e6c Mon Sep 17 00:00:00 2001 From: Anton Date: Tue, 4 Jun 2019 15:45:03 +0800 Subject: [PATCH 02/13] fix for time conversion blocks --- .../blockly/blocks/tools/time/todatetime.js | 32 +++++++++++++++++-- .../blockly/blocks/tools/time/totimestamp.js | 25 ++++++++++++--- 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/botPage/view/blockly/blocks/tools/time/todatetime.js b/src/botPage/view/blockly/blocks/tools/time/todatetime.js index 37063c5bcc..1c399dd6a8 100644 --- a/src/botPage/view/blockly/blocks/tools/time/todatetime.js +++ b/src/botPage/view/blockly/blocks/tools/time/todatetime.js @@ -11,7 +11,7 @@ Blockly.Blocks.todatetime = { this.setColour('#dedede'); this.setTooltip( translate( - 'Convert a string representing a date/time string into seconds since Epoch. Input format: yyyy-mm-dd hh:mm:ss' + 'Converts a string representing a date/time string into seconds since Epoch. Input format: yyyy-mm-dd hh:mm:ss' ) ); // this.setHelpUrl('https://github.com/binary-com/binary-bot/wiki'); @@ -19,7 +19,33 @@ Blockly.Blocks.todatetime = { }; Blockly.JavaScript.todatetime = block => { + // const timestamp = Blockly.JavaScript.valueToCode(block, 'TIMESTAMP', Blockly.JavaScript.ORDER_ATOMIC); + // const code = `Bot.timestampToDateTimeString(${timestamp})`; + // return [code, Blockly.JavaScript.ORDER_ATOMIC]; + const timestamp = Blockly.JavaScript.valueToCode(block, 'TIMESTAMP', Blockly.JavaScript.ORDER_ATOMIC); - const code = `Bot.timestampToDateTimeString(${timestamp})`; - return [code, Blockly.JavaScript.ORDER_ATOMIC]; + + // eslint-disable-next-line no-underscore-dangle + const functionName = Blockly.JavaScript.provideFunction_('timestampToDateString', [ + // eslint-disable-next-line no-underscore-dangle + `function ${Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_}(timestamp) { + var dateTime; + if(typeof timestamp == 'number') { + dateTime = new Date(timestamp * 1000); + } + return [ + dateTime.getFullYear().toString(), + dateTime.getMonth()+1 < 10 ? '0' + (dateTime.getMonth()+1) : dateTime.getMonth()+1, + dateTime.getDate() < 10 ? '0' + dateTime.getDate() : dateTime.getDate() + ].join('-') + ' ' + + [ + dateTime.getHours() < 10 ? '0' + dateTime.getHours() : dateTime.getHours(), + dateTime.getMinutes() < 10 ? '0' + dateTime.getMinutes() : dateTime.getMinutes(), + dateTime.getSeconds() < 10 ? '0' + dateTime.getSeconds() : dateTime.getSeconds() + ].join(':'); + }`, + ]); + + const code = `${functionName}(${timestamp})`; + return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; }; diff --git a/src/botPage/view/blockly/blocks/tools/time/totimestamp.js b/src/botPage/view/blockly/blocks/tools/time/totimestamp.js index 028b9a03ea..e757e8f150 100644 --- a/src/botPage/view/blockly/blocks/tools/time/totimestamp.js +++ b/src/botPage/view/blockly/blocks/tools/time/totimestamp.js @@ -1,6 +1,6 @@ // https://blockly-demo.appspot.com/static/demos/blockfactory/index.html#wupwb4 import { translate } from '../../../../../../common/i18n'; -import { dateToTimeString } from 'binary-utils/lib'; +// import { dateToTimeString } from 'binary-utils/lib'; // import { disable } from '../../../utils'; Blockly.Blocks.totimestamp = { @@ -12,7 +12,7 @@ Blockly.Blocks.totimestamp = { this.setColour('#dedede'); this.setTooltip( translate( - 'Convert a string representing a date/time string into seconds since Epoch. Input format: yyyy-mm-dd hh:mm:ss' + 'Converts a string representing a date/time string into seconds since Epoch. Input format: yyyy-mm-dd hh:mm:ss' ) ); // this.setHelpUrl('https://github.com/binary-com/binary-bot/wiki'); @@ -20,7 +20,22 @@ Blockly.Blocks.totimestamp = { }; Blockly.JavaScript.totimestamp = block => { - const dString = Blockly.JavaScript.valueToCode(block, 'DATETIME', Blockly.JavaScript.ORDER_ATOMIC); - const code = `Bot.dateTimeStringToTimestamp('${dString}')`; - return [code, Blockly.JavaScript.ORDER_NONE]; + // const dString = Blockly.JavaScript.valueToCode(block, 'DATETIME', Blockly.JavaScript.ORDER_ATOMIC); + // const code = `Bot.dateTimeStringToTimestamp('${dString}')`; + // return [code, Blockly.JavaScript.ORDER_NONE]; + + // YYYY-MM-DD HH:MM:SS format + const dateString = Blockly.JavaScript.valueToCode(block, 'DATETIME', Blockly.JavaScript.ORDER_ATOMIC); + + // eslint-disable-next-line no-underscore-dangle + const functionName = Blockly.JavaScript.provideFunction_('dateTimeStringToTimestamp', [ + // eslint-disable-next-line no-underscore-dangle + `function ${Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_}(dateTimeString) { + var date = new Date(dateTimeString); + return date ? date.getTime() / 1000 : 'Invalid date/time'; + }`, + ]); + + const code = `${functionName}(${dateString})`; + return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; }; From 6c161f4f9695048be1551fd15d5deaf719398c40 Mon Sep 17 00:00:00 2001 From: Anton Date: Tue, 11 Jun 2019 14:05:06 +0800 Subject: [PATCH 03/13] fix for error messages --- src/botPage/view/blockly/blocks/tools/time/todatetime.js | 9 ++++----- .../view/blockly/blocks/tools/time/totimestamp.js | 9 +++++++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/botPage/view/blockly/blocks/tools/time/todatetime.js b/src/botPage/view/blockly/blocks/tools/time/todatetime.js index 1c399dd6a8..0746aef765 100644 --- a/src/botPage/view/blockly/blocks/tools/time/todatetime.js +++ b/src/botPage/view/blockly/blocks/tools/time/todatetime.js @@ -5,7 +5,7 @@ import { translate } from '../../../../../../common/i18n'; Blockly.Blocks.todatetime = { init: function init() { this.appendDummyInput(); - this.appendValueInput('TIMESTAMP').appendField(translate('To Date/Time')); + this.appendValueInput('TIMESTAMP').appendField('To Date/Time'); this.setInputsInline(true); this.setOutput(true, 'String'); this.setColour('#dedede'); @@ -19,19 +19,18 @@ Blockly.Blocks.todatetime = { }; Blockly.JavaScript.todatetime = block => { - // const timestamp = Blockly.JavaScript.valueToCode(block, 'TIMESTAMP', Blockly.JavaScript.ORDER_ATOMIC); - // const code = `Bot.timestampToDateTimeString(${timestamp})`; - // return [code, Blockly.JavaScript.ORDER_ATOMIC]; - const timestamp = Blockly.JavaScript.valueToCode(block, 'TIMESTAMP', Blockly.JavaScript.ORDER_ATOMIC); // eslint-disable-next-line no-underscore-dangle const functionName = Blockly.JavaScript.provideFunction_('timestampToDateString', [ // eslint-disable-next-line no-underscore-dangle + `function ${Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_}(timestamp) { var dateTime; if(typeof timestamp == 'number') { dateTime = new Date(timestamp * 1000); + } else { + return '${translate('Invalid timestamp')}: ' + timestamp; } return [ dateTime.getFullYear().toString(), diff --git a/src/botPage/view/blockly/blocks/tools/time/totimestamp.js b/src/botPage/view/blockly/blocks/tools/time/totimestamp.js index e757e8f150..1f97f8b366 100644 --- a/src/botPage/view/blockly/blocks/tools/time/totimestamp.js +++ b/src/botPage/view/blockly/blocks/tools/time/totimestamp.js @@ -31,8 +31,13 @@ Blockly.JavaScript.totimestamp = block => { const functionName = Blockly.JavaScript.provideFunction_('dateTimeStringToTimestamp', [ // eslint-disable-next-line no-underscore-dangle `function ${Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_}(dateTimeString) { - var date = new Date(dateTimeString); - return date ? date.getTime() / 1000 : 'Invalid date/time'; + var p = /([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])\s(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]))/; + if(p.test(dateTimeString)) { + var date = new Date(dateTimeString); + } else { + return '${translate('Invalid date/time')}: ' + dateTimeString; + } + return date ? date.getTime() / 1000 : '${translate('Invalid date/time')}: ' + dateTimeString; }`, ]); From 4fe495d923ebd5b58119bb9b1ba58614198ebe93 Mon Sep 17 00:00:00 2001 From: Anton Date: Tue, 11 Jun 2019 16:06:25 +0800 Subject: [PATCH 04/13] added tests --- src/botPage/bot/Interface/ToolsInterface.js | 27 ++++++++++++++++- .../__tests__/block-tests/tools-test/Time.js | 30 ++++++++++++++++++- .../blockly/blocks/tools/time/todatetime.js | 17 +---------- .../blockly/blocks/tools/time/totimestamp.js | 14 +-------- 4 files changed, 57 insertions(+), 31 deletions(-) diff --git a/src/botPage/bot/Interface/ToolsInterface.js b/src/botPage/bot/Interface/ToolsInterface.js index 90fb23f451..f4c1085ca8 100644 --- a/src/botPage/bot/Interface/ToolsInterface.js +++ b/src/botPage/bot/Interface/ToolsInterface.js @@ -1,13 +1,38 @@ import CandleInterface from './CandleInterface'; import MiscInterface from './MiscInterface'; import IndicatorsInterface from './IndicatorsInterface'; +import { translate } from '../../../common/i18n'; // prettier-ignore export default Interface => class extends IndicatorsInterface( MiscInterface(CandleInterface(Interface))) { getToolsInterface() { return { - getTime: () => parseInt(new Date().getTime() / 1000), + getTime : () => parseInt(new Date().getTime() / 1000), + toDateTime: (timestamp) => { + let dateTime; + if(typeof timestamp === 'number') { + dateTime = new Date(timestamp * 1000); + return `${[ + dateTime.getFullYear().toString(), + dateTime.getMonth()+1 < 10 ? `0${ dateTime.getMonth()+1}` : dateTime.getMonth()+1, + dateTime.getDate() < 10 ? `0${ dateTime.getDate()}` : dateTime.getDate(), + ].join('-') } ${[ + dateTime.getHours() < 10 ? `0${ dateTime.getHours()}` : dateTime.getHours(), + dateTime.getMinutes() < 10 ? `0${ dateTime.getMinutes()}` : dateTime.getMinutes(), + dateTime.getSeconds() < 10 ? `0${ dateTime.getSeconds()}` : dateTime.getSeconds(), + ].join(':')}`; + } + return `${translate('Invalid timestamp')}: ${timestamp}`; + }, + toTimestamp: (dateTimeString) => { + const p = /([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])\s(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]))/; + if(p.test(dateTimeString)) { + const date = new Date(dateTimeString); + return date ? date.getTime() / 1000 : `${translate('Invalid date/time')}: ${dateTimeString}`; + } + return `${translate('Invalid date/time')}: ${dateTimeString}`; + }, ...this.getCandleInterface(), ...this.getMiscInterface(), ...this.getIndicatorsInterface(), diff --git a/src/botPage/bot/__tests__/block-tests/tools-test/Time.js b/src/botPage/bot/__tests__/block-tests/tools-test/Time.js index 344f02c738..66abb5596d 100644 --- a/src/botPage/bot/__tests__/block-tests/tools-test/Time.js +++ b/src/botPage/bot/__tests__/block-tests/tools-test/Time.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { run } from '../../tools'; +import { run, runAndGetResult } from '../tools'; describe('Time in tools', () => { let result; @@ -27,3 +27,31 @@ describe('Time in tools', () => { expect(time2 - time1).most(3); }); }); + +describe('Convert to date/time string', () => { + const timestamp = '1560238593'; + let result; + beforeAll(done => { + runAndGetResult(undefined, `Bot.toDateTime(${timestamp})`).then(v => { + result = v; + done(); + }); + }); + it('converts timestamp to date/time string', () => { + expect(result).satisfy(dt => dt === '2019-06-11 15:36:33'); + }); +}); + +describe('Convert to timestamp', () => { + const dateTime = '2019-06-11 15:36:33'; + let result; + beforeAll(done => { + runAndGetResult(undefined, `Bot.toTimestamp(${dateTime})`).then(v => { + result = v; + done(); + }); + }); + it('converts date/time string to timestamp', () => { + expect(result).satisfy(ts => ts === '1560238593'); + }); +}); diff --git a/src/botPage/view/blockly/blocks/tools/time/todatetime.js b/src/botPage/view/blockly/blocks/tools/time/todatetime.js index 0746aef765..a0dae6d0b9 100644 --- a/src/botPage/view/blockly/blocks/tools/time/todatetime.js +++ b/src/botPage/view/blockly/blocks/tools/time/todatetime.js @@ -26,22 +26,7 @@ Blockly.JavaScript.todatetime = block => { // eslint-disable-next-line no-underscore-dangle `function ${Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_}(timestamp) { - var dateTime; - if(typeof timestamp == 'number') { - dateTime = new Date(timestamp * 1000); - } else { - return '${translate('Invalid timestamp')}: ' + timestamp; - } - return [ - dateTime.getFullYear().toString(), - dateTime.getMonth()+1 < 10 ? '0' + (dateTime.getMonth()+1) : dateTime.getMonth()+1, - dateTime.getDate() < 10 ? '0' + dateTime.getDate() : dateTime.getDate() - ].join('-') + ' ' + - [ - dateTime.getHours() < 10 ? '0' + dateTime.getHours() : dateTime.getHours(), - dateTime.getMinutes() < 10 ? '0' + dateTime.getMinutes() : dateTime.getMinutes(), - dateTime.getSeconds() < 10 ? '0' + dateTime.getSeconds() : dateTime.getSeconds() - ].join(':'); + return Bot.toDateTime(timestamp); }`, ]); diff --git a/src/botPage/view/blockly/blocks/tools/time/totimestamp.js b/src/botPage/view/blockly/blocks/tools/time/totimestamp.js index 1f97f8b366..7ae8fc1342 100644 --- a/src/botPage/view/blockly/blocks/tools/time/totimestamp.js +++ b/src/botPage/view/blockly/blocks/tools/time/totimestamp.js @@ -20,24 +20,12 @@ Blockly.Blocks.totimestamp = { }; Blockly.JavaScript.totimestamp = block => { - // const dString = Blockly.JavaScript.valueToCode(block, 'DATETIME', Blockly.JavaScript.ORDER_ATOMIC); - // const code = `Bot.dateTimeStringToTimestamp('${dString}')`; - // return [code, Blockly.JavaScript.ORDER_NONE]; - - // YYYY-MM-DD HH:MM:SS format const dateString = Blockly.JavaScript.valueToCode(block, 'DATETIME', Blockly.JavaScript.ORDER_ATOMIC); - // eslint-disable-next-line no-underscore-dangle const functionName = Blockly.JavaScript.provideFunction_('dateTimeStringToTimestamp', [ // eslint-disable-next-line no-underscore-dangle `function ${Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_}(dateTimeString) { - var p = /([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])\s(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]))/; - if(p.test(dateTimeString)) { - var date = new Date(dateTimeString); - } else { - return '${translate('Invalid date/time')}: ' + dateTimeString; - } - return date ? date.getTime() / 1000 : '${translate('Invalid date/time')}: ' + dateTimeString; + return Bot.toTimestamp(dateTimeString); }`, ]); From a82e899e4f0153bd2fd994da6e532ed6ec0e9eb9 Mon Sep 17 00:00:00 2001 From: Anton Date: Wed, 12 Jun 2019 09:49:09 +0800 Subject: [PATCH 05/13] fixes following code review suggestions --- src/botPage/bot/Interface/ToolsInterface.js | 36 +++++++++++-------- .../__tests__/block-tests/tools-test/Time.js | 2 +- .../blockly/blocks/tools/time/todatetime.js | 7 +--- .../blockly/blocks/tools/time/totimestamp.js | 4 --- 4 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/botPage/bot/Interface/ToolsInterface.js b/src/botPage/bot/Interface/ToolsInterface.js index f4c1085ca8..b5a4ddcc1e 100644 --- a/src/botPage/bot/Interface/ToolsInterface.js +++ b/src/botPage/bot/Interface/ToolsInterface.js @@ -10,28 +10,34 @@ export default Interface => class extends IndicatorsInterface( return { getTime : () => parseInt(new Date().getTime() / 1000), toDateTime: (timestamp) => { - let dateTime; + const getTwoDigitValue = input => { + if (input < 10) { + return `0${input}`; + } + return `${input}`; + } if(typeof timestamp === 'number') { - dateTime = new Date(timestamp * 1000); - return `${[ - dateTime.getFullYear().toString(), - dateTime.getMonth()+1 < 10 ? `0${ dateTime.getMonth()+1}` : dateTime.getMonth()+1, - dateTime.getDate() < 10 ? `0${ dateTime.getDate()}` : dateTime.getDate(), - ].join('-') } ${[ - dateTime.getHours() < 10 ? `0${ dateTime.getHours()}` : dateTime.getHours(), - dateTime.getMinutes() < 10 ? `0${ dateTime.getMinutes()}` : dateTime.getMinutes(), - dateTime.getSeconds() < 10 ? `0${ dateTime.getSeconds()}` : dateTime.getSeconds(), - ].join(':')}`; + const dateTime = new Date(timestamp * 1000); + + const year = dateTime.getFullYear(); + const month = getTwoDigitValue(dateTime.getMonth() + 1); + const day = getTwoDigitValue(dateTime.getDate()); + const hours = getTwoDigitValue(dateTime.getHours()); + const minutes = getTwoDigitValue(dateTime.getMinutes()); + const seconds = getTwoDigitValue(dateTime.getSeconds()); + + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; } return `${translate('Invalid timestamp')}: ${timestamp}`; }, toTimestamp: (dateTimeString) => { - const p = /([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])\s(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]))/; - if(p.test(dateTimeString)) { + const p = /^([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])\s(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]))$/; + const invalidDateTime = () => `${translate('Invalid date/time')}: ${dateTimeString}`; + if (p.test(dateTimeString)) { const date = new Date(dateTimeString); - return date ? date.getTime() / 1000 : `${translate('Invalid date/time')}: ${dateTimeString}`; + return date ? date.getTime() / 1000 : invalidDateTime(); } - return `${translate('Invalid date/time')}: ${dateTimeString}`; + return invalidDateTime(); }, ...this.getCandleInterface(), ...this.getMiscInterface(), diff --git a/src/botPage/bot/__tests__/block-tests/tools-test/Time.js b/src/botPage/bot/__tests__/block-tests/tools-test/Time.js index 66abb5596d..224437f637 100644 --- a/src/botPage/bot/__tests__/block-tests/tools-test/Time.js +++ b/src/botPage/bot/__tests__/block-tests/tools-test/Time.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { run, runAndGetResult } from '../tools'; +import { run, runAndGetResult } from '../../tools'; describe('Time in tools', () => { let result; diff --git a/src/botPage/view/blockly/blocks/tools/time/todatetime.js b/src/botPage/view/blockly/blocks/tools/time/todatetime.js index a0dae6d0b9..de821280ec 100644 --- a/src/botPage/view/blockly/blocks/tools/time/todatetime.js +++ b/src/botPage/view/blockly/blocks/tools/time/todatetime.js @@ -1,11 +1,9 @@ -// https://blockly-demo.appspot.com/static/demos/blockfactory/index.html#wupwb4 import { translate } from '../../../../../../common/i18n'; -// import { disable } from '../../../utils'; Blockly.Blocks.todatetime = { init: function init() { this.appendDummyInput(); - this.appendValueInput('TIMESTAMP').appendField('To Date/Time'); + this.appendValueInput('TIMESTAMP').appendField(translate('To Date/Time')); this.setInputsInline(true); this.setOutput(true, 'String'); this.setColour('#dedede'); @@ -14,17 +12,14 @@ Blockly.Blocks.todatetime = { 'Converts a string representing a date/time string into seconds since Epoch. Input format: yyyy-mm-dd hh:mm:ss' ) ); - // this.setHelpUrl('https://github.com/binary-com/binary-bot/wiki'); }, }; Blockly.JavaScript.todatetime = block => { const timestamp = Blockly.JavaScript.valueToCode(block, 'TIMESTAMP', Blockly.JavaScript.ORDER_ATOMIC); - // eslint-disable-next-line no-underscore-dangle const functionName = Blockly.JavaScript.provideFunction_('timestampToDateString', [ // eslint-disable-next-line no-underscore-dangle - `function ${Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_}(timestamp) { return Bot.toDateTime(timestamp); }`, diff --git a/src/botPage/view/blockly/blocks/tools/time/totimestamp.js b/src/botPage/view/blockly/blocks/tools/time/totimestamp.js index 7ae8fc1342..849e698cf4 100644 --- a/src/botPage/view/blockly/blocks/tools/time/totimestamp.js +++ b/src/botPage/view/blockly/blocks/tools/time/totimestamp.js @@ -1,7 +1,4 @@ -// https://blockly-demo.appspot.com/static/demos/blockfactory/index.html#wupwb4 import { translate } from '../../../../../../common/i18n'; -// import { dateToTimeString } from 'binary-utils/lib'; -// import { disable } from '../../../utils'; Blockly.Blocks.totimestamp = { init: function init() { @@ -15,7 +12,6 @@ Blockly.Blocks.totimestamp = { 'Converts a string representing a date/time string into seconds since Epoch. Input format: yyyy-mm-dd hh:mm:ss' ) ); - // this.setHelpUrl('https://github.com/binary-com/binary-bot/wiki'); }, }; From 9efa44a4d8f692448cde425394c288e1fed7476a Mon Sep 17 00:00:00 2001 From: Anton Date: Wed, 12 Jun 2019 13:14:49 +0800 Subject: [PATCH 06/13] fixed tests --- src/botPage/bot/__tests__/block-tests/tools-test/Time.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/botPage/bot/__tests__/block-tests/tools-test/Time.js b/src/botPage/bot/__tests__/block-tests/tools-test/Time.js index 224437f637..14dc4edbd1 100644 --- a/src/botPage/bot/__tests__/block-tests/tools-test/Time.js +++ b/src/botPage/bot/__tests__/block-tests/tools-test/Time.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { run, runAndGetResult } from '../../tools'; +import { run } from '../../tools'; describe('Time in tools', () => { let result; @@ -32,7 +32,7 @@ describe('Convert to date/time string', () => { const timestamp = '1560238593'; let result; beforeAll(done => { - runAndGetResult(undefined, `Bot.toDateTime(${timestamp})`).then(v => { + run(`(function() {return Bot.toDateTime(${timestamp});})()`).then(v => { result = v; done(); }); @@ -46,12 +46,12 @@ describe('Convert to timestamp', () => { const dateTime = '2019-06-11 15:36:33'; let result; beforeAll(done => { - runAndGetResult(undefined, `Bot.toTimestamp(${dateTime})`).then(v => { + run(`(function() {return Bot.toTimestamp('${dateTime}');})()`).then(v => { result = v; done(); }); }); it('converts date/time string to timestamp', () => { - expect(result).satisfy(ts => ts === '1560238593'); + expect(result).satisfy(ts => ts === 1560238593); }); }); From 60e76f7b8647138adcaeddca6581e24facd5e53b Mon Sep 17 00:00:00 2001 From: Anton Date: Wed, 12 Jun 2019 18:16:56 +0800 Subject: [PATCH 07/13] fix for timezone issue in tests --- .../__tests__/block-tests/tools-test/Time.js | 22 ++++--------------- 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/src/botPage/bot/__tests__/block-tests/tools-test/Time.js b/src/botPage/bot/__tests__/block-tests/tools-test/Time.js index 14dc4edbd1..0c38235b8c 100644 --- a/src/botPage/bot/__tests__/block-tests/tools-test/Time.js +++ b/src/botPage/bot/__tests__/block-tests/tools-test/Time.js @@ -28,30 +28,16 @@ describe('Time in tools', () => { }); }); -describe('Convert to date/time string', () => { - const timestamp = '1560238593'; +describe('Convert timestamp to date/time and back', () => { + const timestamp = Math.ceil(new Date().getTime() / 1000); let result; beforeAll(done => { - run(`(function() {return Bot.toDateTime(${timestamp});})()`).then(v => { + run(`(function() {return Bot.toTimestamp(Bot.toDateTime(${timestamp}));})()`).then(v => { result = v; done(); }); }); it('converts timestamp to date/time string', () => { - expect(result).satisfy(dt => dt === '2019-06-11 15:36:33'); - }); -}); - -describe('Convert to timestamp', () => { - const dateTime = '2019-06-11 15:36:33'; - let result; - beforeAll(done => { - run(`(function() {return Bot.toTimestamp('${dateTime}');})()`).then(v => { - result = v; - done(); - }); - }); - it('converts date/time string to timestamp', () => { - expect(result).satisfy(ts => ts === 1560238593); + expect(result).satisfy(dt => dt === timestamp); }); }); From fac2c55ecd22e626e530bd50a73e9188b9db7ab4 Mon Sep 17 00:00:00 2001 From: Anton Date: Sat, 15 Jun 2019 13:21:00 +0800 Subject: [PATCH 08/13] GMT offset added, input validation refactored --- src/botPage/bot/Interface/ToolsInterface.js | 39 +++++++++++-------- .../blockly/blocks/tools/time/todatetime.js | 2 +- .../blockly/blocks/tools/time/totimestamp.js | 2 +- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/botPage/bot/Interface/ToolsInterface.js b/src/botPage/bot/Interface/ToolsInterface.js index b5a4ddcc1e..43571f25bd 100644 --- a/src/botPage/bot/Interface/ToolsInterface.js +++ b/src/botPage/bot/Interface/ToolsInterface.js @@ -16,28 +16,33 @@ export default Interface => class extends IndicatorsInterface( } return `${input}`; } + const invalidTimestamp = () => `${translate('Invalid timestamp')}: ${timestamp}`; if(typeof timestamp === 'number') { const dateTime = new Date(timestamp * 1000); - - const year = dateTime.getFullYear(); - const month = getTwoDigitValue(dateTime.getMonth() + 1); - const day = getTwoDigitValue(dateTime.getDate()); - const hours = getTwoDigitValue(dateTime.getHours()); - const minutes = getTwoDigitValue(dateTime.getMinutes()); - const seconds = getTwoDigitValue(dateTime.getSeconds()); - - return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; + if(dateTime.getTime()) { + const year = dateTime.getFullYear(); + const month = getTwoDigitValue(dateTime.getMonth() + 1); + const day = getTwoDigitValue(dateTime.getDate()); + const hours = getTwoDigitValue(dateTime.getHours()); + const minutes = getTwoDigitValue(dateTime.getMinutes()); + const seconds = getTwoDigitValue(dateTime.getSeconds()); + const formatGTMoffset = () => { + const GMToffsetRaw = dateTime.getTimezoneOffset(); + const sign = GMToffsetRaw > 0 ? '-' : '+'; + const GMToffset = Math.abs(GMToffsetRaw); + const h = Math.floor(GMToffset / 60); + const m = GMToffset - h * 60; + return `GMT${sign}${getTwoDigitValue(h)}${getTwoDigitValue(m)}`; + } + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds} ${formatGTMoffset()}`; + } + return invalidTimestamp(); } - return `${translate('Invalid timestamp')}: ${timestamp}`; + return invalidTimestamp(); }, toTimestamp: (dateTimeString) => { - const p = /^([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])\s(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]))$/; - const invalidDateTime = () => `${translate('Invalid date/time')}: ${dateTimeString}`; - if (p.test(dateTimeString)) { - const date = new Date(dateTimeString); - return date ? date.getTime() / 1000 : invalidDateTime(); - } - return invalidDateTime(); + const date = new Date(dateTimeString.substr(0,19)).getTime(); + return date ? Math.floor(date / 1000) : `${translate('Invalid date/time')}: ${dateTimeString}`; }, ...this.getCandleInterface(), ...this.getMiscInterface(), diff --git a/src/botPage/view/blockly/blocks/tools/time/todatetime.js b/src/botPage/view/blockly/blocks/tools/time/todatetime.js index de821280ec..df1e981408 100644 --- a/src/botPage/view/blockly/blocks/tools/time/todatetime.js +++ b/src/botPage/view/blockly/blocks/tools/time/todatetime.js @@ -9,7 +9,7 @@ Blockly.Blocks.todatetime = { this.setColour('#dedede'); this.setTooltip( translate( - 'Converts a string representing a date/time string into seconds since Epoch. Input format: yyyy-mm-dd hh:mm:ss' + 'Converts a number of seconds since Epoch into a string representing date and time. Example: 1546347825 will be converted to 2019-01-01 21:03:45.' ) ); }, diff --git a/src/botPage/view/blockly/blocks/tools/time/totimestamp.js b/src/botPage/view/blockly/blocks/tools/time/totimestamp.js index 849e698cf4..8fdc7330c6 100644 --- a/src/botPage/view/blockly/blocks/tools/time/totimestamp.js +++ b/src/botPage/view/blockly/blocks/tools/time/totimestamp.js @@ -9,7 +9,7 @@ Blockly.Blocks.totimestamp = { this.setColour('#dedede'); this.setTooltip( translate( - 'Converts a string representing a date/time string into seconds since Epoch. Input format: yyyy-mm-dd hh:mm:ss' + 'Converts a string representing a date/time string into seconds since Epoch. Example: 2019-01-01 21:03:45 GMT+0800 will be converted to 1546347825. Time and time zone offset are optional.' ) ); }, From d670ca51a656589d7bc764a14bcc3212275b9486 Mon Sep 17 00:00:00 2001 From: Anton Date: Sun, 23 Jun 2019 14:56:16 +0800 Subject: [PATCH 09/13] fixed safari bugs and date/time validation --- src/botPage/bot/Interface/ToolsInterface.js | 22 +++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/botPage/bot/Interface/ToolsInterface.js b/src/botPage/bot/Interface/ToolsInterface.js index 43571f25bd..f051a15c97 100644 --- a/src/botPage/bot/Interface/ToolsInterface.js +++ b/src/botPage/bot/Interface/ToolsInterface.js @@ -17,9 +17,9 @@ export default Interface => class extends IndicatorsInterface( return `${input}`; } const invalidTimestamp = () => `${translate('Invalid timestamp')}: ${timestamp}`; - if(typeof timestamp === 'number') { + if (typeof timestamp === 'number') { const dateTime = new Date(timestamp * 1000); - if(dateTime.getTime()) { + if (dateTime.getTime()) { const year = dateTime.getFullYear(); const month = getTwoDigitValue(dateTime.getMonth() + 1); const day = getTwoDigitValue(dateTime.getDate()); @@ -37,12 +37,22 @@ export default Interface => class extends IndicatorsInterface( return `${year}-${month}-${day} ${hours}:${minutes}:${seconds} ${formatGTMoffset()}`; } return invalidTimestamp(); - } - return invalidTimestamp(); + } + return invalidTimestamp(); }, toTimestamp: (dateTimeString) => { - const date = new Date(dateTimeString.substr(0,19)).getTime(); - return date ? Math.floor(date / 1000) : `${translate('Invalid date/time')}: ${dateTimeString}`; + const invalidDatetime = () => `${translate('Invalid date/time')}: ${dateTimeString}`; + if (typeof dateTimeString === 'string') { + const tmp = dateTimeString.replace(/\s+/g, 'T').substr(0, 19); + const dateTime = tmp[tmp.length - 1] === 'T' ? tmp.substr(0, tmp.length - 1) : tmp; + const p = /^([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])(T(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9])(:([0-5][0-9]))?)?)/; + if (p.test(dateTime)) { + const date = new Date(dateTime); + return date ? date.getTime() / 1000 : invalidDatetime(); + } + return invalidDatetime(); + } + return invalidDatetime(); }, ...this.getCandleInterface(), ...this.getMiscInterface(), From f31771d81c0abc3c0fe8d96dd0c3e153d3d3bfaa Mon Sep 17 00:00:00 2001 From: Anton Date: Mon, 24 Jun 2019 18:17:26 +0800 Subject: [PATCH 10/13] fixed date object validation --- src/botPage/bot/Interface/ToolsInterface.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/botPage/bot/Interface/ToolsInterface.js b/src/botPage/bot/Interface/ToolsInterface.js index f051a15c97..efd34fe159 100644 --- a/src/botPage/bot/Interface/ToolsInterface.js +++ b/src/botPage/bot/Interface/ToolsInterface.js @@ -48,8 +48,11 @@ export default Interface => class extends IndicatorsInterface( const p = /^([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])(T(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9])(:([0-5][0-9]))?)?)/; if (p.test(dateTime)) { const date = new Date(dateTime); - return date ? date.getTime() / 1000 : invalidDatetime(); + // return `ok: ${ date}`; + // eslint-disable-next-line no-restricted-globals + return date instanceof Date && !isNaN(date) ? date.getTime() / 1000 : invalidDatetime(); } + // return `not ok: ${ dateTime}`; return invalidDatetime(); } return invalidDatetime(); From 84ff2c5b2d64b1ce1a25bc584c4913ae00a95be1 Mon Sep 17 00:00:00 2001 From: Anton Date: Mon, 24 Jun 2019 18:21:35 +0800 Subject: [PATCH 11/13] removed comments --- src/botPage/bot/Interface/ToolsInterface.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/botPage/bot/Interface/ToolsInterface.js b/src/botPage/bot/Interface/ToolsInterface.js index efd34fe159..f9808c6022 100644 --- a/src/botPage/bot/Interface/ToolsInterface.js +++ b/src/botPage/bot/Interface/ToolsInterface.js @@ -48,11 +48,9 @@ export default Interface => class extends IndicatorsInterface( const p = /^([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])(T(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9])(:([0-5][0-9]))?)?)/; if (p.test(dateTime)) { const date = new Date(dateTime); - // return `ok: ${ date}`; // eslint-disable-next-line no-restricted-globals return date instanceof Date && !isNaN(date) ? date.getTime() / 1000 : invalidDatetime(); } - // return `not ok: ${ dateTime}`; return invalidDatetime(); } return invalidDatetime(); From e179a45ebbea8e182a39caf35dfca884c105d8c6 Mon Sep 17 00:00:00 2001 From: Anton Date: Thu, 27 Jun 2019 09:43:38 +0800 Subject: [PATCH 12/13] added more flexible validation --- src/botPage/bot/Interface/ToolsInterface.js | 30 ++++++++++++++++----- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/botPage/bot/Interface/ToolsInterface.js b/src/botPage/bot/Interface/ToolsInterface.js index f9808c6022..1dfc0a3c2b 100644 --- a/src/botPage/bot/Interface/ToolsInterface.js +++ b/src/botPage/bot/Interface/ToolsInterface.js @@ -43,13 +43,31 @@ export default Interface => class extends IndicatorsInterface( toTimestamp: (dateTimeString) => { const invalidDatetime = () => `${translate('Invalid date/time')}: ${dateTimeString}`; if (typeof dateTimeString === 'string') { - const tmp = dateTimeString.replace(/\s+/g, 'T').substr(0, 19); - const dateTime = tmp[tmp.length - 1] === 'T' ? tmp.substr(0, tmp.length - 1) : tmp; - const p = /^([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])(T(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9])(:([0-5][0-9]))?)?)/; - if (p.test(dateTime)) { - const date = new Date(dateTime); + const dateTime = dateTimeString + .replace(/[^0-9.:-\s]/g, '') + .replace(/\s+/g,' ') + .replace(/\s$/,'') + .split(' '); + + const d = /^[12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/; + const t = /^(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9])(:([0-5][0-9])?)?$/; + + let validatedDateTime; + + if(dateTime.length >= 2) { + validatedDateTime = d.test(dateTime[0]) && t.test(dateTime[1]) ? `${dateTime[0]}T${dateTime[1]}` : null; + } else if(dateTime.length === 1) { + validatedDateTime = d.test(dateTime[0]) ? dateTime[0] : null; + } else { + validatedDateTime = null; + } + + if(validatedDateTime) { + const dateObj = new Date(validatedDateTime); // eslint-disable-next-line no-restricted-globals - return date instanceof Date && !isNaN(date) ? date.getTime() / 1000 : invalidDatetime(); + if(dateObj instanceof Date && !isNaN(dateObj)) { + return dateObj.getTime() / 1000; + } } return invalidDatetime(); } From 2992b40a3715c0f31f9f356517e6dfc70b01cbe0 Mon Sep 17 00:00:00 2001 From: Anton Date: Thu, 27 Jun 2019 16:07:15 +0800 Subject: [PATCH 13/13] trim spaces in the beginning/end of date-time string --- src/botPage/bot/Interface/ToolsInterface.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/botPage/bot/Interface/ToolsInterface.js b/src/botPage/bot/Interface/ToolsInterface.js index 1dfc0a3c2b..2067f0889b 100644 --- a/src/botPage/bot/Interface/ToolsInterface.js +++ b/src/botPage/bot/Interface/ToolsInterface.js @@ -46,7 +46,7 @@ export default Interface => class extends IndicatorsInterface( const dateTime = dateTimeString .replace(/[^0-9.:-\s]/g, '') .replace(/\s+/g,' ') - .replace(/\s$/,'') + .trim() .split(' '); const d = /^[12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/;