Intial Commit

This commit is contained in:
valki
2020-10-17 18:42:50 +02:00
commit 664c6d8ca3
5892 changed files with 759183 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
{
"env": {
"node": true,
"browser": false,
"es6": true
},
"extends": "eslint:recommended",
"rules": {
"indent": [
"warn",
[2, 2]
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"warn",
"single"
],
"semi": [
"warn",
"never"
]
}
}

View File

@@ -0,0 +1,46 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at the GitHub Issues page for this repo. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed 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.

View File

@@ -0,0 +1,131 @@
# node-red-contrib-moment
[Node-Red](http://nodered.org) Node that produces a nicely formatted Date/Time string using the Moment.JS library & is fully time zone/DST/locale aware.
[![NPM Version](https://img.shields.io/npm/v/node-red-contrib-moment.svg)](https://www.npmjs.com/package/node-red-contrib-moment)
[![NPM Total Downloads](https://img.shields.io/npm/dt/node-red-contrib-moment.svg)](https://www.npmjs.com/package/node-red-contrib-moment)
[![NPM Downloads per month](https://img.shields.io/npm/dm/node-red-contrib-moment.svg)](https://www.npmjs.com/package/node-red-contrib-moment)
[![GitHub last commit](https://img.shields.io/github/last-commit/totallyinformation/node-red-contrib-moment.svg)](https://github.com/TotallyInformation/node-red-contrib-moment)
[![GitHub stars](https://img.shields.io/github/stars/TotallyInformation/node-red-contrib-moment.svg)](https://github.com/TotallyInformation/node-red-contrib-moment/watchers)
[![GitHub watchers](https://img.shields.io/github/watchers/TotallyInformation/node-red-contrib-moment.svg)](https://github.com/TotallyInformation/node-red-contrib-moment/stargazers)
[![GitHub license](https://img.shields.io/github/license/TotallyInformation/node-red-contrib-moment.svg)](https://github.com/TotallyInformation/node-red-contrib-moment/blob/master/LICENSE)
[![Min Node Version](https://img.shields.io/node/v/node-red-contrib-moment.svg)](https://www.npmjs.com/package/node-red-contrib-moment)
[![Package Quality](http://npm.packagequality.com/shield/node-red-contrib-moment.png)](http://packagequality.com/#?package=node-red-contrib-moment)
[![Dependencies](https://img.shields.io/david/TotallyInformation/node-red-contrib-moment.svg)](https://github.com/TotallyInformation/node-red-contrib-moment)
[![Open Issues](https://img.shields.io/github/issues-raw/TotallyInformation/node-red-contrib-moment.svg)](https://github.com/TotallyInformation/node-red-contrib-moment/issues)
[![Closed Issues](https://img.shields.io/github/issues-closed-raw/TotallyInformation/node-red-contrib-moment.svg)](https://github.com/TotallyInformation/node-red-contrib-moment/issues?q=is%3Aissue+is%3Aclosed)
Based on thoughts from a [conversation in the Node-Red Google Group](https://groups.google.com/d/msg/node-red/SXEGvfFLfQA/fhJCGBWvYEAJ). Updated with timezone/locale capabilities after Jaques44's initial work. Updated with +/- adjustments after [another conversion in the Google Group](https://groups.google.com/forum/#!topic/node-red/u3qoISFoKus).
**IMPORTANT NOTE FOR v3+**: Because this node uses the `moment` library and because of an upstream security issue requiring updates to underlying libraries, this version of the node is **dependent on Node.JS v6 or above**. It will not work with Node v4. If you are forced to use Node v4, please stay with v2x of this node. Otherwise, please consider upgrading to the current LTS version of Node.JS. Thanks.
# Install
You can always install the latest version via Node-RED's built-in "Manage Palette" menu. Alternatively ...
Run the following command in the "userDir" folder. (typically `~/.node-red`)
npm install node-red-contrib-moment
If you want to install the Node v4 compatible version:
npm install node-red-contrib-moment@2
To get the latest development version, install with:
npm install https://github.com/TotallyInformation/node-red-contrib-moment/tarball/master
# Updates
- 3.0.2 - Update dependencies to latest versions.
- 3.0.1 - **Bug Fix** Remove errant log statement.
- 3.0.0 - No feature changes, just upgrades of the dependent libraries. Note breaking change, minimum Node.JS version is now v6 or above.
- Documentation updated to clarify processing of different inputs.
- Fix: If input property contains `null`, output is now a warning + empty string in line with other invalid inputs. It was an incorrect timestamp.
- Examples added to Node-RED library to make testing easier.
- 2.0.7 - Fallback to new Date(inp) when the date string is non-standard, like this output from the file stat() function: `2017-12-12 16:03:51.832427000 -0400` as well as the Twitter API default time string: `Mon Jan 08 21:24:37 +0000 2018` (contributed by [Steve Rickus](https://github.com/shrickus)). Update dependencies.
- 2.0.6 - Upstream change in MomentJS introduced bug when feeding with a timestamp (number), fixed
- 2.0.5 - Autocorrect common tz errors (e.g. UTC+4 should be ETC/GMT+4) & autofill default
- 2.0.4 - Show warning for invalid timezone specifications
- 2.0.3 - Humanize helper node added, exposes moments humanize of timespan functionality (contributed by [Laro88](https://github.com/Laro88)),
Documentation updated to highlight issue with moment.js object handing (month is 0-11 not 1-12)
- 2.0.2 - Minor fixes - change version to get latest moment.js. 2017-03-19
- 2.0.1 - Fix get/set of msg properties. 2016-07-08
- 2.0.0 - Significant rewrite, updated moment.js, got rid of all eval's, added adjustment calcs, added time zone and locale awareness. 2016-06-26
- 1.0.9 - Merged in some fixes on Jacques44's contributions & acknowledged him in the package. Also fixed the npm readme. 2016-06-12
- 1.0.5 - Merged a pull request containing a Locale option for localisation. 2016-03-30
- 1.0.3 - First stable release. 2015-01-31
# Usage
## Moment
The node generally expects an input from the incoming msg. By default, this is msg.payload. If it is a recognisable date/time, it will apply a format and output the resulting string or object accordingly.
Input and output time zones are settable as is the output locale. All of which default to the host systems tz/locale.
This allows the node to be used to translate from one time zone to another. It also will take into account daylight savings time (DST).
You can also apply an adjustment to the date/time by adding or subtracting an amount.
If the **Input from**:
* is "timestamp", the current date/time is used as input. Output will be processed as normal.
* is "msg", "global" or "flow" and the given property is empty or does not exist, the current date/time is used as input. Output will be processed as normal.
* is a property containing a numeric value, it will be assumed to be a UNIX time value (ms since 1970-01-01 I think). Output will be processed as normal.
* is a property containing a string that is not a recognisable date/time (including `null`). Output is an empty string plus a debug warning.
If the **output** property is not `msg.payload` the input `msg.payload` is retained in the output.
See the node's built-in help for more details.
## Humanize
Specify the input variable to execute humanize on, `msg.payload.humanized` will contain a humanized version of the specified span in seconds. (Contributed by [Laro88](https://github.com/Laro88))
# Depends on
- [Moment.js](http://momentjs.com/docs) - Clever date/time handler for Node.js and browsers
- [Moment-Timezone](http://momentjs.com/timezone/docs) - Adds timezone and locale awareness to Moment.js
- [Moment-ParseFormat](https://github.com/gr2m/moment-parseformat) - Tries to interpret input strings as date/times and creates a format string that moment.js can use.
- [os-locale](https://github.com/sindresorhus/os-locale) - interpets the host OS's locale. Works with Windows as well as Linux.
- [Node-Red](http://nodered.org/docs/) - of course!
# To Do
Summary of things I'd like to do with the moment node (not necessarily immediately):
* [ ] Add some additional nodes for doing date/time calculations - partly complete, can do simple add/subtract from main node
* [ ] Add additional node for doing duration calculations
* [ ] Add a combo box to the Format field with common formats pre-populated
* [x] Improve the error messages when Moment.JS fails to interpret the input (say why)
* [x] Allow more input date/time formats - turns out Moment.JS doesn't really help here. At present, I see too many input failures from US/UK date formats, etc.
It would be great if I could parse "human" inputs like "tomorrow" and "2 minutes from now". We can output them now but not input them. As of v1.0.5, a localisation parameter is supported.
~~Partly complete: Added the [parseFormat plugin](https://github.com/gr2m/moment.parseFormat). That failed, see code for details.~~ Now complete.
# License
This code is Open Source under an Apache 2 License. Please see the [apache2-license.txt file](https://github.com/TotallyInformation/node-red-contrib-moment/apache2-license.txt) for details.
You may not use this code except in compliance with the License. You may obtain an original 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. Please see the
License for the specific language governing permissions and limitations under the License.
# Author
[Julian Knight](https://uk.linkedin.com/in/julianknight2/) ([Totally Information](https://www.totallyinformation.com)), https://github.com/totallyinformation
# Contributors
* [Vicary Archangel](https://github.com/vicary)
* [Steve Rickus](https://github.com/shrickus)
* [Jes Ramsing](https://github.com/Laro88)
* [Jacques W](https://github.com/Jacques44)
Many thanks for the contributions.
# Feedback and Support
Please report any issues or suggestions via the [Github Issues list for this repository](https://github.com/TotallyInformation/node-red-contrib-moment/issues).
For more information, feedback, or community support see the Node-Red Google groups forum at https://groups.google.com/forum/#!forum/node-red

View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed 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.

View File

@@ -0,0 +1,161 @@
[
{
"id": "320464b5.d0134c",
"type": "moment",
"z": "533475c4.a28eac",
"name": "input: msg.payload",
"topic": "",
"input": "",
"inputType": "msg",
"inTz": "America/New_York",
"adjAmount": 0,
"adjType": "days",
"adjDir": "add",
"format": "YYYY-MM-DD HH:mm",
"locale": "en_US",
"output": "now",
"outputType": "msg",
"outTz": "America/New_York",
"x": 470,
"y": 400,
"wires": [
[
"72ed58b3.7f9178"
]
]
},
{
"id": "aceef80.40a4908",
"type": "inject",
"z": "533475c4.a28eac",
"name": "",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": "",
"x": 240,
"y": 340,
"wires": [
[
"320464b5.d0134c"
]
]
},
{
"id": "72ed58b3.7f9178",
"type": "debug",
"z": "533475c4.a28eac",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"x": 650,
"y": 400,
"wires": []
},
{
"id": "bbe21120.87815",
"type": "inject",
"z": "533475c4.a28eac",
"name": "blank string",
"topic": "",
"payload": "",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": "",
"x": 230,
"y": 380,
"wires": [
[
"320464b5.d0134c"
]
]
},
{
"id": "e49c12a.d2215f",
"type": "inject",
"z": "533475c4.a28eac",
"name": "'test'",
"topic": "",
"payload": "test",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": "",
"x": 250,
"y": 420,
"wires": [
[
"320464b5.d0134c"
]
]
},
{
"id": "58881f8c.6cc45",
"type": "inject",
"z": "533475c4.a28eac",
"name": "null",
"topic": "",
"payload": "null",
"payloadType": "json",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": "",
"x": 250,
"y": 460,
"wires": [
[
"320464b5.d0134c"
]
]
},
{
"id": "43a381eb.dae01",
"type": "comment",
"z": "533475c4.a28eac",
"name": "Pass different data types to a valid input property",
"info": "",
"x": 560,
"y": 360,
"wires": []
},
{
"id": "e2fe39e8.d9aba8",
"type": "inject",
"z": "533475c4.a28eac",
"name": "Invalid Date String",
"topic": "Invalid Date String",
"payload": "36th September 3046",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": "",
"x": 210,
"y": 500,
"wires": [
[
"320464b5.d0134c"
]
]
},
{
"id": "4b9bf042.f40d3",
"type": "comment",
"z": "533475c4.a28eac",
"name": "Expected Results",
"info": "Requests input from `msg.payload` but puts\noutput to `msg.now`.\n\n\n## Timestamp input\n\n```\n{\n \"_msgid\":\"2792614c.a404ee\",\"topic\":\"\",\n \"payload\":1537718900126,\n \"now\":\"2018-09-23 12:08\"\n}\n```\n\n## All other inputs\n\n1. An output warning message\n `The input property was NOT a recognisable date. Output will be a blank string`\n\n2. `msg.payload` set to input msg.payload\n3. `msg.now` set to empty string.\n",
"x": 460,
"y": 460,
"wires": []
}
]

View File

@@ -0,0 +1,141 @@
[
{
"id": "6e87ca1f.077804",
"type": "moment",
"z": "533475c4.a28eac",
"name": "input: msg.foo",
"topic": "",
"input": "foo",
"inputType": "msg",
"inTz": "America/New_York",
"adjAmount": 0,
"adjType": "days",
"adjDir": "add",
"format": "YYYY-MM-DD HH:mm",
"locale": "en_US",
"output": "now",
"outputType": "msg",
"outTz": "America/New_York",
"x": 460,
"y": 660,
"wires": [
[
"61f6f582.f8708c"
]
]
},
{
"id": "12d13caf.fd1683",
"type": "inject",
"z": "533475c4.a28eac",
"name": "",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": "",
"x": 240,
"y": 600,
"wires": [
[
"6e87ca1f.077804"
]
]
},
{
"id": "61f6f582.f8708c",
"type": "debug",
"z": "533475c4.a28eac",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"x": 650,
"y": 660,
"wires": []
},
{
"id": "63c7416c.aa3ce",
"type": "inject",
"z": "533475c4.a28eac",
"name": "blank string",
"topic": "",
"payload": "",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": "",
"x": 230,
"y": 640,
"wires": [
[
"6e87ca1f.077804"
]
]
},
{
"id": "c371a083.37e4f",
"type": "inject",
"z": "533475c4.a28eac",
"name": "'test'",
"topic": "",
"payload": "test",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": "",
"x": 250,
"y": 680,
"wires": [
[
"6e87ca1f.077804"
]
]
},
{
"id": "c0c9733a.5abb3",
"type": "inject",
"z": "533475c4.a28eac",
"name": "null",
"topic": "",
"payload": "null",
"payloadType": "json",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": "",
"x": 250,
"y": 720,
"wires": [
[
"6e87ca1f.077804"
]
]
},
{
"id": "bed64b79.64ac88",
"type": "comment",
"z": "533475c4.a28eac",
"name": "Reference a non-existent input property",
"info": "",
"x": 530,
"y": 620,
"wires": []
},
{
"id": "805b442c.c26d48",
"type": "comment",
"z": "533475c4.a28eac",
"name": "Expected Results",
"info": "As the input msg property does not exist,\n**all** outputs will be the same:\n\n```\n{\n \"_msgid\":\"fbb0e16f.af613\",\"topic\":\"\",\n \"payload\":1537719147115,\n \"now\":\"2018-09-23 12:12\"\n}\n```\n\n1. `msg.payload` set to input msg.payload\n3. `msg.now` set to current date/time string.\n",
"x": 460,
"y": 720,
"wires": []
}
]

View File

@@ -0,0 +1,91 @@
[
{
"id": "df76bbb4.8529e8",
"type": "inject",
"z": "533475c4.a28eac",
"name": "UNIX timestamp",
"topic": "UNIX timestamp",
"payload": "1512545487",
"payloadType": "num",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 180,
"y": 380,
"wires": [
[
"c5a8c.dddf4574"
]
]
},
{
"id": "c5a8c.dddf4574",
"type": "moment",
"z": "533475c4.a28eac",
"name": "",
"topic": "",
"input": "",
"inputType": "msg",
"inTz": "",
"adjAmount": 0,
"adjType": "days",
"adjDir": "add",
"format": "",
"locale": "",
"output": "",
"outputType": "msg",
"outTz": "",
"x": 420,
"y": 380,
"wires": [
[
"e5a3e641.545528"
]
]
},
{
"id": "e5a3e641.545528",
"type": "debug",
"z": "533475c4.a28eac",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"x": 610,
"y": 380,
"wires": []
},
{
"id": "48c26998.0d90a8",
"type": "inject",
"z": "533475c4.a28eac",
"name": "JS Timestamp",
"topic": "JS Timestamp",
"payload": "1512545487000",
"payloadType": "num",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 170,
"y": 420,
"wires": [
[
"c5a8c.dddf4574"
]
]
},
{
"id": "d12e7985.07ef88",
"type": "comment",
"z": "533475c4.a28eac",
"name": "Expected Output",
"info": "UNIX Timestamps are the number of **SECONDS** \nsince 1970-01-01 00:00:00.\n\nJavaScript Timestamps are the number of **MILLIseconds**\nsince 1970-01-01 00:00:00.\n\nMoment.JS only recognises JavaScript timestamps\nso if you want to process a UNIX timestamp, \nplease multiply by 1000 as in the second\ninput.",
"x": 400,
"y": 420,
"wires": []
}
]

View File

@@ -0,0 +1,218 @@
[
{
"id": "e75759f3.14aed8",
"type": "moment",
"z": "533475c4.a28eac",
"name": "",
"topic": "OBJECT OUTPUT",
"input": "",
"inputType": "msg",
"inTz": "Europe/London",
"adjAmount": 0,
"adjType": "days",
"adjDir": "add",
"format": "object",
"locale": "en_GB",
"output": "",
"outputType": "msg",
"outTz": "Europe/London",
"x": 470,
"y": 360,
"wires": [
[
"3514268f.2b575a"
]
]
},
{
"id": "749a67b1.8511e8",
"type": "inject",
"z": "533475c4.a28eac",
"name": "",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "",
"crontab": "",
"once": false,
"x": 120,
"y": 360,
"wires": [
[
"e75759f3.14aed8",
"d057c5dc.43ec08",
"6a30d321.63b5ec",
"3562ef2d.e961c",
"2046d084.fb1e4"
]
]
},
{
"id": "3514268f.2b575a",
"type": "debug",
"z": "533475c4.a28eac",
"name": "",
"active": true,
"console": "false",
"complete": "payload",
"x": 870,
"y": 440,
"wires": []
},
{
"id": "d057c5dc.43ec08",
"type": "moment",
"z": "533475c4.a28eac",
"name": "",
"topic": "JSDATE (date) OUTPUT",
"input": "",
"inputType": "msg",
"inTz": "Europe/London",
"adjAmount": 0,
"adjType": "days",
"adjDir": "add",
"format": "jsdate",
"locale": "en_GB",
"output": "",
"outputType": "msg",
"outTz": "Europe/London",
"x": 490,
"y": 400,
"wires": [
[
"3514268f.2b575a"
]
]
},
{
"id": "6a30d321.63b5ec",
"type": "moment",
"z": "533475c4.a28eac",
"name": "",
"topic": "CALENDAR (AROUNDNOW) OUTPUT",
"input": "",
"inputType": "msg",
"inTz": "Europe/London",
"adjAmount": 0,
"adjType": "days",
"adjDir": "add",
"format": "calendar",
"locale": "en_GB",
"output": "",
"outputType": "msg",
"outTz": "Europe/London",
"x": 540,
"y": 440,
"wires": [
[
"3514268f.2b575a"
]
]
},
{
"id": "3562ef2d.e961c",
"type": "moment",
"z": "533475c4.a28eac",
"name": "",
"topic": "FROMNOW (TIMEAGO) OUTPUT",
"input": "",
"inputType": "msg",
"inTz": "Europe/London",
"adjAmount": 0,
"adjType": "days",
"adjDir": "add",
"format": "fromnow",
"locale": "en_GB",
"output": "",
"outputType": "msg",
"outTz": "Europe/London",
"x": 520,
"y": 480,
"wires": [
[
"3514268f.2b575a"
]
]
},
{
"id": "2046d084.fb1e4",
"type": "moment",
"z": "533475c4.a28eac",
"name": "",
"topic": "ISO8601 (ISO) OUTPUT",
"input": "",
"inputType": "msg",
"inTz": "Europe/London",
"adjAmount": 0,
"adjType": "days",
"adjDir": "add",
"format": "iso8601",
"locale": "en_GB",
"output": "",
"outputType": "msg",
"outTz": "Europe/London",
"x": 490,
"y": 520,
"wires": [
[
"3514268f.2b575a"
]
]
},
{
"id": "487012c7.d8d1bc",
"type": "inject",
"z": "533475c4.a28eac",
"name": "string yr 1st",
"topic": "",
"payload": "2017/6/14 20:10:10.276",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"x": 130,
"y": 400,
"wires": [
[
"e75759f3.14aed8",
"d057c5dc.43ec08",
"6a30d321.63b5ec",
"3562ef2d.e961c",
"2046d084.fb1e4"
]
]
},
{
"id": "366462c6.c51dbe",
"type": "inject",
"z": "533475c4.a28eac",
"name": "string complex",
"topic": "",
"payload": "Thu Jun 15 2017 18:02:13 GMT+0100 (GMT Summer Time)",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"x": 140,
"y": 440,
"wires": [
[
"e75759f3.14aed8",
"d057c5dc.43ec08",
"6a30d321.63b5ec",
"3562ef2d.e961c",
"2046d084.fb1e4"
]
]
},
{
"id": "d384ff51.8b4d",
"type": "comment",
"z": "533475c4.a28eac",
"name": "Expected Output",
"info": "| Input | Moment | Output |\n|------------------|-----------------------------|---------------------------------------------------------------------------------------------|\n| timestamp | OBJECT OUTPUT | {\"years\":2018,\"months\":8,\"date\":23,\"hours\":17,\"minutes\":0,\"seconds\":54,\"milliseconds\":298} |\n| | JSDATE (date) OUTPUT | Sun Sep 23 2018 17:00:54 GMT+0100 (GMT Summer Time) |\n| | CALENDAR (AROUNDNOW) OUTPUT | Today at 17:00 |\n| | FROMNOW (TIMEAGO) OUTPUT | a few seconds ago |\n| | ISO8601 (ISO) OUTPUT | 2018-09-23T16:00:54.298Z |\n| String Yr 1st | OBJECT OUTPUT | {\"years\":2017,\"months\":5,\"date\":14,\"hours\":20,\"minutes\":10,\"seconds\":10,\"milliseconds\":276} |\n| | JSDATE (date) OUTPUT | Wed Jun 14 2017 20:10:10 GMT+0100 (GMT Summer Time) |\n| | CALENDAR (AROUNDNOW) OUTPUT | 2017-06-14 |\n| | FROMNOW (TIMEAGO) OUTPUT | a year ago |\n| | ISO8601 (ISO) OUTPUT | 2017-06-14T19:10:10.276Z |\n| String (Complex) | OBJECT OUTPUT | {\"years\":2017,\"months\":5,\"date\":15,\"hours\":18,\"minutes\":2,\"seconds\":13,\"milliseconds\":0} |\n| | JSDATE (date) OUTPUT | Thu Jun 15 2017 18:02:13 GMT+0100 (GMT Summer Time) |\n| | CALENDAR (AROUNDNOW) OUTPUT | 2017-06-15 |\n| | FROMNOW (TIMEAGO) OUTPUT | a year ago |\n| | ISO8601 (ISO) OUTPUT | 2017-06-15T17:02:13.000Z |\n\nNeedess to say that your timestamp values will be different.",
"x": 780,
"y": 380,
"wires": []
}
]

View File

@@ -0,0 +1,164 @@
[
{
"id": "9fe47dca.ad366",
"type": "moment",
"z": "533475c4.a28eac",
"name": "UTC-4",
"topic": "UTC-4",
"input": "payload",
"inputType": "msg",
"inTz": "ETC/GMT-4",
"adjAmount": 0,
"adjType": "days",
"adjDir": "add",
"format": "ddd Do MMM YYYY HH:mm",
"locale": "en_GB",
"output": "",
"outputType": "msg",
"outTz": "ETC/GMT-4",
"x": 450,
"y": 640,
"wires": [
[
"3b9b0dc5.bae662"
]
]
},
{
"id": "3c0267e8.e1c0b8",
"type": "inject",
"z": "533475c4.a28eac",
"name": "2017-05-28T21:00:00-04:00",
"topic": "",
"payload": "2017-05-28T21:00:00-04:00",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"x": 200,
"y": 700,
"wires": [
[
"9fe47dca.ad366",
"71ef9d10.3d4904",
"72638b85.4698d4"
]
]
},
{
"id": "3b9b0dc5.bae662",
"type": "debug",
"z": "533475c4.a28eac",
"name": "",
"active": true,
"console": "false",
"complete": "false",
"x": 890,
"y": 640,
"wires": []
},
{
"id": "71ef9d10.3d4904",
"type": "moment",
"z": "533475c4.a28eac",
"name": "UTC",
"topic": "UTC",
"input": "payload",
"inputType": "msg",
"inTz": "etc/GMT-4",
"adjAmount": 0,
"adjType": "days",
"adjDir": "add",
"format": "ddd Do MMM YYYY HH:mm",
"locale": "en_GB",
"output": "",
"outputType": "msg",
"outTz": "UTC",
"x": 450,
"y": 680,
"wires": [
[
"3b9b0dc5.bae662"
]
]
},
{
"id": "72638b85.4698d4",
"type": "moment",
"z": "533475c4.a28eac",
"name": "UTC+10",
"topic": "UTC+10",
"input": "payload",
"inputType": "msg",
"inTz": "etc/GMT-4",
"adjAmount": 0,
"adjType": "days",
"adjDir": "add",
"format": "ddd Do MMM YYYY HH:mm",
"locale": "en_GB",
"output": "",
"outputType": "msg",
"outTz": "etc/GMT+10",
"x": 460,
"y": 720,
"wires": [
[
"3b9b0dc5.bae662"
]
]
},
{
"id": "e862abcc.69b328",
"type": "inject",
"z": "533475c4.a28eac",
"name": "2017-05-28T21:00:00",
"topic": "",
"payload": "2017-05-28T21:00:00",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": "",
"x": 180,
"y": 760,
"wires": [
[
"72638b85.4698d4",
"71ef9d10.3d4904",
"9fe47dca.ad366"
]
]
},
{
"id": "ace5ef2a.af5c2",
"type": "inject",
"z": "533475c4.a28eac",
"name": "2017-05-28T21:00:00Z",
"topic": "",
"payload": "2017-05-28T21:00:00Z",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": "",
"x": 180,
"y": 640,
"wires": [
[
"9fe47dca.ad366",
"71ef9d10.3d4904",
"72638b85.4698d4"
]
]
},
{
"id": "acbc2d1d.86082",
"type": "comment",
"z": "533475c4.a28eac",
"name": "Expected Results",
"info": "| Input | Moment | Output |\n|---------------------------|--------|-------------------------|\n| 2017-05-28T21:00:00Z | UTC-4 | Mon 29th May 2017 01:00 |\n| | UTC | Sun 28th May 2017 21:00 |\n| | UTC+10 | Sun 28th May 2017 11:00 |\n| 2017-05-28T21:00:00-04:00 | UTC-4 | Mon 29th May 2017 05:00 |\n| | UTC | Mon 29th May 2017 01:00 |\n| | UTC+10 | Sun 28th May 2017 15:00 |\n| 2017-05-28T21:00:00 | UTC-4 | Sun 28th May 2017 07:00 |\n| | UTC | Sun 28th May 2017 17:00 |\n| | UTC+10 | Sun 28th May 2017 21:00 |",
"x": 700,
"y": 760,
"wires": []
}
]

View File

@@ -0,0 +1,80 @@
<!--
Copyright (c) 2018 Julian Knight (Totally Information)
Licensed 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.
-->
<!-- This creates and configures the onscreen elements of the node -->
<!-- First, the content of the edit dialog is defined. -->
<script type="text/x-red" data-template-name="humanizer">
<!-- data-template-name identifies the node type this is for -->
<!-- INPUT -->
<div class="form-row">
<label for="node-input-input"><i class="fa fa-arrow-left"></i> Input variable</label>
<input type="text" id="node-input-input" style="width: 70%;" placeholder="varname in msg.payload or empty for all">
</div>
<!-- NODE NAME - Should always be the last field -->
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-tips" style="font-size:83%">
Specify which property on msg.payload to humanize or use msg.payload. <br />
The input must be in seconds since the event so +10 is 10 seconds ago.<br />
Only integer numbers are allowed.
</div>
</script>
<!-- Next, some simple help text is provided for the node. -->
<!-- The first <p> is used as the pop-up tool tip when hovering over pallette -->
<script type="text/x-red" data-help-name="humanizer">
<p>
Humanize timespans in seconds.
</p>
<p>
Uses the humanize functionality in the moment.js library.
</p>
<p>
Input must be in integer seconds.
</p>
<p>
Contributed by <a href="https://github.com/Laro88">Laro88</a>
</p>
</script>
<!-- Finally, the node type is registered along with all of its properties -->
<script type="text/javascript">
RED.nodes.registerType('humanizer',{
category: 'formats', // the palette category
color: '#E6E0F8',
defaults: {
name: {value:''},
input: {value:''}
},
inputs:1, // set the number of inputs - only 0 or 1
outputs:1, // set the number of outputs - 0 to n
// set the icon (held in icons dir below where you save the node)
icon: 'timer.png', // saved in icons/myicon.png
label: function() { // sets the default label contents
return this.name||'Humanizer';
},
labelStyle: function() { // sets the class to apply to the label
return this.name?'node_label_italic':'';
}
}); // ---- end of RED.nodes.registerType ---- //
</script>

View File

@@ -0,0 +1,75 @@
/**
* Copyright (c) 2018 Julian Knight (Totally Information)
*
* Licensed 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.
**/
// JK Note: This code contributed by (Contributed by Laro88, https://github.com/Laro88)
// Tidying done by JK. Also removed dependency on validator which is vastly OTT for just ensuring an integer
// 2017-04-13
// Node for Node-Red that humalizes a timespan msg.payload.[] //TODO whould this be extended to work on Date objects as well and if so how?
// It is helpful when working with ui things that informs users of time since last operation etc.
// require moment.js (must be installed from package.js as a dependency)
var moment = require('moment-timezone');
// Module name must match this nodes html file
var moduleName = 'humanizer';
module.exports = function(RED) {
'use strict';
// The main node definition - most things happen in here
function nodeGo(config) {
// Create a RED node
RED.nodes.createNode(this,config);
// Store local copies of the node configuration (as defined in the .html)
this.topic = config.topic;
this.input = config.input || 'payload'; // where to take the input from
// copy "this" object in case we need it in context of callbacks of other functions.
var node = this;
// respond to inputs....
node.on('input', function (msg) {
'use strict'; // We will be using eval() so lets get a bit of safety using strict
//console.log(this.input);
var v = msg.payload.hasOwnProperty(this.input) ? msg.payload[this.input] : msg.payload;
// JK: Replace validator with native JS INT check, improve warning message
//v = v;
//if( !validator.isInt(v) ) {
if( ! Number.isInteger(v) ) {
return node.warn('Invalid input for humanize call, input must be an integer');
}
// JK: Pass seconds to duration - remove *1000 ms conversion
var _humanized = moment.duration(v, 'seconds').humanize();
if(typeof(msg.payload) == 'object'){
msg.payload.humanized = _humanized;
}
else{
msg.payload = {'humanized':_humanized};
}
node.send(msg);
});
} // ---- end of nodeGo function ---- //
// Register the node by name. This must be called before overriding any of the
// Node functions.
RED.nodes.registerType(moduleName,nodeGo);
};

View File

@@ -0,0 +1,290 @@
<!--
Copyright (c) 2018 Julian Knight (Totally Information)
Licensed 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.
-->
<!-- This creates and configures the onscreen elements of the node -->
<!-- First, the content of the edit dialog is defined. -->
<script type="text/x-red" data-template-name="moment">
<!-- data-template-name identifies the node type this is for -->
<!-- INPUT -->
<div class="form-row">
<label for="node-input-input"><i class="fa fa-arrow-left"></i> Input from</label>
<input type="text" id="node-input-input" style="width: 70%;" placeholder="payload">
<input type="hidden" id="node-input-inputType">
</div>
<!-- INPUT TIMEZONE -->
<div class="form-row">
<label for="node-input-inTz">Input Timezone</label>
<input type="text" id="node-input-inTz" placeholder="[determined by system]" style="width:70%;">
</div>
<!-- ADJUSTMENT -->
<div class="form-row">
<label for="node-input-adjAmount"> Adjustment</label>
<select id="node-input-adjDir" style="width:4em">
<option value="add">+</option>
<option value="subtract">-</option>
</select>
<input type="text" id="node-input-adjAmount" placeholder="0" style="width:25%;">
<select id="node-input-adjType" style="width:30%">
<option value="days">Days</option>
<option value="hours">Hours</option>
<option value="weeks">Weeks</option>
<option value="months">Months</option>
<option value="quarters">Quarters</option>
<option value="years">Years</option>
<option value="minutes">Minutes</option>
<option value="seconds">Seconds</option>
<option value="milliseconds">Milliseconds</option>
</select>
</div>
<!-- OUTPUT FORMAT -->
<br />
<div class="form-row">
<label for="node-input-format"><i class="fa fa-eye-open"></i> Output Format</label>
<input type="text" id="node-input-format" placeholder="ISO8601 (UTC)">
</div>
<!-- OUTPUT LOCALE -->
<div class="form-row">
<label for="node-input-locale"><i class="fa fa-flag"></i> Locale</label>
<input type="text" id="node-input-locale" placeholder="en">
</div>
<!-- OUTPUT TIMEZONE -->
<div class="form-row">
<label for="node-input-outTz">Output Tz</label>
<input type="text" id="node-input-outTz" placeholder="[determined by system]" style="width:70%;">
</div>
<!-- OUTPUT OBJECT -->
<div class="form-row">
<label for="node-input-output"><i class="fa fa-arrow-right"></i> Output to</label>
<input type="text" id="node-input-output" style="width: 70%;" placeholder="payload">
<input type="hidden" id="node-input-outputType">
</div>
<br/>
<!-- TOPIC -->
<div class="form-row">
<label for="node-input-topic"><i class="fa fa-tasks"></i> Topic</label>
<input type="text" id="node-input-topic" placeholder="Topic">
</div>
<!-- NODE NAME - Should always be the last field -->
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-tips" style="font-size:83%">
See the info sidebar for formatting details. <br />
Use locale and format to change string output.<br />
See the info sidebar for several warnings about inputting strings.
</div>
</script>
<!-- Next, some simple help text is provided for the node. -->
<!-- The first <p> is used as the pop-up tool tip when hovering over pallette -->
<script type="text/x-red" data-help-name="moment">
<p>
Convert date/time object or string to nicely formatted text or date/time object.
</p>
<p>
Uses the moment.js library. Now updated to use moment-timezone.js for full timezone and DST handling.
Also uses moment.parseFormat for string inputs and os-locale for output localisation.
This version requires Node v6+.
</p>
<p>
See the <a href="https://github.com/TotallyInformation/node-red-contrib-moment">readme file</a> for a change log.
</p>
<h3>Input</h3>
<p>
If the input property does not exist or is left blank, the current date/time will be assumed.
This can be used to add a current timestamp to a flow of any kind easily.
</p>
<p>Otherwise, the input is processed as follows:</p>
<ul>
<li>If input is "timestamp" or a JS datetime object or a <a href="http://momentjs.com/docs/#/parsing/">string that Moment.js</a> can resolve
(with the help of <a href="https://github.com/gr2m/moment-parseformat">moment.parseFormat</a>). It will be processed as normal.</li>
<li>If the input is null, is a blank string or a string that cannot be converted. The output will be an empty string.</li>
</ul>
<h4>String input warnings</h4>
<p>
Note that parsing date/time strings is a hard problem. moment.parseFormat helps but it isn&apos;t magic.
We assume that ambiguous input dates such as <code>3/5/05</code> are in EU/UK format <code>dd/mm/yy</code> <i>unless</i>
either the input timezone is in <i>America</i> or the locale is set to <i>en_US</i>.
</p>
<h3>Input Timezone</h3>
<p>
If blank, the node will try to guess. If you have set your host system to a local timezone (e.g. <code>dpkg-reconfigure tzdata</code> on Linux)
then by default, input timestamps from the <code>inject</code> node will be in that timezone, otherwise they will be in UTC.
You can override this by specifying the full timezone in the format <code>region/location</code>,
e.g. <code>Europe/London</code>. Note that spellings are not validated, if it doesn&apos;t seem to work, check the valid timezone
list built in to moment-timezone.
</p>
<h3>Output</h3>
<p>
Is a formatted string if the output format is anything other than <code>date</code> or <code>object</code>
in which case, the output is a Javascript date object or an object as described below respectively.
</p>
<p>
Output string formatting is controlled by the Locale setting and the output format field.
Note that the output Timezone is ignored for ISO8601 output (the default), such output is <i>always</i>
in UTC. For other formats, the output will be in the specified timezone which defaults to your host timezone.
</p>
<p>
Specifying different input and output timezones allows you to translated between them.
</p>
<p>
The output msg will pass through the input msg.topic unless it is overridden. If the "Output to" field is changed
from the default <code>msg.payload</code>, the input msg.payload will also be passed through.
</p>
<h3>Output String Formatting</h3>
<p>
May be any <a href="http://momentjs.com/docs/#/displaying/format/">format string
allowed by Moment.JS</a> (try <code>LLL</code> for a localised output for example).
The formatting additions from moment-timezone are also allowed.<br>
In addition, the following (not case sensitive, alternatives in brackets) format strings are also allowed:
</p>
<dl>
<dt>Blank (ISO8601, ISO)</dt>
<dd>
ISO 8602 format, e.g. "2015-01-28T16:24:48.123Z"<br>
Note that ISO8601 formatted output is ALWAYS in UTC ('Z', Zulu time) not
local, no matter what output timezone you may specify.
</dd>
<dt>date (jsDate)</dt>
<dd>
A Javascript Date object<br>
This is the default if the input is a recognised date string
</dd>
<dt>object</dt>
<dd>
A Javascript object in the form <code>{years:nnnn, months:n, date:n, hours:n, minutes:n, seconds:n, milliseconds:n}</code>
<br>
<em>WARNING</em>: moment.js has a bizarre object format where the month is zero-based (0-11) instead of 1-based (1-12) like all the other elements are.
I don't currently know why, I've raised an upstream issue but this appears to be a deliberate decision for some strange reason.
</dd>
<dt>fromNow (timeAgo)</dt>
<dd>
Human readable output<br />
e.g. 30 minutes ago
</dd>
<dt>calendar (aroundNow)</dt>
<dd>
Human readable alternative<br />
e.g. "Last Monday", "Tomorrow 2:30pm"<br />
Note that dates beyond a week from now are output as yyyy-mm-dd
</dd>
</dl>
<p>
Note that with the exception of ISO8601, other formats are in the specified
timezone & DST. If not specified, the output timezone/DST is the same as the input.<br />
Use an output timezone of <code>UTC</code> to force output to that.
</p>
<p>
If output is shown in the wrong format, such as dates in US mm/dd/yy format, change the
output locale. For example, using <code>en_gb</code> will force short dates to output in
dd/mm/yy format. The default is <code>en</code> which moment assumes means the USA :-(
</p>
</script>
<!-- Finally, the node type is registered along with all of its properties -->
<script type="text/javascript">
function tzValidate(val) {
// auto-correct the entry
//$('#node-input-inTz').val( val.replace(/^GMT|UTC/i, 'ETC/GMT') )
return true
}
RED.nodes.registerType('moment',{
category: 'formats', // the palette category
color: '#E6E0F8',
defaults: {
name: {value:''},
topic: {value:''},
input: {value:''},
inputType: {value:'msg'},
inTz: {value:'', validate:tzValidate},
adjAmount: {value:0, validate:RED.validators.number()},
adjType: {value:'days'},
adjDir: {value:'add'},
format: {value:''},
locale: {value:''},
output: {value:''},
outputType: {value:'msg'},
outTz: {value:'', validate:tzValidate}
},
inputs:1, // set the number of inputs - only 0 or 1
outputs:1, // set the number of outputs - 0 to n
// set the icon (held in icons dir below where you save the node)
icon: 'timer.png', // saved in icons/myicon.png
label: function() { // sets the default label contents
return this.name||this.topic||'Date/Time Formatter';
},
labelStyle: function() { // sets the class to apply to the label
return this.name?'node_label_italic':'';
},
oneditprepare: function() {
// Make sure we can reference parent this in async fns
var _this = this
if (!this.inputType) {
this.inputType = 'msg';
}
$('#node-input-input').typedInput({
default: 'msg',
types: ['msg','flow','global','date','str'],
typeField: $('#node-input-inputType')
});
if (!this.outputType) {
this.outputType = 'msg';
}
$('#node-input-output').typedInput({
default: 'msg',
types: ['msg','flow','global'],
typeField: $('#node-input-outputType')
});
// Get host locale and timezone
$.getJSON('contribapi/moment',function(data) {
// Save to parent object
_this.localeData = data
if ( $('#node-input-inTz').val() === '' ) $('#node-input-inTz').val(data.tz);
if ( $('#node-input-outTz').val() === '' ) $('#node-input-outTz').val(data.tz);
if ( $('#node-input-locale').val() === '' ) $('#node-input-locale').val(data.locale);
});
// Autocorrect timezone entries
$('#node-input-inTz').add('#node-input-outTz').blur( function(){
if( this.value === '' ) {
// Use saved locale data from parent object as default
this.value = _this.localeData.tz
} else {
// autocorrect common tz errors
this.value = this.value.replace(/^GMT|UTC/i, 'ETC/GMT')
}
})
} // --- end of oneditprepare --- //
}); // ---- end of RED.nodes.registerType ---- //
</script>

View File

@@ -0,0 +1,311 @@
/**
* Copyright (c) 2018 Julian Knight (Totally Information)
*
* Licensed 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.
**/
// Node for Node-Red that outputs a nicely formatted string from a date/time
// object or string using the moment.js library.
// require moment.js (must be installed from package.js as a dependency)
var moment = require('moment-timezone');
var parseFormat = require('moment-parseformat');
var osLocale = require('os-locale');
var hostTz = moment.tz.guess();
var hostLocale = osLocale.sync();
// Module name must match this nodes html file
var moduleName = 'moment';
module.exports = function(RED) {
'use strict';
// The main node definition - most things happen in here
function nodeGo(config) {
// Create a RED node
RED.nodes.createNode(this,config);
// Store local copies of the node configuration (as defined in the .html)
this.topic = config.topic;
this.input = config.input || 'payload'; // where to take the input from
this.inputType = config.inputType || 'msg'; // msg, flow, global, timestamp or string
this.fakeUTC = config.fakeUTC || false; // is the input UTC rather than local date/time?
this.adjAmount = config.adjAmount || 0; // number
this.adjType = config.adjType || 'days'; // days, hours, etc.
this.adjDir = config.adjDir || 'add'; // add or subtract
this.format = config.format || ''; // valid moment.js format string
this.locale = config.locale || false // valid moment.js locale string
this.output = config.output || 'payload'; // where to put the output
this.outputType = config.outputType || 'msg'; // msg, flow or global
this.inTz = config.inTz || false; // timezone, '' or zone name, e.g. Europe/London
this.outTz = config.outTz || this.inTz; // timezone, '' or zone name, e.g. Europe/London
// copy "this" object in case we need it in context of callbacks of other functions.
var node = this;
// respond to inputs....
node.on('input', function (msg) {
'use strict'; // We will be using eval() so lets get a bit of safety using strict
// If the node's topic is set, copy to output msg
if ( node.topic !== '' ) {
msg.topic = node.topic;
} // If nodes topic is blank, the input msg.topic is already there
// make sure output property is set, if not, assume msg.payload
if ( node.output === '' ) {
node.output = 'payload';
//node.warn('Output field is REQUIRED, currently blank, set to payload');
}
if ( node.outputType === '' ) {
node.outputType = 'msg';
node.warn('Output Type field is REQUIRED, currently blank, set to msg');
}
// If the input property is blank, assume NOW as the required timestamp
// or make sure that the node's input property actually exists on the input msg
var inp = '';
// If input is a blank string, use a Date object with Now DT
if ( node.input === '' ) {
inp = new Date();
} else {
// Otherwise, check which input type & get the input
try {
switch ( node.inputType ) {
case 'msg':
inp = RED.util.getMessageProperty(msg, node.input);
break;
case 'flow':
inp = node.context().flow.get(node.input);
break;
case 'global':
inp = node.context().global.get(node.input);
break;
case 'date':
inp = new Date();
break;
case 'str':
inp = node.input.trim();
break;
default:
inp = new Date();
node.warn('Unrecognised Input Type, ' + node.inputType + '. Output has been set to NOW.');
}
} catch (err) {
inp = new Date();
node.warn('Input property, ' + node.inputType + '.' + node.input + ', does NOT exist. Output has been set to NOW.');
}
}
// We are going to overwrite the output property without warning or permission!
// Final check for input being a string (which moment doesn't really want to handle)
// NB: moment.js v3 will stop accepting strings. v2.7+ throws a warning.
var dtHack = '', inpFmt = '';
// @from v3 2018-09-23: If input is `null`, change to empty string
if ( inp === null ) inp = '';
if ( (typeof inp) === 'string' ) {
inp = inp.trim();
// Some string input hacks
switch (inp.toLowerCase()) {
case 'today':
inp = new Date();
break;
case 'yesterday':
inp = new Date();
dtHack = {days:-1};
break;
case 'tomorrow':
inp = new Date();
dtHack = {days:+1};
break;
default:
var prefOrder = {preferredOrder: {'/': 'DMY', '.': 'DMY', '-': 'YMD'} };
if ( (node.locale.toLowerCase().replace('-','_') === 'en_US') || (node.inTz.split('/')[0] === 'America') ) {
prefOrder = {preferredOrder: {'/': 'MDY', '.': 'DMY', '-': 'YMD'} };
}
inpFmt = parseFormat(inp, prefOrder);
}
} else if ( (typeof inp) === 'number' ) {
// @from 2017-06-15 IF inp is a number at this point, it needs turning into a date object
inp = new Date(inp)
}
// At this point, `inp` SHOULD be a Date object and safe to pass to moment.js
if ( !node.inTz ) { node.inTz = hostTz; }
if ( !node.outTz ) { node.outTz = node.inTz; }
// Validate input and output timezones - @since 2.0.4
if ( moment.tz.zone(node.inTz) === null ) {
// tz invalid, warn and set to UTC
node.warn('Moment: Input Timezone Invalid, reset to UTC - see http://momentjs.com/timezone/docs/#/data-loading/')
node.inTz = 'UTC'
}
if ( moment.tz.zone(node.outTz) === null ) {
// tz invalid, warn and set to UTC
node.warn('Moment: Output Timezone Invalid, reset to UTC - see http://momentjs.com/timezone/docs/#/data-loading/')
node.outTz = 'UTC'
}
// Get a Moment.JS date/time - NB: the result might not be
// valid since the input might not parse as a date/time
var mDT;
if ( inpFmt !== '' ) {
mDT = moment.tz(inp, inpFmt, true, node.inTz);
} else {
// @from 2017-06-15 change to momentjs meant having to add null parameter
mDT = moment.tz(inp, null, true, node.inTz)
}
// Fallback to JS built-in Date parsing, if not recognized by moment
if (!mDT.isValid()) {
var dtm = new Date(inp);
if (dtm === 'Invalid Date') {
node.warn('Unrecognized date string format => ' + inp);
}
else {
mDT = moment(dtm);
}
}
// Adjust the date for input hacks if needed (e.g. input was "yesterday" or "tommorow")
if ( dtHack !== '' ) { mDT.add(dtHack); }
// JK: Added OS locale lookup
if ( !node.locale ) { node.locale = hostLocale; }
// JK: Add a trap to Jaques44's locale code in case the output locale string is invalid
try {
// Jacques44 - set locale for localised output formats
mDT.locale(node.locale);
} catch (err) {
node.warn('Locale string invalid - check moment.js for valid strings');
}
// Adjust the input date if required
if ( node.adjAmount !== 0 ) {
// check if measure is valid
if ( isMeasureValid(node.adjType) ) {
// NB: moments are mutable so don't need to reassign
if ( node.adjDir === 'subtract') {
mDT.subtract(node.adjAmount, node.adjType);
} else {
mDT.add(node.adjAmount, node.adjType);
}
} else {
// it isn't valid so warn and don't adjust
node.warn('Adjustment measure type not valid, no adjustment made - check moment.js docs for valid measures (days, hours, etc)');
}
}
// ==== NO MORE DATE/TIME CALCULATIONS AFTER HERE ==== //
// If required, change to the output Timezone
if ( node.outTz !== '' ) mDT.tz(node.outTz);
// Check if the input is a date?
if ( ! mDT.isValid() ) {
// THIS SHOULD NEVER BE CALLED - it left to catch the occasional error
node.warn('The input property was NOT a recognisable date. Output will be a blank string');
setOutput(msg, node.outputType, node.output, '');
} else {
// Handle different format strings. We allow any fmt str that
// Moment.JS supports but also some special formats
// If format not set, assume ISO8601 string if input is a Date otherwise assume Date
switch ( node.format.toLowerCase() ) {
case '':
case 'iso8601':
case 'iso':
// Default to ISO8601 string
setOutput(msg, node.outputType, node.output, mDT.toISOString());
break;
case 'fromnow':
case 'timeago':
// We are also going to handle time-from-now (AKA time ago) format
setOutput(msg, node.outputType, node.output, mDT.fromNow());
break;
case 'calendar':
case 'aroundnow':
// We are also going to handle calendar format (AKA around now)
// Force dates >1 week from now to be in ISO instead of US format
setOutput(msg, node.outputType, node.output, mDT.calendar(null,{sameElse:'YYYY-MM-DD'}));
break;
case 'date':
case 'jsdate':
// we also allow output as a Javascript Date object
setOutput(msg, node.outputType, node.output, mDT.toDate());
break;
case 'object':
// we also allow output as a Javascript Date object
setOutput(msg, node.outputType, node.output, mDT.toObject());
break;
default:
// or we assume it is a valid format definition ...
setOutput(msg, node.outputType, node.output, mDT.format(node.format));
}
}
// Send the output message
node.send(msg);
});
// Tidy up if we need to
//node.on('close', function() {
// Called when the node is shutdown - eg on redeploy.
// Allows ports to be closed, connections dropped etc.
// eg: node.client.disconnect();
//});
// Set the appropriate output variable
function setOutput(msg, outputType, output, value) {
try {
switch ( outputType ) {
case 'msg':
RED.util.setMessageProperty(msg, output, value);
break;
case 'flow':
node.context().flow.set(output, value);
break;
case 'global':
node.context().global.set(output, value);
break;
default:
node.warn('Unrecognised Output Type, ' + outputType + '. No output.');
}
} catch (err) {
node.warn('Output property, ' + outputType + '.' + output + ', cannot be set. No output.', err);
}
} // --- end of setOutput function --- //
// Is the date/time adjustment type (measure) valid? See moment.js docs
function isMeasureValid(adjType) {
var validTypes = ['years','y','quarters','Q','months','M','weeks','w','days','d','hours','h','minutes','m','seconds','s','milliseconds','ms'];
//return validTypes.includes(adjType);
return validTypes.indexOf(adjType) > -1;
} // --- end of isMeasureValid function --- //
} // ---- end of nodeGo function ---- //
// Register the node by name. This must be called before overriding any of the
// Node functions.
RED.nodes.registerType(moduleName,nodeGo);
// Create API listener: sends the host locale & timezone to the admin ui
// NB: uses Express middleware on the admin server
RED.httpAdmin.get('/contribapi/moment', RED.auth.needsPermission('moment.read'), function(req,res) {
res.json({
'tz': hostTz,
'locale': hostLocale
});
});
};

View File

@@ -0,0 +1,92 @@
{
"_from": "node-red-contrib-moment@3.0.3",
"_id": "node-red-contrib-moment@3.0.3",
"_inBundle": false,
"_integrity": "sha512-rZGvETymYQuNeHL5uUmhaSNhiGAFLkKHI2viuiSdlpcCEVw7Yg4op4dI/uK40MT+3nbEYE7GIJ/aYwldr6WPXA==",
"_location": "/node-red-contrib-moment",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "node-red-contrib-moment@3.0.3",
"name": "node-red-contrib-moment",
"escapedName": "node-red-contrib-moment",
"rawSpec": "3.0.3",
"saveSpec": null,
"fetchSpec": "3.0.3"
},
"_requiredBy": [
"#USER",
"/"
],
"_resolved": "https://registry.npmjs.org/node-red-contrib-moment/-/node-red-contrib-moment-3.0.3.tgz",
"_shasum": "d340cf42dc422f1d37d595d04401ff48a51e674f",
"_spec": "node-red-contrib-moment@3.0.3",
"_where": "/data",
"author": {
"name": "Julian Knight",
"url": "https://github.com/totallyinformation"
},
"bugs": {
"url": "https://github.com/totallyinformation/node-red-contrib-moment/issues"
},
"bundleDependencies": false,
"contributors": [
{
"name": "Jacques W",
"url": "Jacques44"
},
{
"name": "Jes Ramsing",
"url": "Laro88"
}
],
"dependencies": {
"moment": "^2.24.0",
"moment-parseformat": "^3.0.0",
"moment-timezone": "^0.5.23",
"os-locale": "^3.1.0"
},
"deprecated": false,
"description": "Node-Red Node that produces formatted Date/Time output using the Moment.JS library. Timezone, dst and locale aware.",
"directories": {},
"engines": {
"node": ">4"
},
"homepage": "https://github.com/totallyinformation/node-red-contrib-moment",
"keywords": [
"node-red",
"moment",
"time",
"date",
"timezone",
"locale",
"DST"
],
"license": "Apache-2.0",
"main": "moment/nrmoment.js",
"name": "node-red-contrib-moment",
"node-red": {
"nodes": {
"moment": "moment/nrmoment.js",
"humanizer": "moment/nrhumanizer.js"
}
},
"repository": {
"type": "git",
"url": "git+https://github.com/totallyinformation/node-red-contrib-moment.git"
},
"scripts": {
"gitpushtags": "git push origin --tags",
"gittag": "git tag -a v$npm_package_version",
"gittags": "git tag",
"listbin": "ls ./node_modules/bin",
"npmtagnext": "npm dist-tag add node-red-contrib-uibuilder@$npm_package_version next",
"npmtags": "npm dist-tag ls node-red-contrib-uibuilder",
"presync": "npm run pull",
"pull": "git pull origin",
"push": "git push origin",
"sync": "npm run push"
},
"version": "3.0.3"
}