206860e0c45207e666803c5905e861dc82a0ef53169ad0e05cebc65942e4c1b3b6efe611df97451e107d081b54a81d543a3629a4bf9921c257a094572a9f99 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. import { Duration, isDuration } from './constructor';
  2. import isNumber from '../utils/is-number';
  3. import toInt from '../utils/to-int';
  4. import absRound from '../utils/abs-round';
  5. import hasOwnProp from '../utils/has-own-prop';
  6. import { DATE, HOUR, MINUTE, SECOND, MILLISECOND } from '../units/constants';
  7. import { cloneWithOffset } from '../units/offset';
  8. import { createLocal } from '../create/local';
  9. import { createInvalid as invalid } from './valid';
  10. // ASP.NET json date format regex
  11. var aspNetRegex = /^(-|\+)?(?:(\d*)[. ])?(\d+):(\d+)(?::(\d+)(\.\d*)?)?$/,
  12. // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
  13. // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
  14. // and further modified to allow for strings containing both week and day
  15. isoRegex =
  16. /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;
  17. export function createDuration(input, key) {
  18. var duration = input,
  19. // matching against regexp is expensive, do it on demand
  20. match = null,
  21. sign,
  22. ret,
  23. diffRes;
  24. if (isDuration(input)) {
  25. duration = {
  26. ms: input._milliseconds,
  27. d: input._days,
  28. M: input._months,
  29. };
  30. } else if (isNumber(input) || !isNaN(+input)) {
  31. duration = {};
  32. if (key) {
  33. duration[key] = +input;
  34. } else {
  35. duration.milliseconds = +input;
  36. }
  37. } else if ((match = aspNetRegex.exec(input))) {
  38. sign = match[1] === '-' ? -1 : 1;
  39. duration = {
  40. y: 0,
  41. d: toInt(match[DATE]) * sign,
  42. h: toInt(match[HOUR]) * sign,
  43. m: toInt(match[MINUTE]) * sign,
  44. s: toInt(match[SECOND]) * sign,
  45. ms: toInt(absRound(match[MILLISECOND] * 1000)) * sign, // the millisecond decimal point is included in the match
  46. };
  47. } else if ((match = isoRegex.exec(input))) {
  48. sign = match[1] === '-' ? -1 : 1;
  49. duration = {
  50. y: parseIso(match[2], sign),
  51. M: parseIso(match[3], sign),
  52. w: parseIso(match[4], sign),
  53. d: parseIso(match[5], sign),
  54. h: parseIso(match[6], sign),
  55. m: parseIso(match[7], sign),
  56. s: parseIso(match[8], sign),
  57. };
  58. } else if (duration == null) {
  59. // checks for null or undefined
  60. duration = {};
  61. } else if (
  62. typeof duration === 'object' &&
  63. ('from' in duration || 'to' in duration)
  64. ) {
  65. diffRes = momentsDifference(
  66. createLocal(duration.from),
  67. createLocal(duration.to)
  68. );
  69. duration = {};
  70. duration.ms = diffRes.milliseconds;
  71. duration.M = diffRes.months;
  72. }
  73. ret = new Duration(duration);
  74. if (isDuration(input) && hasOwnProp(input, '_locale')) {
  75. ret._locale = input._locale;
  76. }
  77. if (isDuration(input) && hasOwnProp(input, '_isValid')) {
  78. ret._isValid = input._isValid;
  79. }
  80. return ret;
  81. }
  82. createDuration.fn = Duration.prototype;
  83. createDuration.invalid = invalid;
  84. function parseIso(inp, sign) {
  85. // We'd normally use ~~inp for this, but unfortunately it also
  86. // converts floats to ints.
  87. // inp may be undefined, so careful calling replace on it.
  88. var res = inp && parseFloat(inp.replace(',', '.'));
  89. // apply sign while we're at it
  90. return (isNaN(res) ? 0 : res) * sign;
  91. }
  92. function positiveMomentsDifference(base, other) {
  93. var res = {};
  94. res.months =
  95. other.month() - base.month() + (other.year() - base.year()) * 12;
  96. if (base.clone().add(res.months, 'M').isAfter(other)) {
  97. --res.months;
  98. }
  99. res.milliseconds = +other - +base.clone().add(res.months, 'M');
  100. return res;
  101. }
  102. function momentsDifference(base, other) {
  103. var res;
  104. if (!(base.isValid() && other.isValid())) {
  105. return { milliseconds: 0, months: 0 };
  106. }
  107. other = cloneWithOffset(other, base);
  108. if (base.isBefore(other)) {
  109. res = positiveMomentsDifference(base, other);
  110. } else {
  111. res = positiveMomentsDifference(other, base);
  112. res.milliseconds = -res.milliseconds;
  113. res.months = -res.months;
  114. }
  115. return res;
  116. }