mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-09-29 22:34:33 +00:00
354 lines
8.7 KiB
TypeScript
354 lines
8.7 KiB
TypeScript
import moment from 'moment';
|
|
|
|
import {parseStatsPeriod} from 'sentry/components/organizations/pageFilters/parse';
|
|
import ConfigStore from 'sentry/stores/configStore';
|
|
import type {DateString} from 'sentry/types';
|
|
|
|
// TODO(billy): Move to TimeRangeSelector specific utils
|
|
export const DEFAULT_DAY_START_TIME = '00:00:00';
|
|
export const DEFAULT_DAY_END_TIME = '23:59:59';
|
|
const DATE_FORMAT_NO_TIMEZONE = 'YYYY/MM/DD HH:mm:ss';
|
|
|
|
function getParser(local: boolean = false): typeof moment | typeof moment.utc {
|
|
return local ? moment : moment.utc;
|
|
}
|
|
|
|
/**
|
|
* Checks if string is valid time. Only accepts 24 hour format.
|
|
*
|
|
* Chrome's time input will (at least for US locale), allow you to input 12
|
|
* hour format with AM/PM but the raw value is in 24 hour.
|
|
*
|
|
* Safari does not do any validation so you could get a value of > 24 hours
|
|
*/
|
|
export function isValidTime(str: string): boolean {
|
|
return moment(str, 'HH:mm', true).isValid();
|
|
}
|
|
|
|
/**
|
|
* Given a date object, format in datetime in UTC
|
|
* given: Tue Oct 09 2018 00:00:00 GMT-0700 (Pacific Daylight Time)
|
|
* returns: "2018-10-09T07:00:00.000"
|
|
*/
|
|
export function getUtcDateString(dateObj: moment.MomentInput): string {
|
|
return moment.utc(dateObj).format(moment.HTML5_FMT.DATETIME_LOCAL_SECONDS);
|
|
}
|
|
|
|
export function getFormattedDate(
|
|
dateObj: moment.MomentInput,
|
|
format: string,
|
|
{local}: {local?: boolean} = {}
|
|
): string {
|
|
return getParser(local)(dateObj).format(format);
|
|
}
|
|
|
|
/**
|
|
* Returns user timezone from their account preferences
|
|
*/
|
|
export function getUserTimezone(): string {
|
|
return ConfigStore.get('user')?.options?.timezone;
|
|
}
|
|
|
|
/**
|
|
* Given a UTC date, return a Date object in local time
|
|
*/
|
|
export function getUtcToLocalDateObject(date: moment.MomentInput): Date {
|
|
return moment.utc(date).local().toDate();
|
|
}
|
|
|
|
/**
|
|
* Sets time (hours + minutes) of the current date object
|
|
*
|
|
* @param timeStr Time in 24hr format (HH:mm)
|
|
*/
|
|
export function setDateToTime(
|
|
dateObj: string | Date,
|
|
timeStr: string,
|
|
{local}: {local?: boolean} = {}
|
|
): Date {
|
|
const [hours, minutes, seconds] = timeStr.split(':').map(t => parseInt(t, 10));
|
|
|
|
const date = new Date(+dateObj);
|
|
|
|
if (local) {
|
|
date.setHours(hours, minutes);
|
|
} else {
|
|
date.setUTCHours(hours, minutes);
|
|
}
|
|
|
|
if (typeof seconds !== 'undefined') {
|
|
date.setSeconds(seconds);
|
|
}
|
|
|
|
return date;
|
|
}
|
|
|
|
/**
|
|
* Given a UTC timestamp, return a system date object with the same date
|
|
* e.g. given: system is -0700 (PST),
|
|
* 1/1/2001 @ 22:00 UTC, return: 1/1/2001 @ 22:00 -0700 (PST)
|
|
*/
|
|
export function getUtcToSystem(dateObj: moment.MomentInput): Date {
|
|
// This is required because if your system timezone !== user configured timezone
|
|
// then there will be a mismatch of dates with `react-date-picker`
|
|
//
|
|
// We purposely strip the timezone when formatting from the utc timezone
|
|
return new Date(moment.utc(dateObj).format(DATE_FORMAT_NO_TIMEZONE));
|
|
}
|
|
|
|
/**
|
|
* Given a timestamp, format to user preference timezone, and strip timezone to
|
|
* return a system date object with the same date
|
|
*
|
|
* e.g. given: system is -0700 (PST) and user preference is -0400 (EST),
|
|
* 1/1/2001 @ 22:00 UTC --> 1/1/2001 @ 18:00 -0400 (EST) -->
|
|
* return: 1/1/2001 @ 18:00 -0700 (PST)
|
|
*/
|
|
export function getLocalToSystem(dateObj: moment.MomentInput): Date {
|
|
// This is required because if your system timezone !== user configured timezone
|
|
// then there will be a mismatch of dates with `react-date-picker`
|
|
//
|
|
// We purposely strip the timezone when formatting from the utc timezone
|
|
return new Date(moment(dateObj).format(DATE_FORMAT_NO_TIMEZONE));
|
|
}
|
|
|
|
/**
|
|
* Get the beginning of day (e.g. midnight)
|
|
*/
|
|
export function getStartOfDay(date: moment.MomentInput): Date {
|
|
return moment(date)
|
|
.startOf('day')
|
|
.startOf('hour')
|
|
.startOf('minute')
|
|
.startOf('second')
|
|
.local()
|
|
.toDate();
|
|
}
|
|
|
|
/**
|
|
* Get tomorrow at midnight so that default endtime is inclusive of today
|
|
*/
|
|
export function getEndOfDay(date: moment.MomentInput): Date {
|
|
return moment(date)
|
|
.add(1, 'day')
|
|
.startOf('hour')
|
|
.startOf('minute')
|
|
.startOf('second')
|
|
.subtract(1, 'second')
|
|
.local()
|
|
.toDate();
|
|
}
|
|
|
|
export function getPeriodAgo(
|
|
period: moment.unitOfTime.DurationConstructor,
|
|
unit: number
|
|
): moment.Moment {
|
|
return moment().local().subtract(unit, period);
|
|
}
|
|
|
|
/**
|
|
* Get the start of the day (midnight) for a period ago
|
|
*
|
|
* e.g. 2 weeks ago at midnight
|
|
*/
|
|
export function getStartOfPeriodAgo(
|
|
period: moment.unitOfTime.DurationConstructor,
|
|
unit: number
|
|
): Date {
|
|
return getStartOfDay(getPeriodAgo(period, unit));
|
|
}
|
|
|
|
/**
|
|
* Convert an interval string into a number of seconds.
|
|
* This allows us to create end timestamps from starting ones
|
|
* enabling us to find events in narrow windows.
|
|
*
|
|
* @param {String} interval The interval to convert.
|
|
* @return {Integer}
|
|
*/
|
|
export function intervalToMilliseconds(interval: string): number {
|
|
const pattern = /^(\d+)(w|d|h|m)$/;
|
|
const matches = pattern.exec(interval);
|
|
if (!matches) {
|
|
return 0;
|
|
}
|
|
const [, value, unit] = matches;
|
|
const multipliers = {
|
|
w: 60 * 60 * 24 * 7,
|
|
d: 60 * 60 * 24,
|
|
h: 60 * 60,
|
|
m: 60,
|
|
};
|
|
return parseInt(value, 10) * multipliers[unit] * 1000;
|
|
}
|
|
|
|
/**
|
|
* This parses our period shorthand strings (e.g. <int><unit>)
|
|
* and converts it into hours
|
|
*/
|
|
export function parsePeriodToHours(str: string): number {
|
|
const result = parseStatsPeriod(str);
|
|
|
|
if (!result) {
|
|
return -1;
|
|
}
|
|
|
|
const {period, periodLength} = result;
|
|
|
|
const periodNumber = parseInt(period, 10);
|
|
|
|
switch (periodLength) {
|
|
case 's':
|
|
return periodNumber / (60 * 60);
|
|
case 'm':
|
|
return periodNumber / 60;
|
|
case 'h':
|
|
return periodNumber;
|
|
case 'd':
|
|
return periodNumber * 24;
|
|
case 'w':
|
|
return periodNumber * 24 * 7;
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
export function statsPeriodToDays(
|
|
statsPeriod?: string | null,
|
|
start?: DateString,
|
|
end?: DateString
|
|
) {
|
|
if (statsPeriod?.endsWith('d')) {
|
|
return parseInt(statsPeriod.slice(0, -1), 10);
|
|
}
|
|
if (statsPeriod?.endsWith('h')) {
|
|
return parseInt(statsPeriod.slice(0, -1), 10) / 24;
|
|
}
|
|
if (start && end) {
|
|
return (new Date(end).getTime() - new Date(start).getTime()) / (24 * 60 * 60 * 1000);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Does the user prefer a 24 hour clock?
|
|
*/
|
|
export function shouldUse24Hours() {
|
|
return ConfigStore.get('user')?.options?.clock24Hours;
|
|
}
|
|
|
|
/**
|
|
* Get a common date format
|
|
*/
|
|
export function getDateFormat({year}: {year?: boolean}) {
|
|
// "Jan 1, 2022" or "Jan 1"
|
|
return year ? 'MMM D, YYYY' : 'MMM D';
|
|
}
|
|
|
|
/**
|
|
* Get a common time format
|
|
*/
|
|
export function getTimeFormat({
|
|
clock24Hours,
|
|
seconds,
|
|
timeZone,
|
|
}: {
|
|
clock24Hours?: boolean;
|
|
seconds?: boolean;
|
|
timeZone?: boolean;
|
|
} = {}) {
|
|
let format = '';
|
|
|
|
if (clock24Hours ?? shouldUse24Hours()) {
|
|
format = seconds ? 'HH:mm:ss' : 'HH:mm';
|
|
} else {
|
|
format = seconds ? 'LTS' : 'LT';
|
|
}
|
|
|
|
if (timeZone) {
|
|
format += ' z';
|
|
}
|
|
|
|
return format;
|
|
}
|
|
|
|
interface FormatProps {
|
|
/**
|
|
* Should show a 24hour clock? If not set the users preference will be used
|
|
*/
|
|
clock24Hours?: boolean;
|
|
/**
|
|
* If true, will only return the date part, e.g. "Jan 1".
|
|
*/
|
|
dateOnly?: boolean;
|
|
/**
|
|
* Whether to show the seconds.
|
|
*/
|
|
seconds?: boolean;
|
|
/**
|
|
* If true, will only return the time part, e.g. "2:50 PM"
|
|
*/
|
|
timeOnly?: boolean;
|
|
/**
|
|
* Whether to show the time zone.
|
|
*/
|
|
timeZone?: boolean;
|
|
/**
|
|
* Whether to show the year. If not specified, the returned date string will
|
|
* not contain the year _if_ the date is not in the current calendar year.
|
|
* For example: "Feb 1" (2022), "Jan 1" (2022), "Dec 31, 2021".
|
|
*/
|
|
year?: boolean;
|
|
}
|
|
|
|
export function getFormat({
|
|
dateOnly,
|
|
timeOnly,
|
|
year,
|
|
seconds,
|
|
timeZone,
|
|
clock24Hours,
|
|
}: FormatProps = {}) {
|
|
if (dateOnly) {
|
|
return getDateFormat({year});
|
|
}
|
|
|
|
if (timeOnly) {
|
|
return getTimeFormat({clock24Hours, seconds, timeZone});
|
|
}
|
|
|
|
const dateFormat = getDateFormat({year});
|
|
const timeFormat = getTimeFormat({
|
|
clock24Hours,
|
|
seconds,
|
|
timeZone,
|
|
});
|
|
|
|
// If the year is shown, then there's already a comma in dateFormat ("Jan 1, 2020"),
|
|
// so we don't need to add another comma between the date and time
|
|
return year ? `${dateFormat} ${timeFormat}` : `${dateFormat}, ${timeFormat}`;
|
|
}
|
|
|
|
export function getInternalDate(date: string | Date, utc?: boolean | null) {
|
|
if (utc) {
|
|
return getUtcToSystem(date);
|
|
}
|
|
return new Date(
|
|
moment.tz(moment.utc(date), getUserTimezone()).format('YYYY/MM/DD HH:mm:ss')
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Strips timezone from local date, creates a new moment date object with timezone
|
|
* returns the moment as a Date object
|
|
*/
|
|
export function getDateWithTimezoneInUtc(date?: Date, utc?: boolean | null) {
|
|
return moment
|
|
.tz(
|
|
moment(date).local().format('YYYY-MM-DD HH:mm:ss'),
|
|
utc ? 'UTC' : getUserTimezone()
|
|
)
|
|
.utc()
|
|
.toDate();
|
|
}
|