dates.tsx 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. import moment from 'moment';
  2. import {parseStatsPeriod} from 'sentry/components/organizations/pageFilters/parse';
  3. import ConfigStore from 'sentry/stores/configStore';
  4. import {DateString} from 'sentry/types';
  5. // TODO(billy): Move to TimeRangeSelector specific utils
  6. export const DEFAULT_DAY_START_TIME = '00:00:00';
  7. export const DEFAULT_DAY_END_TIME = '23:59:59';
  8. const DATE_FORMAT_NO_TIMEZONE = 'YYYY/MM/DD HH:mm:ss';
  9. function getParser(local: boolean = false): typeof moment | typeof moment.utc {
  10. return local ? moment : moment.utc;
  11. }
  12. /**
  13. * Checks if string is valid time. Only accepts 24 hour format.
  14. *
  15. * Chrome's time input will (at least for US locale), allow you to input 12
  16. * hour format with AM/PM but the raw value is in 24 hour.
  17. *
  18. * Safari does not do any validation so you could get a value of > 24 hours
  19. */
  20. export function isValidTime(str: string): boolean {
  21. return moment(str, 'HH:mm', true).isValid();
  22. }
  23. /**
  24. * Given a date object, format in datetime in UTC
  25. * given: Tue Oct 09 2018 00:00:00 GMT-0700 (Pacific Daylight Time)
  26. * returns: "2018-10-09T07:00:00.000"
  27. */
  28. export function getUtcDateString(dateObj: moment.MomentInput): string {
  29. return moment.utc(dateObj).format(moment.HTML5_FMT.DATETIME_LOCAL_SECONDS);
  30. }
  31. export function getFormattedDate(
  32. dateObj: moment.MomentInput,
  33. format: string,
  34. {local}: {local?: boolean} = {}
  35. ): string {
  36. return getParser(local)(dateObj).format(format);
  37. }
  38. /**
  39. * Returns user timezone from their account preferences
  40. */
  41. export function getUserTimezone(): string {
  42. return ConfigStore.get('user')?.options?.timezone;
  43. }
  44. /**
  45. * Given a UTC date, return a Date object in local time
  46. */
  47. export function getUtcToLocalDateObject(date: moment.MomentInput): Date {
  48. return moment.utc(date).local().toDate();
  49. }
  50. /**
  51. * Sets time (hours + minutes) of the current date object
  52. *
  53. * @param {String} timeStr Time in 24hr format (HH:mm)
  54. */
  55. export function setDateToTime(
  56. dateObj: string | Date,
  57. timeStr: string,
  58. {local}: {local?: boolean} = {}
  59. ): Date {
  60. const [hours, minutes, seconds] = timeStr.split(':').map(t => parseInt(t, 10));
  61. const date = new Date(+dateObj);
  62. if (local) {
  63. date.setHours(hours, minutes);
  64. } else {
  65. date.setUTCHours(hours, minutes);
  66. }
  67. if (typeof seconds !== 'undefined') {
  68. date.setSeconds(seconds);
  69. }
  70. return date;
  71. }
  72. /**
  73. * Given a UTC timestamp, return a system date object with the same date
  74. * e.g. given: system is -0700 (PST),
  75. * 1/1/2001 @ 22:00 UTC, return: 1/1/2001 @ 22:00 -0700 (PST)
  76. */
  77. export function getUtcToSystem(dateObj: moment.MomentInput): Date {
  78. // This is required because if your system timezone !== user configured timezone
  79. // then there will be a mismatch of dates with `react-date-picker`
  80. //
  81. // We purposely strip the timezone when formatting from the utc timezone
  82. return new Date(moment.utc(dateObj).format(DATE_FORMAT_NO_TIMEZONE));
  83. }
  84. /**
  85. * Given a timestamp, format to user preference timezone, and strip timezone to
  86. * return a system date object with the same date
  87. *
  88. * e.g. given: system is -0700 (PST) and user preference is -0400 (EST),
  89. * 1/1/2001 @ 22:00 UTC --> 1/1/2001 @ 18:00 -0400 (EST) -->
  90. * return: 1/1/2001 @ 18:00 -0700 (PST)
  91. */
  92. export function getLocalToSystem(dateObj: moment.MomentInput): Date {
  93. // This is required because if your system timezone !== user configured timezone
  94. // then there will be a mismatch of dates with `react-date-picker`
  95. //
  96. // We purposely strip the timezone when formatting from the utc timezone
  97. return new Date(moment(dateObj).format(DATE_FORMAT_NO_TIMEZONE));
  98. }
  99. // Get the beginning of day (e.g. midnight)
  100. export function getStartOfDay(date: moment.MomentInput): Date {
  101. return moment(date)
  102. .startOf('day')
  103. .startOf('hour')
  104. .startOf('minute')
  105. .startOf('second')
  106. .local()
  107. .toDate();
  108. }
  109. // Get tomorrow at midnight so that default endtime
  110. // is inclusive of today
  111. export function getEndOfDay(date: moment.MomentInput): Date {
  112. return moment(date)
  113. .add(1, 'day')
  114. .startOf('hour')
  115. .startOf('minute')
  116. .startOf('second')
  117. .subtract(1, 'second')
  118. .local()
  119. .toDate();
  120. }
  121. export function getPeriodAgo(
  122. period: moment.unitOfTime.DurationConstructor,
  123. unit: number
  124. ): moment.Moment {
  125. return moment().local().subtract(unit, period);
  126. }
  127. // Get the start of the day (midnight) for a period ago
  128. //
  129. // e.g. 2 weeks ago at midnight
  130. export function getStartOfPeriodAgo(
  131. period: moment.unitOfTime.DurationConstructor,
  132. unit: number
  133. ): Date {
  134. return getStartOfDay(getPeriodAgo(period, unit));
  135. }
  136. /**
  137. * Convert an interval string into a number of seconds.
  138. * This allows us to create end timestamps from starting ones
  139. * enabling us to find events in narrow windows.
  140. *
  141. * @param {String} interval The interval to convert.
  142. * @return {Integer}
  143. */
  144. export function intervalToMilliseconds(interval: string): number {
  145. const pattern = /^(\d+)(d|h|m)$/;
  146. const matches = pattern.exec(interval);
  147. if (!matches) {
  148. return 0;
  149. }
  150. const [, value, unit] = matches;
  151. const multipliers = {
  152. d: 60 * 60 * 24,
  153. h: 60 * 60,
  154. m: 60,
  155. };
  156. return parseInt(value, 10) * multipliers[unit] * 1000;
  157. }
  158. /**
  159. * This parses our period shorthand strings (e.g. <int><unit>)
  160. * and converts it into hours
  161. */
  162. export function parsePeriodToHours(str: string): number {
  163. const result = parseStatsPeriod(str);
  164. if (!result) {
  165. return -1;
  166. }
  167. const {period, periodLength} = result;
  168. const periodNumber = parseInt(period, 10);
  169. switch (periodLength) {
  170. case 's':
  171. return periodNumber / (60 * 60);
  172. case 'm':
  173. return periodNumber / 60;
  174. case 'h':
  175. return periodNumber;
  176. case 'd':
  177. return periodNumber * 24;
  178. case 'w':
  179. return periodNumber * 24 * 7;
  180. default:
  181. return -1;
  182. }
  183. }
  184. export function statsPeriodToDays(
  185. statsPeriod?: string | null,
  186. start?: DateString,
  187. end?: DateString
  188. ) {
  189. if (statsPeriod && statsPeriod.endsWith('d')) {
  190. return parseInt(statsPeriod.slice(0, -1), 10);
  191. }
  192. if (statsPeriod && statsPeriod.endsWith('h')) {
  193. return parseInt(statsPeriod.slice(0, -1), 10) / 24;
  194. }
  195. if (start && end) {
  196. return (new Date(end).getTime() - new Date(start).getTime()) / (24 * 60 * 60 * 1000);
  197. }
  198. return 0;
  199. }
  200. export function shouldUse24Hours() {
  201. return ConfigStore.get('user')?.options?.clock24Hours;
  202. }
  203. export function getTimeFormat({displaySeconds = false}: {displaySeconds?: boolean} = {}) {
  204. if (shouldUse24Hours()) {
  205. return displaySeconds ? 'HH:mm:ss' : 'HH:mm';
  206. }
  207. return displaySeconds ? 'LTS' : 'LT';
  208. }
  209. export function getInternalDate(date: string | Date, utc?: boolean | null) {
  210. if (utc) {
  211. return getUtcToSystem(date);
  212. }
  213. return new Date(
  214. moment.tz(moment.utc(date), getUserTimezone()).format('YYYY/MM/DD HH:mm:ss')
  215. );
  216. }
  217. /**
  218. * Strips timezone from local date, creates a new moment date object with timezone
  219. * returns the moment as a Date object
  220. */
  221. export function getDateWithTimezoneInUtc(date?: Date, utc?: boolean | null) {
  222. return moment
  223. .tz(
  224. moment(date).local().format('YYYY-MM-DD HH:mm:ss'),
  225. utc ? 'UTC' : getUserTimezone()
  226. )
  227. .utc()
  228. .toDate();
  229. }