feat: Centralize and Standardize Date/Time Format Handling (#6925)

* feat: change the format of uplot x axis to 24 hours

* feat: centralize date/time formats

* refactor: use the centralized 24 hour date/time formatting across components

* refactor: centralize uPlot x-axis values formatting

* feat: make the x axis of alert history in 24 hour format
This commit is contained in:
Shaheer Kochai 2025-01-27 16:28:54 +04:30 committed by GitHub
parent 6dc7a76853
commit 8d6731c7ba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
46 changed files with 260 additions and 84 deletions

View File

@ -113,16 +113,17 @@ function CustomTimePicker({
selectedTimeValue: string,
): string => {
if (selectedTime === 'custom') {
// Convert the date range string to 12-hour format
const dates = selectedTimeValue.split(' - ');
if (dates.length === 2) {
const startDate = dayjs(dates[0], 'DD/MM/YYYY HH:mm');
const endDate = dayjs(dates[1], 'DD/MM/YYYY HH:mm');
// TODO(shaheer): if the user preference is 12 hour format, then convert the date range string to 12-hour format (pick this up while working on 12/24 hour preference feature)
// // Convert the date range string to 12-hour format
// const dates = selectedTimeValue.split(' - ');
// if (dates.length === 2) {
// const startDate = dayjs(dates[0], DATE_TIME_FORMATS.UK_DATETIME);
// const endDate = dayjs(dates[1], DATE_TIME_FORMATS.UK_DATETIME);
return `${startDate.format('DD/MM/YYYY hh:mm A')} - ${endDate.format(
'DD/MM/YYYY hh:mm A',
)}`;
}
// return `${startDate.format(DATE_TIME_FORMATS.UK_DATETIME)} - ${endDate.format(
// DATE_TIME_FORMATS.UK_DATETIME,
// )}`;
// }
return selectedTimeValue;
}

View File

@ -1,6 +1,7 @@
import './RangePickerModal.styles.scss';
import { DatePicker } from 'antd';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { DateTimeRangeType } from 'container/TopNav/CustomDateTimeModal';
import { LexicalContext } from 'container/TopNav/DateTimeSelectionV2/config';
import dayjs, { Dayjs } from 'dayjs';
@ -68,12 +69,9 @@ function RangePickerModal(props: RangePickerModalProps): JSX.Element {
<RangePicker
disabledDate={disabledDate}
allowClear
showTime={{
use12Hours: true,
format: 'hh:mm A',
}}
showTime
format={(date: Dayjs): string =>
date.tz(timezone.value).format('YYYY-MM-DD hh:mm A')
date.tz(timezone.value).format(DATE_TIME_FORMATS.ISO_DATETIME)
}
onOk={onModalOkHandler}
// eslint-disable-next-line react/jsx-props-no-spreading

View File

@ -18,6 +18,7 @@ import {
Tooltip,
} from 'chart.js';
import annotationPlugin from 'chartjs-plugin-annotation';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { generateGridTitle } from 'container/GridPanelSwitch/utils';
import dayjs from 'dayjs';
import { useIsDarkMode } from 'hooks/useDarkMode';
@ -67,13 +68,13 @@ Tooltip.positioners.custom = TooltipPositionHandler;
// Map of Chart.js time formats to dayjs format strings
const formatMap = {
'HH:mm:ss': 'HH:mm:ss',
'HH:mm': 'HH:mm',
'MM/DD HH:mm': 'MM/DD HH:mm',
'MM/dd HH:mm': 'MM/DD HH:mm',
'MM/DD': 'MM/DD',
'YY-MM': 'YY-MM',
YY: 'YY',
'HH:mm:ss': DATE_TIME_FORMATS.TIME_SECONDS,
'HH:mm': DATE_TIME_FORMATS.TIME,
'MM/DD HH:mm': DATE_TIME_FORMATS.SLASH_SHORT,
'MM/dd HH:mm': DATE_TIME_FORMATS.SLASH_SHORT,
'MM/DD': DATE_TIME_FORMATS.DATE_SHORT,
'YY-MM': DATE_TIME_FORMATS.YEAR_MONTH,
YY: DATE_TIME_FORMATS.YEAR_SHORT,
};
const Graph = forwardRef<ToggleGraphProps | undefined, GraphProps>(
@ -136,7 +137,7 @@ const Graph = forwardRef<ToggleGraphProps | undefined, GraphProps>(
const format = formatMap[fmt as keyof typeof formatMap];
if (!format) {
console.warn(`Missing datetime format for ${fmt}`);
return dayjsTime.format('YYYY-MM-DD HH:mm:ss'); // fallback format
return dayjsTime.format(DATE_TIME_FORMATS.ISO_DATETIME_SECONDS); // fallback format
}
return dayjsTime.format(format);

View File

@ -1,6 +1,7 @@
import { Chart, ChartConfiguration, ChartData, Color } from 'chart.js';
import * as chartjsAdapter from 'chartjs-adapter-date-fns';
import { Timezone } from 'components/CustomTimePicker/timezoneUtils';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import dayjs from 'dayjs';
import { MutableRefObject } from 'react';
@ -99,7 +100,9 @@ export const getGraphOptions = (
callbacks: {
title(context): string | string[] {
const date = dayjs(context[0].parsed.x);
return date.tz(timezone.value).format('MMM DD, YYYY, HH:mm:ss');
return date
.tz(timezone.value)
.format(DATE_TIME_FORMATS.MONTH_DATETIME_FULL_SECONDS);
},
label(context): string | string[] {
let label = context.dataset.label || '';
@ -154,14 +157,14 @@ export const getGraphOptions = (
unit: xAxisTimeUnit?.unitName || 'minute',
stepSize: xAxisTimeUnit?.stepSize || 1,
displayFormats: {
millisecond: 'HH:mm:ss',
second: 'HH:mm:ss',
minute: 'HH:mm',
hour: 'MM/dd HH:mm',
day: 'MM/dd',
week: 'MM/dd',
month: 'yy-MM',
year: 'yy',
millisecond: DATE_TIME_FORMATS.TIME_SECONDS,
second: DATE_TIME_FORMATS.TIME_SECONDS,
minute: DATE_TIME_FORMATS.TIME,
hour: DATE_TIME_FORMATS.SLASH_SHORT,
day: DATE_TIME_FORMATS.DATE_SHORT,
week: DATE_TIME_FORMATS.DATE_SHORT,
month: DATE_TIME_FORMATS.YEAR_MONTH,
year: DATE_TIME_FORMATS.YEAR_SHORT,
},
},
type: 'time',

View File

@ -1,5 +1,6 @@
import { Tag, Typography } from 'antd';
import { ColumnsType } from 'antd/es/table';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { getMs } from 'container/Trace/Filters/Panel/PanelBody/Duration/util';
import {
BlockLink,
@ -33,8 +34,8 @@ export const getListColumns = (
if (key === 'timestamp') {
const date =
typeof value === 'string'
? dayjs(value).format('YYYY-MM-DD HH:mm:ss.SSS')
: dayjs(value / 1e6).format('YYYY-MM-DD HH:mm:ss.SSS');
? dayjs(value).format(DATE_TIME_FORMATS.ISO_DATETIME_MS)
: dayjs(value / 1e6).format(DATE_TIME_FORMATS.ISO_DATETIME_MS);
return (
<BlockLink to={getTraceLink(item)} openInNewTab>

View File

@ -6,6 +6,7 @@ import { Typography } from 'antd';
import cx from 'classnames';
import LogDetail from 'components/LogDetail';
import { VIEW_TYPES } from 'components/LogDetail/constants';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { unescapeString } from 'container/LogDetailedView/utils';
import { FontSize } from 'container/OptionsMenu/types';
import dompurify from 'dompurify';
@ -181,11 +182,11 @@ function ListLogView({
typeof flattenLogData.timestamp === 'string'
? formatTimezoneAdjustedTimestamp(
flattenLogData.timestamp,
'YYYY-MM-DD HH:mm:ss.SSS',
DATE_TIME_FORMATS.ISO_DATETIME_MS,
)
: formatTimezoneAdjustedTimestamp(
flattenLogData.timestamp / 1e6,
'YYYY-MM-DD HH:mm:ss.SSS',
DATE_TIME_FORMATS.ISO_DATETIME_MS,
),
[flattenLogData.timestamp, formatTimezoneAdjustedTimestamp],
);

View File

@ -4,6 +4,7 @@ import Convert from 'ansi-to-html';
import { DrawerProps } from 'antd';
import LogDetail from 'components/LogDetail';
import { VIEW_TYPES, VIEWS } from 'components/LogDetail/constants';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { unescapeString } from 'container/LogDetailedView/utils';
import LogsExplorerContext from 'container/LogsExplorerContext';
import dompurify from 'dompurify';
@ -94,10 +95,13 @@ function RawLogView({
const text = useMemo(() => {
const date =
typeof data.timestamp === 'string'
? formatTimezoneAdjustedTimestamp(data.timestamp, 'YYYY-MM-DD HH:mm:ss.SSS')
? formatTimezoneAdjustedTimestamp(
data.timestamp,
DATE_TIME_FORMATS.ISO_DATETIME_MS,
)
: formatTimezoneAdjustedTimestamp(
data.timestamp / 1e6,
'YYYY-MM-DD HH:mm:ss.SSS',
DATE_TIME_FORMATS.ISO_DATETIME_MS,
);
return `${date} | ${attributesText} ${data.body}`;

View File

@ -4,6 +4,7 @@ import Convert from 'ansi-to-html';
import { Typography } from 'antd';
import { ColumnsType } from 'antd/es/table';
import cx from 'classnames';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { unescapeString } from 'container/LogDetailedView/utils';
import dompurify from 'dompurify';
import { useIsDarkMode } from 'hooks/useDarkMode';
@ -99,10 +100,13 @@ export const useTableView = (props: UseTableViewProps): UseTableViewResult => {
render: (field): ColumnTypeRender<Record<string, unknown>> => {
const date =
typeof field === 'string'
? formatTimezoneAdjustedTimestamp(field, 'YYYY-MM-DD HH:mm:ss.SSS')
? formatTimezoneAdjustedTimestamp(
field,
DATE_TIME_FORMATS.ISO_DATETIME_MS,
)
: formatTimezoneAdjustedTimestamp(
field / 1e6,
'YYYY-MM-DD HH:mm:ss.SSS',
DATE_TIME_FORMATS.ISO_DATETIME_MS,
);
return {
children: (

View File

@ -1,4 +1,5 @@
import { Typography } from 'antd';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { useTimezone } from 'providers/Timezone';
function Time({ CreatedOrUpdateTime }: DateProps): JSX.Element {
@ -6,7 +7,7 @@ function Time({ CreatedOrUpdateTime }: DateProps): JSX.Element {
const time = new Date(CreatedOrUpdateTime);
const timeString = formatTimezoneAdjustedTimestamp(
time,
'MM/DD/YYYY hh:mm:ss A (UTC Z)',
DATE_TIME_FORMATS.UTC_US,
);
return <Typography>{timeString}</Typography>;
}

View File

@ -0,0 +1,68 @@
export const DATE_TIME_FORMATS = {
// ISO formats (YYYY-MM-DD)
ISO_DATETIME: 'YYYY-MM-DD HH:mm',
ISO_DATETIME_SECONDS: 'YYYY-MM-DD HH:mm:ss',
ISO_DATETIME_MS: 'YYYY-MM-DD HH:mm:ss.SSS',
ISO_DATETIME_UTC: 'YYYY-MM-DD HH:mm:ss (UTC Z)',
// Standard regional formats
US_DATE: 'MM/DD/YYYY',
UK_DATETIME: 'DD/MM/YYYY HH:mm',
UK_DATETIME_SECONDS: 'DD/MM/YYYY HH:mm:ss',
// US_DATE: 'MM/DD/YYYY',
US_DATETIME: 'MM/DD/YYYY, HH:mm',
US_DATETIME_SECONDS: 'MM/DD/YYYY, HH:mm:ss',
// Slash formats
SLASH_DATETIME: 'YYYY/MM/DD HH:mm',
SLASH_DATETIME_SECONDS: 'YYYY/MM/DD HH:mm:ss',
SLASH_SHORT: 'MM/DD HH:mm',
// Time only formats
TIME: 'HH:mm',
TIME_SECONDS: 'HH:mm:ss',
TIME_UTC: 'HH:mm:ss (UTC Z)',
TIME_UTC_MS: 'HH:mm:ss.SSS (UTC Z)',
// Short date formats
DATE_SHORT: 'MM/DD',
YEAR_SHORT: 'YY',
YEAR_MONTH: 'YY-MM',
// Month name formats
MONTH_DATE_FULL: 'MMMM DD, YYYY',
MONTH_DATE_SHORT: 'DD MMM YYYY',
MONTH_DATETIME_SHORT: 'DD MMM YYYY HH:mm',
MONTH_YEAR: 'MMM DD YYYY',
MONTH_DATETIME: 'MMM DD, YYYY, HH:mm',
MONTH_DATETIME_SECONDS: 'MMM DD YYYY HH:mm:ss',
MONTH_DATETIME_FULL: 'MMMM DD, YYYY HH:mm',
MONTH_DATETIME_FULL_SECONDS: 'MMM DD, YYYY, HH:mm:ss',
// Ordinal formats (1st, 2nd, 3rd, etc)
ORDINAL_DATE: 'Do MMM YYYY',
ORDINAL_ONLY: 'Do',
ORDINAL_DATETIME: 'Do MMMM, YYYY ⎯ HH:mm:ss',
// UTC specific formats
UTC_FULL: 'DD/MM/YYYY HH:mm:ss (UTC Z)',
UTC_US: 'MM/DD/YYYY HH:mm:ss (UTC Z)',
UTC_US_MS: 'MM/DD/YYYY, HH:mm:ss.SSS (UTC Z)',
UTC_MONTH_FULL: 'MMMM DD, YYYY HH:mm (UTC Z)',
UTC_MONTH_SHORT: 'MMM DD HH:mm:ss.SSS (UTC Z)',
UTC_MONTH_COMPACT: 'MMM DD,YYYY, HH:mm (UTC Z)',
UTC_TIME_DATE: 'HH:mm:ss (UTC Z) MM/DD',
// Formats with dash separator
DASH_DATETIME: 'MMM D, YYYY ⎯ HH:mm:ss',
DASH_DATETIME_UTC: 'MMM D, YYYY ⎯ HH:mm:ss (UTC Z)',
DASH_TIME_DATE: 'HH:mm:ss ⎯ MMM D, YYYY (UTC Z)',
} as const;
export const convert24hTo12h = (format: string): string =>
format
.replace(/\bHH:mm:ss\.SSS\b/g, 'hh:mm:ss.SSS A')
.replace(/\bHH:mm:ss\b/g, 'hh:mm:ss A')
.replace(/\bHH:mm\b/g, 'hh:mm A')
.replace(/\bh:mm:ss\b/g, 'h:mm:ss A');

View File

@ -7,6 +7,7 @@ import useUrlQuery from 'hooks/useUrlQuery';
import history from 'lib/history';
import heatmapPlugin from 'lib/uPlotLib/plugins/heatmapPlugin';
import timelinePlugin from 'lib/uPlotLib/plugins/timelinePlugin';
import { uPlotXAxisValuesFormat } from 'lib/uPlotLib/utils/constants';
import { useTimezone } from 'providers/Timezone';
import { useMemo, useRef } from 'react';
import { useDispatch } from 'react-redux';
@ -60,6 +61,7 @@ function HorizontalTimelineGraph({
{
gap: 10,
stroke: isDarkMode ? Color.BG_VANILLA_400 : Color.BG_INK_400,
values: uPlotXAxisValuesFormat,
},
{ show: false },
],

View File

@ -5,6 +5,7 @@ import { ColumnsType } from 'antd/es/table';
import ClientSideQBSearch, {
AttributeKey,
} from 'components/ClientSideQBSearch/ClientSideQBSearch';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { ConditionalAlertPopover } from 'container/AlertHistory/AlertPopover/AlertPopover';
import { transformKeyValuesToAttributeValuesMap } from 'container/QueryBuilder/filters/utils';
import { useIsDarkMode } from 'hooks/useDarkMode';
@ -112,7 +113,7 @@ export const timelineTableColumns = ({
width: 200,
render: (value): JSX.Element => (
<div className="alert-rule__created-at">
{formatTimezoneAdjustedTimestamp(value, 'MMM D, YYYY ⎯ HH:mm:ss')}
{formatTimezoneAdjustedTimestamp(value, DATE_TIME_FORMATS.DASH_DATETIME)}
</div>
),
},

View File

@ -16,6 +16,7 @@ import logEvent from 'api/common/logEvent';
import getAll from 'api/errors/getAll';
import getErrorCounts from 'api/errors/getErrorCounts';
import { ResizeTable } from 'components/ResizeTable';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import ROUTES from 'constants/routes';
import { useNotifications } from 'hooks/useNotifications';
import useResourceAttribute from 'hooks/useResourceAttribute';
@ -164,7 +165,10 @@ function AllErrors(): JSX.Element {
) => string,
): JSX.Element => (
<Typography>
{formatTimezoneAdjustedTimestamp(value, 'DD/MM/YYYY hh:mm:ss A')}
{formatTimezoneAdjustedTimestamp(
value,
DATE_TIME_FORMATS.UK_DATETIME_SECONDS,
)}
</Typography>
);

View File

@ -1,3 +1,4 @@
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { themeColors } from 'constants/theme';
import dayjs from 'dayjs';
import { generateColor } from 'lib/uPlotLib/utils/generateColor';
@ -19,7 +20,9 @@ const tooltipPlugin = (
return value.toFixed(3);
}
if (value instanceof Date) {
return dayjs(value).tz(timezone).format('MM/DD/YYYY, h:mm:ss A');
return dayjs(value)
.tz(timezone)
.format(DATE_TIME_FORMATS.US_DATETIME_SECONDS);
}
if (value == null) {
return 'N/A';

View File

@ -1,3 +1,4 @@
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import dayjs from 'dayjs';
export interface QuantityData {
@ -36,7 +37,7 @@ interface CsvData {
}
const formatDate = (timestamp: number): string =>
dayjs.unix(timestamp).format('MM/DD/YYYY');
dayjs.unix(timestamp).format(DATE_TIME_FORMATS.US_DATE);
const getQuantityData = (
data: QuantityData[],

View File

@ -1,4 +1,5 @@
import { UsageResponsePayloadProps } from 'api/billing/getUsage';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import dayjs from 'dayjs';
import { getUPlotChartData } from 'lib/uPlotLib/utils/getUplotChartData';
import { isEmpty, isNull } from 'lodash-es';
@ -98,7 +99,7 @@ export function fillMissingValuesForQuantities(
}
const formatDate = (timestamp: number): string =>
dayjs.unix(timestamp).format('MM/DD/YYYY');
dayjs.unix(timestamp).format(DATE_TIME_FORMATS.US_DATE);
export function csvFileName(csvData: QuantityData[]): string {
if (!csvData.length) {

View File

@ -5,6 +5,7 @@ import logEvent from 'api/common/logEvent';
import getNextPrevId from 'api/errors/getNextPrevId';
import Editor from 'components/Editor';
import { ResizeTable } from 'components/ResizeTable';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { getNanoSeconds } from 'container/AllError/utils';
import { useNotifications } from 'hooks/useNotifications';
import createQueryParams from 'lib/createQueryParams';
@ -148,7 +149,7 @@ function ErrorDetails(props: ErrorDetailsProps): JSX.Element {
<Typography>
{formatTimezoneAdjustedTimestamp(
errorDetail.timestamp,
'DD/MM/YYYY hh:mm:ss A (UTC Z)',
DATE_TIME_FORMATS.UTC_FULL,
)}
</Typography>
</div>

View File

@ -1,6 +1,7 @@
import '../GantChart.styles.scss';
import { Popover, Typography } from 'antd';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { convertTimeToRelevantUnit } from 'container/TraceDetail/utils';
import dayjs from 'dayjs';
import { useIsDarkMode } from 'hooks/useDarkMode';
@ -43,7 +44,7 @@ function Span(props: SpanLengthProps): JSX.Element {
const getContent = (): JSX.Element => {
const timeStamp = dayjs(startTime)
.tz(timezone.value)
.format('h:mm:ss:SSS A (UTC Z)');
.format(DATE_TIME_FORMATS.TIME_UTC_MS);
const startTimeInMs = startTime - globalStart;
return (
<div>

View File

@ -31,6 +31,7 @@ import { AxiosError } from 'axios';
import { getYAxisFormattedValue } from 'components/Graph/yAxisConfig';
import Tags from 'components/Tags/Tags';
import { SOMETHING_WENT_WRONG } from 'constants/api';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import dayjs from 'dayjs';
import { useGetAllIngestionsKeys } from 'hooks/IngestionKeys/useGetAllIngestionKeys';
import useDebouncedFn from 'hooks/useDebouncedFunction';
@ -437,7 +438,7 @@ function MultiIngestionSettings(): JSX.Element {
date: string,
formatTimezoneAdjustedTimestamp: (date: string, format: string) => string,
): string =>
formatTimezoneAdjustedTimestamp(date, 'MMM DD,YYYY, hh:mm a (UTC Z)');
formatTimezoneAdjustedTimestamp(date, DATE_TIME_FORMATS.UTC_MONTH_COMPACT);
const showDeleteLimitModal = (
APIKey: IngestionKeyProps,

View File

@ -1,6 +1,7 @@
import { Typography } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import { ResizeTable } from 'components/ResizeTable';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { useTimezone } from 'providers/Timezone';
import { useTranslation } from 'react-i18next';
import { License } from 'types/api/licenses/def';
@ -10,7 +11,7 @@ function ValidityColumn({ value }: { value: string }): JSX.Element {
return (
<Typography>
{formatTimezoneAdjustedTimestamp(value, 'YYYY-MM-DD HH:mm:ss (UTC Z)')}
{formatTimezoneAdjustedTimestamp(value, DATE_TIME_FORMATS.ISO_DATETIME_UTC)}
</Typography>
);
}

View File

@ -26,6 +26,7 @@ import createDashboard from 'api/dashboard/create';
import { AxiosError } from 'axios';
import cx from 'classnames';
import { ENTITY_VERSION_V4 } from 'constants/app';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import ROUTES from 'constants/routes';
import { sanitizeDashboardData } from 'container/NewDashboard/DashboardDescription';
import { downloadObjectAsJson } from 'container/NewDashboard/DashboardDescription/utils';
@ -361,7 +362,7 @@ function DashboardsList(): JSX.Element {
function getFormattedTime(dashboard: Dashboard, option: string): string {
return formatTimezoneAdjustedTimestamp(
get(dashboard, option, ''),
'MMM D, YYYY ⎯ hh:mm:ss A (UTC Z)',
DATE_TIME_FORMATS.DASH_DATETIME_UTC,
);
}
@ -407,7 +408,7 @@ function DashboardsList(): JSX.Element {
render: (dashboard: Data, _, index): JSX.Element => {
const formattedDateAndTime = formatTimezoneAdjustedTimestamp(
dashboard.createdAt,
'MMM D, YYYY ⎯ hh:mm:ss A (UTC Z)',
DATE_TIME_FORMATS.DASH_DATETIME_UTC,
);
const getLink = (): string => `${ROUTES.ALL_DASHBOARD}/${dashboard.id}`;

View File

@ -1,5 +1,6 @@
import { FastBackwardOutlined } from '@ant-design/icons';
import { Button, Divider } from 'antd';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import Controls from 'container/Controls';
import Download from 'container/Download/Download';
import { getGlobalTime } from 'container/LogsSearchFilter/utils';
@ -85,8 +86,8 @@ function LogControls(): JSX.Element | null {
logs.map((log) => {
const timestamp =
typeof log.timestamp === 'string'
? dayjs(log.timestamp).format('YYYY-MM-DD HH:mm:ss.SSS')
: dayjs(log.timestamp / 1e6).format('YYYY-MM-DD HH:mm:ss.SSS');
? dayjs(log.timestamp).format(DATE_TIME_FORMATS.ISO_DATETIME_MS)
: dayjs(log.timestamp / 1e6).format(DATE_TIME_FORMATS.ISO_DATETIME_MS);
return FlatLogData({
...log,

View File

@ -6,6 +6,7 @@ import { Button, Popover, Spin, Tooltip, Tree } from 'antd';
import GroupByIcon from 'assets/CustomIcons/GroupByIcon';
import cx from 'classnames';
import CopyClipboardHOC from 'components/Logs/CopyClipboardHOC';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { OPERATORS } from 'constants/queryBuilder';
import ROUTES from 'constants/routes';
import dompurify from 'dompurify';
@ -124,7 +125,7 @@ export function TableViewActions(
<span style={commonStyles}>
{formatTimezoneAdjustedTimestamp(
cleanTimestamp,
'MM/DD/YYYY, HH:mm:ss.SSS (UTC Z)',
DATE_TIME_FORMATS.UTC_US_MS,
)}
</span>
);

View File

@ -7,6 +7,7 @@ import logEvent from 'api/common/logEvent';
import { getYAxisFormattedValue } from 'components/Graph/yAxisConfig';
import LogsFormatOptionsMenu from 'components/LogsFormatOptionsMenu/LogsFormatOptionsMenu';
import { DEFAULT_ENTITY_VERSION } from 'constants/app';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { LOCALSTORAGE } from 'constants/localStorage';
import { AVAILABLE_EXPORT_PANEL_TYPES } from 'constants/panelTypes';
import { QueryParams } from 'constants/query';
@ -679,10 +680,10 @@ function LogsExplorerViews({
typeof log.timestamp === 'string'
? dayjs(log.timestamp)
.tz(timezone.value)
.format('YYYY-MM-DD HH:mm:ss.SSS')
.format(DATE_TIME_FORMATS.ISO_DATETIME_MS)
: dayjs(log.timestamp / 1e6)
.tz(timezone.value)
.format('YYYY-MM-DD HH:mm:ss.SSS');
.format(DATE_TIME_FORMATS.ISO_DATETIME_MS);
return FlatLogData({
timestamp,

View File

@ -5,6 +5,7 @@ import editUserApi from 'api/user/editUser';
import getOrgUser from 'api/user/getOrgUser';
import updateRole from 'api/user/updateRole';
import { ResizeTable } from 'components/ResizeTable';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import dayjs from 'dayjs';
import { useNotifications } from 'hooks/useNotifications';
import { useAppContext } from 'providers/App/App';
@ -280,7 +281,7 @@ function Members(): JSX.Element {
const { joinedOn } = record;
return (
<Typography>
{dayjs.unix(Number(joinedOn)).format('MMMM DD,YYYY')}
{dayjs.unix(Number(joinedOn)).format(DATE_TIME_FORMATS.MONTH_DATE_FULL)}
</Typography>
);
},

View File

@ -1,3 +1,4 @@
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { useTimezone } from 'providers/Timezone';
function DeploymentTime(deployTime: string): JSX.Element {
@ -6,7 +7,7 @@ function DeploymentTime(deployTime: string): JSX.Element {
<span>
{formatTimezoneAdjustedTimestamp(
deployTime,
'MMMM DD, YYYY hh:mm A (UTC Z)',
DATE_TIME_FORMATS.UTC_MONTH_FULL,
)}{' '}
</span>
);

View File

@ -3,6 +3,7 @@ import './styles.scss';
import { ExpandAltOutlined } from '@ant-design/icons';
import LogDetail from 'components/LogDetail';
import { VIEW_TYPES } from 'components/LogDetail/constants';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { useActiveLog } from 'hooks/logs/useActiveLog';
import { useTimezone } from 'providers/Timezone';
import { ILog } from 'types/api/logs/log';
@ -27,7 +28,7 @@ function LogsList({ logs }: LogsListProps): JSX.Element {
<div className="logs-preview-list-item-timestamp">
{formatTimezoneAdjustedTimestamp(
log.timestamp,
'MMM DD HH:mm:ss.SSS (UTC Z)',
DATE_TIME_FORMATS.UTC_MONTH_SHORT,
)}
</div>
<div className="logs-preview-list-item-body">{log.body}</div>

View File

@ -1,3 +1,4 @@
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { useTimezone } from 'providers/Timezone';
import React from 'react';
import { PipelineData, ProcessorData } from 'types/api/pipeline/def';
@ -10,7 +11,7 @@ function CreatedAtComponent({ record }: { record: Record }): JSX.Element {
const { formatTimezoneAdjustedTimestamp } = useTimezone();
return (
<ColumnDataStyle>
{formatTimezoneAdjustedTimestamp(record, 'MMMM DD, YYYY hh:mm A (UTC Z)')}
{formatTimezoneAdjustedTimestamp(record, DATE_TIME_FORMATS.UTC_MONTH_FULL)}
</ColumnDataStyle>
);
}

View File

@ -1,4 +1,5 @@
import { ColumnType } from 'antd/lib/table/interface';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import dayjs from 'dayjs';
import update from 'react-addons-update';
import { ProcessorData } from 'types/api/pipeline/def';
@ -69,7 +70,7 @@ export function getDataOnSearch(
key === 'createdAt'
? dayjs(data[key])
.locale('en')
.format('MMMM DD, YYYY hh:mm A')
.format(DATE_TIME_FORMATS.MONTH_DATETIME_FULL)
.includes(searchValue)
: String(data[key]).toLowerCase().includes(searchValue.toLowerCase()),
);

View File

@ -23,6 +23,7 @@ import {
Recurrence,
} from 'api/plannedDowntime/getAllDowntimeSchedules';
import { DowntimeScheduleUpdatePayload } from 'api/plannedDowntime/updateDowntimeSchedule';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import {
ModalButtonWrapper,
ModalTitle,
@ -52,9 +53,9 @@ dayjs.locale('en');
dayjs.extend(utc);
dayjs.extend(timezone);
const TIME_FORMAT = 'HH:mm';
const DATE_FORMAT = 'Do MMM YYYY';
const ORDINAL_FORMAT = 'Do';
const TIME_FORMAT = DATE_TIME_FORMATS.TIME;
const DATE_FORMAT = DATE_TIME_FORMATS.ORDINAL_DATE;
const ORDINAL_FORMAT = DATE_TIME_FORMATS.ORDINAL_ONLY;
interface PlannedDowntimeFormData {
name: string;
@ -66,7 +67,7 @@ interface PlannedDowntimeFormData {
timezone?: string;
}
const customFormat = 'Do MMMM, YYYY ⎯ HH:mm:ss';
const customFormat = DATE_TIME_FORMATS.ORDINAL_DATETIME;
interface PlannedDowntimeFormProps {
initialValues: Partial<

View File

@ -11,6 +11,7 @@ import updateDowntimeSchedule, {
PayloadProps,
} from 'api/plannedDowntime/updateDowntimeSchedule';
import { showErrorNotification } from 'components/ExplorerCard/utils';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import dayjs from 'dayjs';
import { isEmpty, isEqual } from 'lodash-es';
import { UseMutateAsyncFunction } from 'react-query';
@ -44,7 +45,9 @@ export const formatDateTime = (dateTimeString?: string | null): string => {
return 'N/A';
}
return dayjs(dateTimeString.slice(0, 19)).format('MMM DD, YYYY h:mm A');
return dayjs(dateTimeString.slice(0, 19)).format(
DATE_TIME_FORMATS.MONTH_DATETIME,
);
};
export const getAlertOptionsFromIds = (

View File

@ -5,6 +5,7 @@ import { Button } from 'antd';
import getLocalStorageKey from 'api/browser/localstorage/get';
import setLocalStorageKey from 'api/browser/localstorage/set';
import CustomTimePicker from 'components/CustomTimePicker/CustomTimePicker';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { LOCALSTORAGE } from 'constants/localStorage';
import { QueryParams } from 'constants/query';
import ROUTES from 'constants/routes';
@ -125,7 +126,7 @@ function DateTimeSelection({
timeInterval: Time | TimeV2 | CustomTimeType = '15m',
): string | Time => {
if (startTime && endTime && timeInterval === 'custom') {
const format = 'YYYY/MM/DD HH:mm';
const format = DATE_TIME_FORMATS.SLASH_DATETIME;
const startString = startTime.format(format);
const endString = endTime.format(format);

View File

@ -6,6 +6,7 @@ import { Button, Popover, Switch, Typography } from 'antd';
import getLocalStorageKey from 'api/browser/localstorage/get';
import setLocalStorageKey from 'api/browser/localstorage/set';
import CustomTimePicker from 'components/CustomTimePicker/CustomTimePicker';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { LOCALSTORAGE } from 'constants/localStorage';
import { QueryParams } from 'constants/query';
import {
@ -202,7 +203,7 @@ function DateTimeSelection({
timeInterval: Time | CustomTimeType = '15m',
): string | Time => {
if (startTime && endTime && timeInterval === 'custom') {
const format = 'DD/MM/YYYY HH:mm';
const format = DATE_TIME_FORMATS.UK_DATETIME;
const startString = startTime.format(format);
const endString = endTime.format(format);

View File

@ -1,6 +1,7 @@
import { TableProps, Tag, Typography } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import { ResizeTable } from 'components/ResizeTable';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import ROUTES from 'constants/routes';
import {
getSpanOrder,
@ -78,7 +79,11 @@ function TraceTable(): JSX.Element {
sorter: true,
render: (value: TableType['timestamp']): JSX.Element => {
const day = dayjs(value);
return <Typography>{day.format('YYYY/MM/DD HH:mm:ss')}</Typography>;
return (
<Typography>
{day.format(DATE_TIME_FORMATS.SLASH_DATETIME_SECONDS)}
</Typography>
);
},
},
{

View File

@ -1,4 +1,5 @@
import { Popover } from 'antd';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import dayjs from 'dayjs';
import { useIsDarkMode } from 'hooks/useDarkMode';
@ -8,7 +9,7 @@ function EventStartTime({ timeUnixNano }: EventStartTimeProps): JSX.Element {
const isDarkMode = useIsDarkMode();
const humanReadableTimeInDayJs = dayjs(timeUnixNano / 1e6).format(
'YYYY-MM-DD hh:mm:ss.SSS A',
DATE_TIME_FORMATS.ISO_DATETIME_MS,
);
return (

View File

@ -12,6 +12,7 @@ import {
StyledTypography,
} from 'components/Styled';
import { Flex, Spacing } from 'components/Styled/styles';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import GanttChart, { ITraceMetaData } from 'container/GantChart';
import { getNodeById } from 'container/GantChart/utils';
import Timeline from 'container/Timeline';
@ -200,7 +201,7 @@ function TraceDetail({ response }: TraceDetailProps): JSX.Element {
<Typography>
{dayjs(traceMetaData.globalStart)
.tz(timezone.value)
.format('hh:mm:ss a (UTC Z) MM/DD')}
.format(DATE_TIME_FORMATS.UTC_TIME_DATE)}
</Typography>
</styles.TimeStampContainer>
)}

View File

@ -1,5 +1,6 @@
import { Tag, Typography } from 'antd';
import { ColumnsType } from 'antd/es/table';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import ROUTES from 'constants/routes';
import { getMs } from 'container/Trace/Filters/Panel/PanelBody/Duration/util';
import { formUrlParams } from 'container/TraceDetail/utils';
@ -60,8 +61,14 @@ export const getListColumns = (
render: (value, item): JSX.Element => {
const date =
typeof value === 'string'
? formatTimezoneAdjustedTimestamp(value, 'YYYY-MM-DD HH:mm:ss.SSS')
: formatTimezoneAdjustedTimestamp(value / 1e6, 'YYYY-MM-DD HH:mm:ss.SSS');
? formatTimezoneAdjustedTimestamp(
value,
DATE_TIME_FORMATS.ISO_DATETIME_MS,
)
: formatTimezoneAdjustedTimestamp(
value / 1e6,
DATE_TIME_FORMATS.ISO_DATETIME_MS,
);
return (
<BlockLink to={getTraceLink(item)} openInNewTab={false}>
<Typography.Text>{date}</Typography.Text>

View File

@ -1,4 +1,5 @@
import { Tag, Typography } from 'antd';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { useTimezone } from 'providers/Timezone';
import { Alerts } from 'types/api/alerts/getTriggered';
@ -42,7 +43,7 @@ function ExapandableRow({ allAlerts }: ExapandableRowProps): JSX.Element {
<TableCell>
<Typography>{`${formatTimezoneAdjustedTimestamp(
formatedDate,
'MM/DD/YYYY hh:mm:ss A (UTC Z)',
DATE_TIME_FORMATS.UTC_US,
)}`}</Typography>
</TableCell>

View File

@ -3,6 +3,7 @@ import { Typography } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import { ResizeTable } from 'components/ResizeTable';
import LabelColumn from 'components/TableRenderer/LabelColumn';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import AlertStatus from 'container/TriggeredAlerts/TableComponents/AlertStatus';
import { useTimezone } from 'providers/Timezone';
import { Alerts } from 'types/api/alerts/getTriggered';
@ -86,7 +87,7 @@ function NoFilterTable({
render: (date): JSX.Element => (
<Typography>{`${formatTimezoneAdjustedTimestamp(
date,
'MM/DD/YYYY hh:mm:ss A (UTC Z)',
DATE_TIME_FORMATS.UTC_US,
)}`}</Typography>
),
},

View File

@ -1,4 +1,5 @@
import { Timezone } from 'components/CustomTimePicker/timezoneUtils';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import dayjs from 'dayjs';
import timezone from 'dayjs/plugin/timezone';
import utc from 'dayjs/plugin/utc';
@ -69,7 +70,10 @@ function useTimezoneFormatter({
* formatTimezoneAdjustedTimestamp('2024-03-14T19:30:00Z')
*/
const formatTimezoneAdjustedTimestamp = useCallback(
(input: TimestampInput, format = 'YYYY-MM-DD HH:mm:ss'): string => {
(
input: TimestampInput,
format = DATE_TIME_FORMATS.ISO_DATETIME_SECONDS as string,
): string => {
const timestamp = dayjs(input).valueOf();
const cacheKey = `${timestamp}_${userTimezone.value}`;

View File

@ -1,4 +1,5 @@
import { getToolTipValue } from 'components/Graph/yAxisConfig';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { themeColors } from 'constants/theme';
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
@ -72,11 +73,11 @@ const generateTooltipContent = (
if (isBillingUsageGraphs) {
tooltipTitle = dayjs(data[0][idx] * 1000)
.tz(timezone)
.format('MMM DD YYYY');
.format(DATE_TIME_FORMATS.MONTH_YEAR);
} else {
tooltipTitle = dayjs(data[0][idx] * 1000)
.tz(timezone)
.format('MMM DD YYYY h:mm:ss A');
.format(DATE_TIME_FORMATS.MONTH_DATETIME_SECONDS);
}
} else if (item.show) {
const {

View File

@ -13,3 +13,33 @@ export const lineInterpolations = {
stepBefore: 'stepBefore',
spline: 'spline',
};
export const uPlotXAxisValuesFormat = [
[3600 * 24 * 365, '{YYYY}', null, null, null, null, null, null, 1],
[3600 * 24 * 28, '{MMM}', '\n{YYYY}', null, null, null, null, null, 1],
[3600 * 24, '{M}/{D}', '\n{YYYY}', null, null, null, null, null, 1],
[3600, '{HH}:{mm}', '\n{M}/{D}/{YY}', null, '\n{M}/{D}', null, null, null, 1],
[60, '{HH}:{mm}', '\n{M}/{D}/{YY}', null, '\n{M}/{D}', null, null, null, 1],
[
1,
':{ss}',
'\n{M}/{D}/{YY} {HH}:{mm}',
null,
'\n{M}/{D} {HH}:{mm}',
null,
'\n{HH}:{mm}',
null,
1,
],
[
0.001,
':{ss}.{fff}',
'\n{M}/{D}/{YY} {HH}:{mm}',
null,
'\n{M}/{D} {HH}:{mm}',
null,
'\n{HH}:{mm}',
null,
1,
],
];

View File

@ -2,8 +2,10 @@
// @ts-nocheck
import { getToolTipValue } from 'components/Graph/yAxisConfig';
import { uPlotXAxisValuesFormat } from './constants';
import getGridColor from './getGridColor';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const getAxes = (isDarkMode: boolean, yAxisUnit?: string): any => [
{
stroke: isDarkMode ? 'white' : 'black', // Color of the axis line
@ -17,6 +19,7 @@ const getAxes = (isDarkMode: boolean, yAxisUnit?: string): any => [
width: 0.3, // Width of the tick lines,
show: true,
},
values: uPlotXAxisValuesFormat,
gap: 5,
},
{

View File

@ -7,6 +7,7 @@ import installIntegration from 'api/Integrations/installIntegration';
import ConfigureIcon from 'assets/Integrations/ConfigureIcon';
import cx from 'classnames';
import { SOMETHING_WENT_WRONG } from 'constants/api';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import dayjs from 'dayjs';
import { useNotifications } from 'hooks/useNotifications';
import { ArrowLeftRight, Check } from 'lucide-react';
@ -249,19 +250,25 @@ function IntegrationDetailHeader(
title={
latestData.last_received_ts_ms
? // eslint-disable-next-line sonarjs/no-duplicate-string
dayjs(latestData.last_received_ts_ms).format('DD MMM YYYY HH:mm')
dayjs(latestData.last_received_ts_ms).format(
DATE_TIME_FORMATS.MONTH_DATETIME_SHORT,
)
: ''
}
key={
latestData.last_received_ts_ms
? dayjs(latestData.last_received_ts_ms).format('DD MMM YYYY HH:mm')
? dayjs(latestData.last_received_ts_ms).format(
DATE_TIME_FORMATS.MONTH_DATETIME_SHORT,
)
: ''
}
placement="right"
>
<Typography.Text className="last-value" ellipsis>
{latestData.last_received_ts_ms
? dayjs(latestData.last_received_ts_ms).format('DD MMM YYYY HH:mm')
? dayjs(latestData.last_received_ts_ms).format(
DATE_TIME_FORMATS.MONTH_DATETIME_SHORT,
)
: ''}
</Typography.Text>
</Tooltip>

View File

@ -15,6 +15,7 @@ import {
getViewDetailsUsingViewKey,
showErrorNotification,
} from 'components/ExplorerCard/utils';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { getRandomColor } from 'container/ExplorerOptions/utils';
import { useDeleteView } from 'hooks/saveViews/useDeleteView';
import { useGetAllViews } from 'hooks/saveViews/useGetAllViews';
@ -221,7 +222,7 @@ function SaveView(): JSX.Element {
const formattedDateAndTime = formatTimezoneAdjustedTimestamp(
view.createdAt,
'HH:mm:ss ⎯ MMM D, YYYY (UTC Z)',
DATE_TIME_FORMATS.DASH_TIME_DATE,
);
const isEditDeleteSupported = allowedRoles.includes(user.role as string);

View File

@ -1,3 +1,4 @@
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
import duration from 'dayjs/plugin/duration';
@ -16,7 +17,7 @@ export const getFormattedDate = (epochTimestamp: number): string => {
const date = dayjs.unix(epochTimestamp);
// Format the date as "18 Nov 2013"
return date.format('DD MMM YYYY');
return date.format(DATE_TIME_FORMATS.MONTH_DATE_SHORT);
};
export const getFormattedDateWithMinutes = (epochTimestamp: number): string => {
@ -24,7 +25,7 @@ export const getFormattedDateWithMinutes = (epochTimestamp: number): string => {
const date = dayjs.unix(epochTimestamp);
// Format the date as "18 Nov 2013"
return date.format('DD MMM YYYY HH:mm');
return date.format(DATE_TIME_FORMATS.MONTH_DATETIME_SHORT);
};
export const getRemainingDays = (billingEndDate: number): number => {