38ff51ee9a4f8df1de4b4ea07476941a17de25c6295ccae0ee717a535ed6470f89e931e358ac3655c134febd9ae292cb346f7211b570b3e4ee683ee79c488a-exec 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. 'use strict';
  2. const Hoek = require('@hapi/hoek');
  3. const Any = require('../any');
  4. const Ref = require('../../ref');
  5. const internals = {};
  6. internals.isoDate = /^(?:[-+]\d{2})?(?:\d{4}(?!\d{2}\b))(?:(-?)(?:(?:0[1-9]|1[0-2])(?:\1(?:[12]\d|0[1-9]|3[01]))?|W(?:[0-4]\d|5[0-2])(?:-?[1-7])?|(?:00[1-9]|0[1-9]\d|[12]\d{2}|3(?:[0-5]\d|6[1-6])))(?![T]$|[T][\d]+Z$)(?:[T\s](?:(?:(?:[01]\d|2[0-3])(?:(:?)[0-5]\d)?|24\:?00)(?:[.,]\d+(?!:))?)(?:\2[0-5]\d(?:[.,]\d+)?)?(?:[Z]|(?:[+-])(?:[01]\d|2[0-3])(?::?[0-5]\d)?)?)?)?$/;
  7. internals.invalidDate = new Date('');
  8. internals.isIsoDate = (() => {
  9. const isoString = internals.isoDate.toString();
  10. return (date) => {
  11. return date && (date.toString() === isoString);
  12. };
  13. })();
  14. internals.Date = class extends Any {
  15. constructor() {
  16. super();
  17. this._type = 'date';
  18. }
  19. _base(value, state, options) {
  20. const result = {
  21. value: (options.convert && internals.Date.toDate(value, this._flags.format, this._flags.timestamp, this._flags.multiplier)) || value
  22. };
  23. if (result.value instanceof Date && !isNaN(result.value.getTime())) {
  24. result.errors = null;
  25. }
  26. else if (!options.convert) {
  27. result.errors = this.createError('date.strict', { value }, state, options);
  28. }
  29. else {
  30. let type;
  31. if (internals.isIsoDate(this._flags.format)) {
  32. type = 'isoDate';
  33. }
  34. else if (this._flags.timestamp) {
  35. type = `timestamp.${this._flags.timestamp}`;
  36. }
  37. else {
  38. type = 'base';
  39. }
  40. result.errors = this.createError(`date.${type}`, { value }, state, options);
  41. }
  42. return result;
  43. }
  44. static toDate(value, format, timestamp, multiplier) {
  45. if (value instanceof Date) {
  46. return value;
  47. }
  48. if (typeof value === 'string' ||
  49. (typeof value === 'number' && !isNaN(value) && isFinite(value))) {
  50. const isIsoDate = format && internals.isIsoDate(format);
  51. if (!isIsoDate &&
  52. typeof value === 'string' &&
  53. /^[+-]?\d+(\.\d+)?$/.test(value)) {
  54. value = parseFloat(value);
  55. }
  56. let date;
  57. if (isIsoDate) {
  58. date = format.test(value) ? new Date(value.toString()) : internals.invalidDate;
  59. }
  60. else if (timestamp) {
  61. date = /^\s*$/.test(value) ? internals.invalidDate : new Date(value * multiplier);
  62. }
  63. else {
  64. date = new Date(value);
  65. }
  66. if (!isNaN(date.getTime())) {
  67. return date;
  68. }
  69. }
  70. return null;
  71. }
  72. iso() {
  73. if (this._flags.format === internals.isoDate) {
  74. return this;
  75. }
  76. const obj = this.clone();
  77. obj._flags.format = internals.isoDate;
  78. return obj;
  79. }
  80. timestamp(type = 'javascript') {
  81. const allowed = ['javascript', 'unix'];
  82. Hoek.assert(allowed.includes(type), '"type" must be one of "' + allowed.join('", "') + '"');
  83. if (this._flags.timestamp === type) {
  84. return this;
  85. }
  86. const obj = this.clone();
  87. obj._flags.timestamp = type;
  88. obj._flags.multiplier = type === 'unix' ? 1000 : 1;
  89. return obj;
  90. }
  91. _isIsoDate(value) {
  92. return internals.isoDate.test(value);
  93. }
  94. };
  95. internals.compare = function (type, compare) {
  96. return function (date) {
  97. const isNow = date === 'now';
  98. const isRef = Ref.isRef(date);
  99. if (!isNow && !isRef) {
  100. date = internals.Date.toDate(date);
  101. }
  102. Hoek.assert(date, 'Invalid date format');
  103. return this._test(type, date, function (value, state, options) {
  104. let compareTo;
  105. if (isNow) {
  106. compareTo = Date.now();
  107. }
  108. else if (isRef) {
  109. const refValue = date(state.reference || state.parent, options);
  110. compareTo = internals.Date.toDate(refValue);
  111. if (!compareTo) {
  112. return this.createError('date.ref', { ref: date, value: refValue }, state, options);
  113. }
  114. compareTo = compareTo.getTime();
  115. }
  116. else {
  117. compareTo = date.getTime();
  118. }
  119. if (compare(value.getTime(), compareTo)) {
  120. return value;
  121. }
  122. return this.createError('date.' + type, { limit: new Date(compareTo), value }, state, options);
  123. });
  124. };
  125. };
  126. internals.Date.prototype.min = internals.compare('min', (value, date) => value >= date);
  127. internals.Date.prototype.max = internals.compare('max', (value, date) => value <= date);
  128. internals.Date.prototype.greater = internals.compare('greater', (value, date) => value > date);
  129. internals.Date.prototype.less = internals.compare('less', (value, date) => value < date);
  130. module.exports = new internals.Date();