From 91e0697d9712ea757c477860414d257d081eea8a Mon Sep 17 00:00:00 2001 From: Ricardo Espinoza Date: Thu, 23 Jan 2020 19:07:18 -0500 Subject: [PATCH 1/2] :sparkles: date format node --- packages/nodes-base/nodes/DateTime.node.ts | 227 +++++++++++++++++++++ packages/nodes-base/package.json | 2 + 2 files changed, 229 insertions(+) create mode 100644 packages/nodes-base/nodes/DateTime.node.ts diff --git a/packages/nodes-base/nodes/DateTime.node.ts b/packages/nodes-base/nodes/DateTime.node.ts new file mode 100644 index 0000000000..f860162383 --- /dev/null +++ b/packages/nodes-base/nodes/DateTime.node.ts @@ -0,0 +1,227 @@ +import { IExecuteFunctions } from 'n8n-core'; +import { + INodeExecutionData, + INodeType, + INodeTypeDescription, + INodePropertyOptions, + ILoadOptionsFunctions, + IDataObject, +} from 'n8n-workflow'; + +import * as moment from 'moment-timezone'; + +export class DateTime implements INodeType { + description: INodeTypeDescription = { + displayName: 'Date & Time', + name: 'dateTime', + icon: 'fa:calendar', + group: ['transform'], + version: 1, + description: 'Allows you to manipulate date and time values', + defaults: { + name: 'Date & Time', + color: '#408000', + }, + inputs: ['main'], + outputs: ['main'], + properties: [ + { + displayName: 'Action', + name: 'action', + type: 'options', + options: [ + { + name: 'Format a Date', + description: 'Apply to a date a diferent format', + value: 'format' + }, + ], + default: 'format', + }, + { + displayName: 'Field Name', + name: 'fieldName', + displayOptions: { + show: { + action:[ + 'format' + ], + }, + }, + type: 'string', + default: '', + required: true, + }, + { + displayName: 'To Format', + name: 'toFormat', + type: 'options', + displayOptions: { + show: { + action:[ + 'format' + ], + }, + }, + options: [ + { + name: 'MM/DD/YYYY', + value: 'MM/DD/YYYY', + description: 'Example: 09/04/1986', + }, + { + name: 'YYYY/MM/DD', + value: 'YYYY/MM/DD', + description: 'Example: 1986/04/09', + }, + { + name: 'MMMM DD YYYY', + value: 'MMMM DD YYYY', + description: 'Example: April 09 1986', + }, + { + name: 'MM-DD-YYYY', + value: 'MM-DD-YYYY', + description: 'Example: 09-04-1986', + }, + { + name: 'YYYY-MM-DD', + value: 'YYYY-MM-DD', + description: 'Example: 1986-04-09', + }, + { + name: 'Unix Timestamp', + value: 'X', + description: 'Example: 513388800.879', + }, + { + name: 'Unix Ms Timestamp', + value: 'x', + description: 'Example: 513388800', + }, + ], + default: 'MM/DD/YYYY', + }, + { + displayName: 'To Timezone', + name: 'toTimezone', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getTimezones', + }, + displayOptions: { + show: { + action:[ + 'format' + ], + }, + }, + default: 'UTC', + }, + { + displayName: 'Options', + name: 'options', + displayOptions: { + show: { + action:[ + 'format' + ], + }, + }, + type: 'collection', + placeholder: 'Add Option', + default: {}, + options: [ + { + displayName: 'From Timezone', + name: 'fromTimezone', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getTimezones', + }, + default: 'UTC', + }, + { + displayName: 'From Format', + name: 'fromFormat', + type: 'string', + default: '', + description: 'In case the input format is not recognized you can provide the format ', + }, + { + displayName: 'Keep Old Date', + name: 'keepOldDate', + type: 'boolean', + default: false, + }, + ], + }, + ], + }; + + methods = { + loadOptions: { + // Get all the timezones to display them to user so that he can + // select them easily + async getTimezones(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + for (const timezone of moment.tz.names()) { + const timezoneName = timezone; + const timezoneId = timezone; + returnData.push({ + name: timezoneName, + value: timezoneId, + }); + } + return returnData; + }, + } + }; + + async execute(this: IExecuteFunctions): Promise { + const items = this.getInputData(); + const returnData: IDataObject[] = []; + const length = items.length as unknown as number; + let responseData; + for (let i = 0; i < length; i++) { + const action = this.getNodeParameter('action', 0) as string; + if (action === 'format') { + const fieldName = this.getNodeParameter('fieldName', i) as string; + const toTimezone = this.getNodeParameter('toTimezone', i) as string; + const toFormat = this.getNodeParameter('toFormat', i) as string; + const options = this.getNodeParameter('options', i) as IDataObject; + let newDate; + let clone = { ...items[i].json }; + if (clone[fieldName] === undefined) { + throw new Error(`The field ${fieldName} does not exist on the input data`); + } + if (!moment(clone[fieldName] as string | number).isValid()) { + throw new Error('The date input format is not recognized, please set the "From Format" field'); + } + if (Number.isInteger(clone[fieldName] as number)) { + newDate = moment.unix(clone[fieldName] as number).tz(toTimezone).format(toFormat); + } else { + newDate = moment(clone[fieldName] as string).tz(toTimezone).format(toFormat); + if (options.fromTimezone) { + newDate = moment.tz(clone[fieldName] as string, options.fromTimezone as string).tz(toTimezone).format(toFormat); + } + if (options.fromFormat) { + newDate = moment(clone[fieldName] as string, options.fromFormat as string).tz(toTimezone).format(toFormat); + } + } + if (!options.keepOldDate) { + clone[fieldName] = newDate; + } else { + clone['newDate'] = newDate; + } + responseData = clone; + } + if (Array.isArray(responseData)) { + returnData.push.apply(returnData, responseData as IDataObject[]); + } else { + returnData.push(responseData as IDataObject); + } + } + return [this.helpers.returnJsonArray(returnData)]; + } +} diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 9cd7f397c5..1cff3fde15 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -106,6 +106,7 @@ "dist/nodes/Cron.node.js", "dist/nodes/Discord/Discord.node.js", "dist/nodes/Dropbox/Dropbox.node.js", + "dist/nodes/DateTime.node.js", "dist/nodes/EditImage.node.js", "dist/nodes/EmailReadImap.node.js", "dist/nodes/EmailSend.node.js", @@ -201,6 +202,7 @@ "@types/imap-simple": "^4.2.0", "@types/jest": "^24.0.18", "@types/lodash.set": "^4.3.6", + "@types/moment-timezone": "^0.5.12", "@types/mongodb": "^3.3.6", "@types/node": "^10.10.1", "@types/nodemailer": "^4.6.5", From bbd3a3bc8b0c1ba3fc596e65ed7df35e4bc51349 Mon Sep 17 00:00:00 2001 From: Ricardo Espinoza Date: Sat, 25 Jan 2020 17:14:54 -0500 Subject: [PATCH 2/2] :zap: added custom format --- packages/nodes-base/nodes/DateTime.node.ts | 36 ++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/packages/nodes-base/nodes/DateTime.node.ts b/packages/nodes-base/nodes/DateTime.node.ts index f860162383..50f9e07ede 100644 --- a/packages/nodes-base/nodes/DateTime.node.ts +++ b/packages/nodes-base/nodes/DateTime.node.ts @@ -44,7 +44,7 @@ export class DateTime implements INodeType { displayOptions: { show: { action:[ - 'format' + 'format', ], }, }, @@ -52,6 +52,35 @@ export class DateTime implements INodeType { default: '', required: true, }, + { + displayName: 'Custom Format', + name: 'custom', + displayOptions: { + show: { + action:[ + 'format', + ], + }, + }, + type: 'boolean', + default: false, + }, + { + displayName: 'To Format', + name: 'toFormat', + displayOptions: { + show: { + action:[ + 'format', + ], + custom: [ + true, + ], + }, + }, + type: 'string', + default: '', + }, { displayName: 'To Format', name: 'toFormat', @@ -59,7 +88,10 @@ export class DateTime implements INodeType { displayOptions: { show: { action:[ - 'format' + 'format', + ], + custom:[ + false, ], }, },