datemath.ts 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import _ from 'lodash';
  2. import moment from 'moment';
  3. const units = ['y', 'M', 'w', 'd', 'h', 'm', 's'];
  4. export function parse(text, roundUp?, timezone?) {
  5. if (!text) {
  6. return undefined;
  7. }
  8. if (moment.isMoment(text)) {
  9. return text;
  10. }
  11. if (_.isDate(text)) {
  12. return moment(text);
  13. }
  14. let time;
  15. let mathString = '';
  16. let index;
  17. let parseString;
  18. if (text.substring(0, 3) === 'now') {
  19. if (timezone === 'utc') {
  20. time = moment.utc();
  21. } else {
  22. time = moment();
  23. }
  24. mathString = text.substring('now'.length);
  25. } else {
  26. index = text.indexOf('||');
  27. if (index === -1) {
  28. parseString = text;
  29. mathString = ''; // nothing else
  30. } else {
  31. parseString = text.substring(0, index);
  32. mathString = text.substring(index + 2);
  33. }
  34. // We're going to just require ISO8601 timestamps, k?
  35. time = moment(parseString, moment.ISO_8601);
  36. }
  37. if (!mathString.length) {
  38. return time;
  39. }
  40. return parseDateMath(mathString, time, roundUp);
  41. }
  42. export function isValid(text) {
  43. const date = parse(text);
  44. if (!date) {
  45. return false;
  46. }
  47. if (moment.isMoment(date)) {
  48. return date.isValid();
  49. }
  50. return false;
  51. }
  52. export function parseDateMath(mathString, time, roundUp?) {
  53. const dateTime = time;
  54. let i = 0;
  55. const len = mathString.length;
  56. while (i < len) {
  57. const c = mathString.charAt(i++);
  58. let type;
  59. let num;
  60. let unit;
  61. if (c === '/') {
  62. type = 0;
  63. } else if (c === '+') {
  64. type = 1;
  65. } else if (c === '-') {
  66. type = 2;
  67. } else {
  68. return undefined;
  69. }
  70. if (isNaN(mathString.charAt(i))) {
  71. num = 1;
  72. } else if (mathString.length === 2) {
  73. num = mathString.charAt(i);
  74. } else {
  75. const numFrom = i;
  76. while (!isNaN(mathString.charAt(i))) {
  77. i++;
  78. if (i > 10) {
  79. return undefined;
  80. }
  81. }
  82. num = parseInt(mathString.substring(numFrom, i), 10);
  83. }
  84. if (type === 0) {
  85. // rounding is only allowed on whole, single, units (eg M or 1M, not 0.5M or 2M)
  86. if (num !== 1) {
  87. return undefined;
  88. }
  89. }
  90. unit = mathString.charAt(i++);
  91. if (!_.includes(units, unit)) {
  92. return undefined;
  93. } else {
  94. if (type === 0) {
  95. if (roundUp) {
  96. dateTime.endOf(unit);
  97. } else {
  98. dateTime.startOf(unit);
  99. }
  100. } else if (type === 1) {
  101. dateTime.add(num, unit);
  102. } else if (type === 2) {
  103. dateTime.subtract(num, unit);
  104. }
  105. }
  106. }
  107. return dateTime;
  108. }