Browse Source

ref(dateTime): Use updated formatting rules (#35666)

* ref(dateTime): Use updated formatting rules

* ref(eventsTableRow): Show full time string

* fix(discover): Always show the year for timestamp fields
Vu Luong 2 years ago
parent
commit
d801efb941

+ 1 - 1
docs-ui/stories/components/pageTimeRangeSelector.stories.js

@@ -28,7 +28,7 @@ export const _PageTimeRangeSelectorWithOptions = () => (
       release: (
         <Fragment>
           {t('Entire Release Period')} (
-          <DateTime date={start} timeAndDate /> - <DateTime date={end} timeAndDate />)
+          <DateTime date={start} /> - <DateTime date={end} />)
         </Fragment>
       ),
       ...omit(DEFAULT_RELATIVE_PERIODS, ['1h']),

+ 2 - 6
static/app/components/activity/item/index.tsx

@@ -107,13 +107,9 @@ function ActivityItem({
 
             {showRange && (
               <StyledDateTimeWindow>
-                <StyledDateTime timeOnly={timeOnly} timeAndDate={!timeOnly} date={date} />
+                <StyledDateTime timeOnly={timeOnly} date={date} />
                 {' — '}
-                <StyledDateTime
-                  timeOnly={timeOnly}
-                  timeAndDate={!timeOnly}
-                  date={dateEnded}
-                />
+                <StyledDateTime timeOnly={timeOnly} date={dateEnded} />
               </StyledDateTimeWindow>
             )}
           </ActivityHeader>

+ 95 - 57
static/app/components/dateTime.tsx

@@ -4,81 +4,119 @@ import momentTimezone from 'moment-timezone';
 import ConfigStore from 'sentry/stores/configStore';
 
 interface Props extends React.HTMLAttributes<HTMLTimeElement> {
+  /**
+   * Input date.
+   */
   date: moment.MomentInput | momentTimezone.MomentInput;
+  /**
+   * If true, will only return the date part, e.g. "Jan 1".
+   */
   dateOnly?: boolean;
+  /**
+   * Formatting string. If specified, this formatting string will override all
+   * other formatting props (dateOnly, timeOnly, year).
+   */
   format?: string;
+  /**
+   * Whether to show the seconds. Is false by default.
+   */
   seconds?: boolean;
-  shortDate?: boolean;
-  timeAndDate?: boolean;
+  /**
+   * If true, will only return the time part, e.g. "2:50 PM"
+   */
   timeOnly?: boolean;
+  /**
+   * Whether to show the time zone. If not specified, the returned date string
+   * will not contain the time zone _unless_ the time is UTC, in which case
+   * the user would want to know that it's UTC and not their own time zone.
+   */
+  timeZone?: boolean;
+  /**
+   * Whether the date input is UTC time or not.
+   */
   utc?: 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;
+}
+
+function getDateFormat({year}: Pick<Props, 'year'>) {
+  // "Jan 1, 2022" or "Jan 1"
+  return year ? 'MMM D, YYYY' : 'MMM D';
+}
+
+function getTimeFormat({clock24Hours, seconds, timeZone}) {
+  const substrings = [
+    clock24Hours ? 'HH' : 'h', // hour – "23" (24h format) or "11" (12h format)
+    ':mm', // minute
+    seconds ? ':ss' : '', // second
+    clock24Hours ? '' : ' A', // AM/PM
+    timeZone ? ' z' : '', // time zone
+  ];
+  return substrings.join('');
+}
+
+function getFormat({
+  dateOnly,
+  timeOnly,
+  year,
+  seconds,
+  timeZone,
+  clock24Hours,
+}: Pick<Props, 'dateOnly' | 'timeOnly' | 'year' | 'seconds' | 'timeZone'> & {
+  clock24Hours: boolean;
+}) {
+  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}`;
 }
 
 function DateTime({
   format,
   date,
   utc,
-  shortDate,
   dateOnly,
   timeOnly,
-  timeAndDate,
-  seconds = true,
+  year,
+  timeZone,
+  seconds = false,
   ...props
 }: Props) {
-  function getFormat({clock24Hours}: {clock24Hours: boolean}): string {
-    if (format) {
-      return format;
-    }
-
-    // October 26, 2017
-    if (dateOnly) {
-      return 'LL';
-    }
-
-    // Oct 26, 11:30 AM
-    if (timeAndDate) {
-      if (clock24Hours) {
-        return 'MMM DD, HH:mm';
-      }
-
-      return 'MMM DD, LT';
-    }
-
-    // 4:57 PM
-    if (timeOnly) {
-      if (clock24Hours) {
-        return 'HH:mm';
-      }
-
-      return 'LT';
-    }
-
-    if (shortDate) {
-      return 'MM/DD/YYYY';
-    }
-
-    if (clock24Hours) {
-      if (seconds) {
-        // Oct 26, 2017 11:30:30
-        return 'MMM D, YYYY HH:mm:ss';
-      }
-
-      // Oct 26, 2017 11:30
-      return 'MMM D, YYYY HH:mm';
-    }
-
-    // Oct 26, 2017 11:30:30 AM
-    if (seconds) {
-      return 'll LTS z';
-    }
-
-    // Default is Oct 26, 2017 11:30 AM
-    return 'lll';
-  }
-
   const user = ConfigStore.get('user');
   const options = user?.options;
-  const formatString = getFormat(options);
+
+  const formatString =
+    format ??
+    getFormat({
+      dateOnly,
+      timeOnly,
+      // If the year prop is defined, then use it. Otherwise only show the year if `date`
+      // is in the current year.
+      year: year ?? moment().year() !== moment(date).year(),
+      // If timeZone is defined, use it. Otherwise only show the time zone if we're using
+      // UTC time.
+      timeZone: timeZone ?? utc,
+      seconds,
+      ...options,
+    });
 
   return (
     <time {...props}>

+ 2 - 2
static/app/components/events/interfaces/spans/spanDetail.tsx

@@ -405,7 +405,7 @@ class SpanDetail extends Component<Props, State> {
                   fixed: 'Mar 16, 2020 9:10:12 AM UTC',
                   value: (
                     <Fragment>
-                      <DateTime date={startTimestamp * 1000} />
+                      <DateTime date={startTimestamp * 1000} year seconds timeZone />
                       {` (${startTimestamp})`}
                     </Fragment>
                   ),
@@ -416,7 +416,7 @@ class SpanDetail extends Component<Props, State> {
                   fixed: 'Mar 16, 2020 9:10:13 AM UTC',
                   value: (
                     <Fragment>
-                      <DateTime date={endTimestamp * 1000} />
+                      <DateTime date={endTimestamp * 1000} year seconds timeZone />
                       {` (${endTimestamp})`}
                     </Fragment>
                   ),

+ 1 - 1
static/app/components/eventsTable/eventsTableRow.tsx

@@ -61,7 +61,7 @@ class EventsTableRow extends Component<Props> {
         <td>
           <h5>
             <GlobalSelectionLink to={link}>
-              <DateTime date={event.dateCreated} />
+              <DateTime date={event.dateCreated} year seconds timeZone />
             </GlobalSelectionLink>
             <small>{event.title.substr(0, 100)}</small>
             {this.renderCrashFileLink()}

+ 1 - 1
static/app/components/profiling/profilesTable.tsx

@@ -172,7 +172,7 @@ function ProfilesTableCell({column, dataRow}: ProfilesTableCellProps) {
     case 'timestamp':
       return (
         <Container>
-          <DateTime date={value * 1000} />
+          <DateTime date={value * 1000} year seconds timeZone />
         </Container>
       );
     case 'trace_duration_ms':

+ 3 - 3
static/app/utils/discover/fieldRenderers.tsx

@@ -123,7 +123,7 @@ export const FIELD_FORMATTERS: FieldFormatters = {
       <Container>
         {data[field]
           ? getDynamicText({
-              value: <FieldDateTime date={data[field]} />,
+              value: <FieldDateTime date={data[field]} year seconds timeZone />,
               fixed: 'timestamp',
             })
           : emptyValue}
@@ -437,7 +437,7 @@ const SPECIAL_FIELDS: SpecialFields = {
     renderFunc: data => (
       <Container>
         {getDynamicText({
-          value: <FieldDateTime date={data['timestamp.to_hour']} format="lll z" />,
+          value: <FieldDateTime date={data['timestamp.to_hour']} year timeZone />,
           fixed: 'timestamp.to_hour',
         })}
       </Container>
@@ -448,7 +448,7 @@ const SPECIAL_FIELDS: SpecialFields = {
     renderFunc: data => (
       <Container>
         {getDynamicText({
-          value: <FieldDateTime date={data['timestamp.to_day']} dateOnly utc />,
+          value: <FieldDateTime date={data['timestamp.to_day']} dateOnly year utc />,
           fixed: 'timestamp.to_day',
         })}
       </Container>

+ 3 - 0
static/app/views/alerts/rules/issue/details/issuesList.tsx

@@ -130,6 +130,9 @@ class AlertRuleIssuesList extends AsyncComponent<Props, State> {
                       value: lastTriggered,
                       fixed: 'Mar 16, 2020 9:10:13 AM UTC',
                     })}
+                    year
+                    seconds
+                    timeZone
                   />
                 </div>
               </Fragment>

+ 4 - 4
static/app/views/alerts/rules/metric/details/index.tsx

@@ -94,9 +94,9 @@ class MetricAlertDetails extends Component<Props, State> {
         label: t('Custom time'),
         display: (
           <Fragment>
-            <DateTime date={moment.utc(location.query.start)} timeAndDate />
+            <DateTime date={moment.utc(location.query.start)} />
             {' — '}
-            <DateTime date={moment.utc(location.query.end)} timeAndDate />
+            <DateTime date={moment.utc(location.query.end)} />
           </Fragment>
         ),
         custom: true,
@@ -113,9 +113,9 @@ class MetricAlertDetails extends Component<Props, State> {
         label: t('Custom time'),
         display: (
           <Fragment>
-            <DateTime date={moment.utc(start)} timeAndDate />
+            <DateTime date={moment.utc(start)} />
             {' — '}
-            <DateTime date={moment.utc(end)} timeAndDate />
+            <DateTime date={moment.utc(end)} />
           </Fragment>
         ),
         custom: true,

+ 3 - 0
static/app/views/alerts/rules/metric/details/metricHistory.tsx

@@ -114,6 +114,9 @@ function MetricAlertActivity({organization, incident}: MetricAlertActivityProps)
           value: incident.dateCreated,
           fixed: 'Mar 4, 2022 10:44:13 AM UTC',
         })}
+        year
+        seconds
+        timeZone
       />
     </ErrorBoundary>
   );

Some files were not shown because too many files changed in this diff