Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Web console: query with timezone #17650

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions licenses.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5465,7 +5465,7 @@ license_category: binary
module: web-console
license_name: Apache License version 2.0
copyright: Vadim Ogievetsky
version: 1.1.0
version: 1.2.0

---

Expand Down Expand Up @@ -5682,10 +5682,10 @@ license_file_path: licenses/bin/d3-shape.ISC
name: "d3-time-format"
license_category: binary
module: web-console
license_name: BSD-3-Clause License
license_name: ISC License
copyright: Mike Bostock
version: 2.2.1
license_file_path: licenses/bin/d3-time-format.BSD3
version: 4.1.0
license_file_path: licenses/bin/d3-time-format.ISC

---

Expand Down
49 changes: 34 additions & 15 deletions web-console/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion web-console/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"@internationalized/date": "^3.5.6",
"ace-builds": "~1.5.3",
"axios": "^1.7.7",
"chronoshift": "^1.1.0",
"chronoshift": "^1.2.0",
"classnames": "^2.2.6",
"copy-to-clipboard": "^3.3.3",
"d3-array": "^3.2.4",
Expand All @@ -69,6 +69,7 @@
"d3-scale": "^4.0.2",
"d3-selection": "^3.0.0",
"d3-shape": "^3.2.0",
"d3-time-format": "^4.1.0",
"date-fns": "^2.28.0",
"druid-query-toolkit": "^1.0.2",
"echarts": "^5.5.1",
Expand Down Expand Up @@ -104,6 +105,7 @@
"@types/d3-scale": "^4.0.8",
"@types/d3-selection": "^3.0.11",
"@types/d3-shape": "^3.1.6",
"@types/d3-time-format": "^4.0.3",
"@types/enzyme": "^3.10.18",
"@types/enzyme-adapter-react-16": "^1.0.9",
"@types/file-saver": "^2.0.7",
Expand Down
1 change: 1 addition & 0 deletions web-console/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,6 @@ export * from './table-clickable-cell/table-clickable-cell';
export * from './table-column-selector/table-column-selector';
export * from './table-filterable-cell/table-filterable-cell';
export * from './timed-button/timed-button';
export * from './timezone-menu-items/timezone-menu-items';
export * from './view-control-bar/view-control-bar';
export * from './warning-checklist/warning-checklist';
14 changes: 11 additions & 3 deletions web-console/src/components/table-cell/table-cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,16 @@
*/

import { IconNames } from '@blueprintjs/icons';
import { Timezone } from 'chronoshift';
import * as JSONBig from 'json-bigint-native';
import React, { useState } from 'react';

import { ShowValueDialog } from '../../dialogs/show-value-dialog/show-value-dialog';
import { isSimpleArray, prettyFormatIsoDateWithMsIfNeeded } from '../../utils';
import {
isSimpleArray,
prettyFormatIsoDateWithMsIfNeeded,
toIsoStringInTimezone,
} from '../../utils';
import { ActionIcon } from '../action-icon/action-icon';

import './table-cell.scss';
Expand Down Expand Up @@ -51,10 +56,11 @@ function shortenString(str: string): ShortParts {
export interface TableCellProps {
value: any;
unlimited?: boolean;
timezone?: Timezone;
}

export const TableCell = React.memo(function TableCell(props: TableCellProps) {
const { value, unlimited } = props;
const { value, unlimited, timezone = Timezone.UTC } = props;
const [showValue, setShowValue] = useState<string | undefined>();

function renderShowValueDialog() {
Expand Down Expand Up @@ -98,7 +104,9 @@ export const TableCell = React.memo(function TableCell(props: TableCellProps) {
const dateValue = value.valueOf();
return (
<div className="table-cell timestamp" data-tooltip={String(dateValue)}>
{isNaN(dateValue) ? 'Invalid date' : prettyFormatIsoDateWithMsIfNeeded(value.toISOString())}
{isNaN(dateValue)
? 'Invalid date'
: prettyFormatIsoDateWithMsIfNeeded(toIsoStringInTimezone(value, timezone))}
</div>
);
} else if (isSimpleArray(value)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@

exports[`TimezoneMenuItems matches snapshot 1`] = `
[
<Blueprint5.MenuDivider
title="Timezone type"
/>,
<Blueprint5.MenuItem
active={false}
disabled={false}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* limitations under the License.
*/

import { shallow } from '../../../utils/shallow-renderer';
import { shallow } from '../../utils/shallow-renderer';

import { TimezoneMenuItems } from './timezone-menu-items';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@
* limitations under the License.
*/

import { Icon, MenuDivider, MenuItem } from '@blueprintjs/core';
import { Icon, MenuItem } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import { fromDate, getLocalTimeZone } from '@internationalized/date';
import { minute } from 'chronoshift';
import { useMemo } from 'react';

import { tickIcon, timezoneOffsetInMinutesToString } from '../../../utils';
import { tickIcon, timezoneOffsetInMinutesToString } from '../../utils';

const NAMED_TIMEZONES: string[] = [
'America/Juneau', // -9:00
Expand Down Expand Up @@ -51,10 +51,11 @@ export interface TimezoneMenuItemsProps {
sqlTimeZone: string | undefined;
setSqlTimeZone(sqlTimeZone: string | undefined): void;
defaultSqlTimeZone: string | undefined;
namedOnly?: boolean;
}

export const TimezoneMenuItems = function TimezoneMenuItems(props: TimezoneMenuItemsProps) {
const { sqlTimeZone, setSqlTimeZone, defaultSqlTimeZone } = props;
const { sqlTimeZone, setSqlTimeZone, defaultSqlTimeZone, namedOnly } = props;

const { timezones, myTimezone, offsetsInMinutes, myOffsetInMinutes } = useMemo(() => {
const now = new Date();
Expand Down Expand Up @@ -96,35 +97,44 @@ export const TimezoneMenuItems = function TimezoneMenuItems(props: TimezoneMenuI
};
}, []);

return [
<MenuDivider key="type" title="Timezone type" />,
const defaultItem = (
<MenuItem
key="default"
icon={tickIcon(!sqlTimeZone)}
text="Default"
label={defaultSqlTimeZone}
shouldDismissPopover={false}
onClick={() => setSqlTimeZone(undefined)}
/>,
/>
);

const namedMenuItems = timezones.map(({ timezone, offsetInMinutes }) => (
<MenuItem
key={timezone}
icon={tickIcon(timezone === sqlTimeZone)}
text={
timezone === myTimezone ? (
<>
{timezone} <Icon icon={IconNames.STAR} data-tooltip="Browser timezone" />
</>
) : (
timezone
)
}
label={`UTC${timezoneOffsetInMinutesToString(offsetInMinutes, false)}`}
shouldDismissPopover={false}
onClick={() => setSqlTimeZone(timezone)}
/>
));

if (namedOnly) {
return [defaultItem, ...namedMenuItems];
}

return [
defaultItem,
<MenuItem key="named" icon={tickIcon(String(sqlTimeZone).includes('/'))} text="Named">
{timezones.map(({ timezone, offsetInMinutes }) => (
<MenuItem
key={timezone}
icon={tickIcon(timezone === sqlTimeZone)}
text={
timezone === myTimezone ? (
<>
{timezone} <Icon icon={IconNames.STAR} data-tooltip="Browser timezone" />
</>
) : (
timezone
)
}
label={`UTC${timezoneOffsetInMinutesToString(offsetInMinutes, false)}`}
shouldDismissPopover={false}
onClick={() => setSqlTimeZone(timezone)}
/>
))}
{namedMenuItems}
</MenuItem>,
<MenuItem key="offset" icon={tickIcon(String(sqlTimeZone).includes(':'))} text="Offset">
{offsetsInMinutes.map(offsetInMinutes => {
Expand Down
10 changes: 5 additions & 5 deletions web-console/src/utils/date-format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
* limitations under the License.
*/

import type { Duration } from 'chronoshift';
import type { Duration, Timezone } from 'chronoshift';

import { prettyFormatIsoDate } from './date';
import { prettyFormatIsoDate, toIsoStringInTimezone } from './date';

export function formatStartDuration(start: Date, duration: Duration): string {
let sliceLength;
Expand Down Expand Up @@ -54,9 +54,9 @@ export function formatStartDuration(start: Date, duration: Duration): string {
)}`;
}

export function formatIsoDateRange(start: Date, end: Date): string {
let startStr = prettyFormatIsoDate(start);
let endStr = prettyFormatIsoDate(end);
export function formatIsoDateRange(start: Date, end: Date, timezone: Timezone): string {
let startStr = prettyFormatIsoDate(toIsoStringInTimezone(start, timezone));
let endStr = prettyFormatIsoDate(toIsoStringInTimezone(end, timezone));

if (start.getMinutes() === 0 && end.getMinutes() === 0) {
startStr = startStr.slice(0, 16);
Expand Down
24 changes: 6 additions & 18 deletions web-console/src/utils/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
*/

import type { DateRange, NonNullDateRange } from '@blueprintjs/datetime';
import { fromDate, toTimeZone } from '@internationalized/date';
import type { Timezone } from 'chronoshift';

const CURRENT_YEAR = new Date().getUTCFullYear();

Expand All @@ -38,24 +40,10 @@ export function prettyFormatIsoDate(isoDate: string | Date): string {
return prettyFormatIsoDateWithMsIfNeeded(isoDate).replace(/\.\d\d\d/, '');
}

export function prettyFormatIsoDateTick(date: Date): string {
// s like 2016-06-27T19:00:00.000Z
let s = date.toISOString();
if (!s.endsWith('.000Z')) {
return s.slice(19, 23); // => ".001"
}
s = s.slice(0, 19); // s like 2016-06-27T19:00:00

if (!s.endsWith(':00')) {
return s.slice(11); // => 00:00:01
}
s = s.slice(0, 16); // s like 2016-06-27T19:00

if (!s.endsWith('T00:00')) {
return s.slice(11); // => 00:00
}

return s.slice(0, 10); // s like 2016-06-27
export function toIsoStringInTimezone(date: Date, timezone: Timezone): string {
if (timezone.isUTC()) return date.toISOString();
const zonedDate = toTimeZone(fromDate(date, 'Etc/UTC'), timezone.toString());
return zonedDate.toString().replace(/[+-]\d\d:\d\d\[.+$/, '');
}

export function utcToLocalDate(utcDate: Date): Date {
Expand Down
1 change: 1 addition & 0 deletions web-console/src/utils/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,6 @@ export * from './sanitizers';
export * from './sql';
export * from './stage';
export * from './table-helpers';
export * from './ticks';
export * from './types';
export * from './values-query';
Loading
Loading