Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b98c111

Browse files
haldenlkanitw
authored andcommittedJan 29, 2020
fix: properly support utc timeunits
1 parent b5a593d commit b98c111

12 files changed

+45
-17
lines changed
 

‎examples/specs/bar_yearmonth_custom_format.vl.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
3-
"description": "Temperature in Seattle as a bar chart with yearmonth time unit.",
3+
"description": "Custom time format on x-axis.",
44
"data": {"url": "data/seattle-temps.csv"},
55
"mark": "bar",
66
"encoding": {

‎examples/specs/line_timeunit_transform.vl.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
3-
"description": "Google's stock price over time. Used to demonstrate the time unit transform.",
3+
"description": "Time unit transform.",
44
"data": {"url": "data/seattle-weather.csv"},
55
"mark": "line",
66
"transform": [{

‎examples/specs/time_output_utc_scale.vl.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
3-
"description": "Google's stock price over time.",
3+
"description": "Using utc scale with local time input.",
44
"data": {
55
"values": [
66
{"date": "Sun, 01 Jan 2012 23:00:00", "price": 150},

‎examples/specs/time_output_utc_timeunit.vl.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
3-
"description": "Google's stock price over time.",
3+
"description": "Using utc timeunit with local time input.",
44
"data": {
55
"values": [
66
{"date": "Sun, 01 Jan 2012 23:00:00", "price": 150},

‎examples/specs/time_parse_local.vl.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
3-
"description": "Google's stock price over time.",
3+
"description": "Non-ISO time strings are parsed as local time.",
44
"data": {
55
"values": [
66
{"date": "10 Oct 2011 22:48:00"},

‎examples/specs/time_parse_utc_format.vl.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
3-
"description": "Google's stock price over time.",
3+
"description": "Using format parse to parsing of input time data as utc time.",
44
"data": {
55
"values": [
66
{"date": "10 Oct 2011 22:48:00"},

‎site/docs/transform/timeunit.md

+1-3
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ To parse data in local time or UTC time, there are three cases:
120120

121121
### Output
122122

123-
By default, Vega-Lite will output data in local time (even when input is parsed as UTC time). To output data in UTC time, we need to specify either a UTC time unit or scale:
123+
By default, Vega-Lite will output data in local time (even when input is parsed as UTC time). To output data in UTC time, we can specify either a UTC time unit or scale:
124124

125125
1. UTC time unit when input data is in local time.
126126

@@ -129,5 +129,3 @@ By default, Vega-Lite will output data in local time (even when input is parsed
129129
2. UTC scale type when you have input data in UTC time.
130130

131131
<span class="vl-example" data-name="time_output_utc_scale"></span>
132-
133-
Do **not** use UTC time unit and the UTC scale type at the same time since that will cause Vega-Lite to shift the output time twice.

‎src/compile/data/timeunit.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {TimeUnitTransform as VgTimeUnitTransform} from 'vega';
22
import {getSecondaryRangeChannel} from '../../channel';
33
import {hasBand, vgField} from '../../channeldef';
4-
import {getTimeUnitParts} from '../../timeunit';
4+
import {getTimeUnitParts, isUTCTimeUnit} from '../../timeunit';
55
import {TimeUnitTransform} from '../../transform';
66
import {Dict, duplicate, hash, keys, vals} from '../../util';
77
import {isUnitModel, ModelWithField} from '../model';
@@ -101,6 +101,7 @@ export class TimeUnitNode extends DataFlowNode {
101101
field,
102102
type: 'timeunit',
103103
units: getTimeUnitParts(timeUnit),
104+
...(isUTCTimeUnit(timeUnit) ? {timezone: 'utc'} : {}),
104105
as: [as, `${as}_end`]
105106
});
106107
}

‎src/compile/scale/type.ts

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import * as log from '../../log';
55
import {Mark} from '../../mark';
66
import {channelSupportScaleType, Scale, ScaleType, scaleTypeSupportDataType} from '../../scale';
77
import * as util from '../../util';
8+
import {isUTCTimeUnit} from '../../timeunit';
89

910
export type RangeType = 'continuous' | 'discrete' | 'flexible' | undefined;
1011

@@ -77,6 +78,8 @@ function defaultType(channel: Channel, fieldDef: TypedFieldDef<string>, mark: Ma
7778
log.warn(log.message.discreteChannelCannotEncode(channel, 'temporal'));
7879
// TODO: consider using quantize (equivalent to binning) once we have it
7980
return 'ordinal';
81+
} else if (fieldDef.timeUnit && isUTCTimeUnit(fieldDef.timeUnit)) {
82+
return 'utc';
8083
}
8184
return 'time';
8285

‎src/timeunit.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ export function formatExpression(timeUnit: TimeUnit, field: string, isUTCScale:
329329
// We only use utcFormat for utc scale
330330
// For utc time units, the data is already converted as a part of timeUnit transform.
331331
// Thus, utc time units should use timeFormat to avoid shifting the time twice.
332-
if (isUTCScale) {
332+
if (isUTCScale || isUTCTimeUnit(timeUnit)) {
333333
return `utcFormat(${field}, ${timeUnitSpecifierExpr})`;
334334
} else {
335335
return `timeFormat(${field}, ${timeUnitSpecifierExpr})`;

‎test/compile/data/timeunit.test.ts

+17-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ function assembleFromTransform(t: TimeUnitTransform) {
1414

1515
describe('compile/data/timeunit', () => {
1616
describe('parseUnit', () => {
17-
it('should return a dictionary of a formula transform for point', () => {
17+
it('should return a timeunit transform for point', () => {
1818
const model = parseUnitModel({
1919
data: {values: []},
2020
mark: 'point',
@@ -33,7 +33,7 @@ describe('compile/data/timeunit', () => {
3333
]);
3434
});
3535

36-
it('should return a dictionary of formula transforms for bar', () => {
36+
it('should return a unit transforms for bar', () => {
3737
const model = parseUnitModel({
3838
data: {values: []},
3939
mark: 'bar',
@@ -52,7 +52,7 @@ describe('compile/data/timeunit', () => {
5252
]);
5353
});
5454

55-
it('should return a dictionary of formula transform from transform array', () => {
55+
it('should return a timeunit transform from transform array', () => {
5656
const t: TimeUnitTransform = {field: 'date', as: 'month_date', timeUnit: 'month'};
5757

5858
expect(assembleFromTransform(t)).toEqual([
@@ -64,6 +64,20 @@ describe('compile/data/timeunit', () => {
6464
}
6565
]);
6666
});
67+
68+
it('should return a timeunit transform with timezone for utc units', () => {
69+
const t: TimeUnitTransform = {field: 'date', as: 'utcmonth_date', timeUnit: 'utcmonth'};
70+
71+
expect(assembleFromTransform(t)).toEqual([
72+
{
73+
type: 'timeunit',
74+
field: 'date',
75+
timezone: 'utc',
76+
as: ['utcmonth_date', 'utcmonth_date_end'],
77+
units: ['month']
78+
}
79+
]);
80+
});
6781
});
6882

6983
describe('hash', () => {

‎test/compile/scale/type.test.ts

+15-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {scaleType} from '../../../src/compile/scale/type';
33
import * as log from '../../../src/log';
44
import {BAR, PRIMITIVE_MARKS, RULE} from '../../../src/mark';
55
import {ScaleType} from '../../../src/scale';
6-
import {TIMEUNITS} from '../../../src/timeunit';
6+
import {TIMEUNITS, isUTCTimeUnit} from '../../../src/timeunit';
77
import {NOMINAL, ORDINAL} from '../../../src/type';
88
import * as util from '../../../src/util';
99
import {RECT} from './../../../src/mark';
@@ -140,11 +140,17 @@ describe('compile/scale', () => {
140140
})
141141
);
142142

143-
it('should return time for all time units.', () => {
144-
for (const timeUnit of TIMEUNITS) {
143+
it('should return time for all non-utc time units.', () => {
144+
for (const timeUnit of TIMEUNITS.filter(t => !isUTCTimeUnit(t))) {
145145
expect(scaleType({}, Y, {type: 'temporal', timeUnit: timeUnit}, 'point')).toEqual(ScaleType.TIME);
146146
}
147147
});
148+
149+
it('should return utc for all utc time units.', () => {
150+
for (const timeUnit of TIMEUNITS.filter(t => isUTCTimeUnit(t))) {
151+
expect(scaleType({}, Y, {type: 'temporal', timeUnit: timeUnit}, 'point')).toEqual(ScaleType.UTC);
152+
}
153+
});
148154
});
149155
describe('quantitative', () => {
150156
it('should return linear scale for quantitative color field by default.', () => {
@@ -209,6 +215,12 @@ describe('compile/scale', () => {
209215
);
210216
});
211217

218+
it('should return utc scale type if data type is temporal and specified scale type is utc', () => {
219+
expect(scaleType({type: ScaleType.UTC}, 'x', {type: 'temporal', timeUnit: 'year'}, 'point')).toEqual(
220+
ScaleType.UTC
221+
);
222+
});
223+
212224
it('should return default scale type if data type is quantative but scale type do not support quantative', () => {
213225
expect(scaleType({type: ScaleType.TIME}, 'color', {type: 'quantitative'}, 'point')).toEqual(ScaleType.LINEAR);
214226
});

0 commit comments

Comments
 (0)
Please sign in to comment.