time.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. Object.defineProperty(exports, '__esModule', { value: true });
  2. const worldwide = require('./worldwide.js');
  3. const ONE_SECOND_IN_MS = 1000;
  4. /**
  5. * A partial definition of the [Performance Web API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Performance}
  6. * for accessing a high-resolution monotonic clock.
  7. */
  8. /**
  9. * Returns a timestamp in seconds since the UNIX epoch using the Date API.
  10. *
  11. * TODO(v8): Return type should be rounded.
  12. */
  13. function dateTimestampInSeconds() {
  14. return Date.now() / ONE_SECOND_IN_MS;
  15. }
  16. /**
  17. * Returns a wrapper around the native Performance API browser implementation, or undefined for browsers that do not
  18. * support the API.
  19. *
  20. * Wrapping the native API works around differences in behavior from different browsers.
  21. */
  22. function createUnixTimestampInSecondsFunc() {
  23. const { performance } = worldwide.GLOBAL_OBJ ;
  24. if (!performance || !performance.now) {
  25. return dateTimestampInSeconds;
  26. }
  27. // Some browser and environments don't have a timeOrigin, so we fallback to
  28. // using Date.now() to compute the starting time.
  29. const approxStartingTimeOrigin = Date.now() - performance.now();
  30. const timeOrigin = performance.timeOrigin == undefined ? approxStartingTimeOrigin : performance.timeOrigin;
  31. // performance.now() is a monotonic clock, which means it starts at 0 when the process begins. To get the current
  32. // wall clock time (actual UNIX timestamp), we need to add the starting time origin and the current time elapsed.
  33. //
  34. // TODO: This does not account for the case where the monotonic clock that powers performance.now() drifts from the
  35. // wall clock time, which causes the returned timestamp to be inaccurate. We should investigate how to detect and
  36. // correct for this.
  37. // See: https://github.com/getsentry/sentry-javascript/issues/2590
  38. // See: https://github.com/mdn/content/issues/4713
  39. // See: https://dev.to/noamr/when-a-millisecond-is-not-a-millisecond-3h6
  40. return () => {
  41. return (timeOrigin + performance.now()) / ONE_SECOND_IN_MS;
  42. };
  43. }
  44. /**
  45. * Returns a timestamp in seconds since the UNIX epoch using either the Performance or Date APIs, depending on the
  46. * availability of the Performance API.
  47. *
  48. * BUG: Note that because of how browsers implement the Performance API, the clock might stop when the computer is
  49. * asleep. This creates a skew between `dateTimestampInSeconds` and `timestampInSeconds`. The
  50. * skew can grow to arbitrary amounts like days, weeks or months.
  51. * See https://github.com/getsentry/sentry-javascript/issues/2590.
  52. */
  53. const timestampInSeconds = createUnixTimestampInSecondsFunc();
  54. /**
  55. * Re-exported with an old name for backwards-compatibility.
  56. * TODO (v8): Remove this
  57. *
  58. * @deprecated Use `timestampInSeconds` instead.
  59. */
  60. const timestampWithMs = timestampInSeconds;
  61. /**
  62. * Internal helper to store what is the source of browserPerformanceTimeOrigin below. For debugging only.
  63. */
  64. exports._browserPerformanceTimeOriginMode = void 0;
  65. /**
  66. * The number of milliseconds since the UNIX epoch. This value is only usable in a browser, and only when the
  67. * performance API is available.
  68. */
  69. const browserPerformanceTimeOrigin = (() => {
  70. // Unfortunately browsers may report an inaccurate time origin data, through either performance.timeOrigin or
  71. // performance.timing.navigationStart, which results in poor results in performance data. We only treat time origin
  72. // data as reliable if they are within a reasonable threshold of the current time.
  73. const { performance } = worldwide.GLOBAL_OBJ ;
  74. if (!performance || !performance.now) {
  75. exports._browserPerformanceTimeOriginMode = 'none';
  76. return undefined;
  77. }
  78. const threshold = 3600 * 1000;
  79. const performanceNow = performance.now();
  80. const dateNow = Date.now();
  81. // if timeOrigin isn't available set delta to threshold so it isn't used
  82. const timeOriginDelta = performance.timeOrigin
  83. ? Math.abs(performance.timeOrigin + performanceNow - dateNow)
  84. : threshold;
  85. const timeOriginIsReliable = timeOriginDelta < threshold;
  86. // While performance.timing.navigationStart is deprecated in favor of performance.timeOrigin, performance.timeOrigin
  87. // is not as widely supported. Namely, performance.timeOrigin is undefined in Safari as of writing.
  88. // Also as of writing, performance.timing is not available in Web Workers in mainstream browsers, so it is not always
  89. // a valid fallback. In the absence of an initial time provided by the browser, fallback to the current time from the
  90. // Date API.
  91. // eslint-disable-next-line deprecation/deprecation
  92. const navigationStart = performance.timing && performance.timing.navigationStart;
  93. const hasNavigationStart = typeof navigationStart === 'number';
  94. // if navigationStart isn't available set delta to threshold so it isn't used
  95. const navigationStartDelta = hasNavigationStart ? Math.abs(navigationStart + performanceNow - dateNow) : threshold;
  96. const navigationStartIsReliable = navigationStartDelta < threshold;
  97. if (timeOriginIsReliable || navigationStartIsReliable) {
  98. // Use the more reliable time origin
  99. if (timeOriginDelta <= navigationStartDelta) {
  100. exports._browserPerformanceTimeOriginMode = 'timeOrigin';
  101. return performance.timeOrigin;
  102. } else {
  103. exports._browserPerformanceTimeOriginMode = 'navigationStart';
  104. return navigationStart;
  105. }
  106. }
  107. // Either both timeOrigin and navigationStart are skewed or neither is available, fallback to Date.
  108. exports._browserPerformanceTimeOriginMode = 'dateNow';
  109. return dateNow;
  110. })();
  111. exports.browserPerformanceTimeOrigin = browserPerformanceTimeOrigin;
  112. exports.dateTimestampInSeconds = dateTimestampInSeconds;
  113. exports.timestampInSeconds = timestampInSeconds;
  114. exports.timestampWithMs = timestampWithMs;
  115. //# sourceMappingURL=time.js.map