Enables optional use of the timezone set in Advanced Settings in queries (#34602)

* Adds time_zone to query

* Adds dateFormatTZ to kuery query

Removes comments

* Adds defaults for the dateFormatTZ to the function signatures

* Adds tests for date match in kuery

Modifies test

* Adds a test for get_es_query_config

* Adds test for get timezone from settings utility method

* Adds tests for modified range method

Adds config param test to node_types/functions

code clean up

* resolves initial PR comments

* Refactors build_es_query test

* Refactors get_time_zone_from_settings test

* Uses spys to test that the config is passed down to children in ast toElasticsearchQuery

* removes default config nulls

* Deletes sinon.spy tests in kuery

* removes moment.setDefault from __tests__/get_timezone_from_settings.js
This commit is contained in:
Christiane (Tina) Heiligers 2019-04-08 14:18:09 -07:00 committed by GitHub
parent 50fab1aea3
commit 95f93e5f81
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 402 additions and 42 deletions

View file

@ -11,7 +11,8 @@
"kbn:watch": "node scripts/build --source-maps --watch"
},
"dependencies": {
"lodash": "npm:@elastic/lodash@3.10.1-kibana1"
"lodash": "npm:@elastic/lodash@3.10.1-kibana1",
"moment-timezone": "^0.5.14"
},
"devDependencies": {
"@babel/cli": "^7.2.3",

View file

@ -103,6 +103,36 @@ describe('build query', function () {
expect(result).to.eql(expectedResult);
});
it('should use the default time zone set in the Advanced Settings in queries and filters', function () {
const queries = [
{ query: '@timestamp:"2019-03-23T13:18:00"', language: 'kuery' },
{ query: '@timestamp:"2019-03-23T13:18:00"', language: 'lucene' }
];
const filters = [
{ match_all: {}, meta: { type: 'match_all' } }
];
const config = {
allowLeadingWildcards: true,
queryStringOptions: {},
ignoreFilterIfFieldNotInIndex: false,
dateFormatTZ: 'Africa/Johannesburg',
};
const expectedResult = {
bool: {
must: [
decorateQuery(luceneStringToDsl('@timestamp:"2019-03-23T13:18:00"'), config.queryStringOptions, config.dateFormatTZ),
{ match_all: {} }
],
filter: [toElasticsearchQuery(fromKueryExpression('@timestamp:"2019-03-23T13:18:00"'), indexPattern, config)],
should: [],
must_not: [],
}
};
const result = buildEsQuery(indexPattern, queries, filters, config);
expect(result).to.eql(expectedResult);
});
});
});

View file

@ -29,4 +29,9 @@ describe('Query decorator', function () {
const decoratedQuery = decorateQuery({ query_string: { query: '*' } }, { analyze_wildcard: true });
expect(decoratedQuery).to.eql({ query_string: { query: '*', analyze_wildcard: true } });
});
it('should add a default of a time_zone parameter if one is provided', function () {
const decoratedQuery = decorateQuery({ query_string: { query: '*' } }, { analyze_wildcard: true }, 'America/Phoenix');
expect(decoratedQuery).to.eql({ query_string: { query: '*', analyze_wildcard: true, time_zone: 'America/Phoenix' } });
});
});

View file

@ -60,6 +60,31 @@ describe('build query', function () {
);
});
it('should accept a specific date format for a kuery query into an ES query in the bool\'s filter clause', function () {
const queries = [{ query: '@timestamp:"2018-04-03T19:04:17"', language: 'kuery' }];
const expectedESQueries = queries.map(query => {
return toElasticsearchQuery(fromKueryExpression(query.query), indexPattern, { dateFormatTZ: 'America/Phoenix' });
});
const result = buildQueryFromKuery(indexPattern, queries, true, 'America/Phoenix');
expect(result.filter).to.eql(expectedESQueries);
});
it('should gracefully handle date queries when no date format is provided', function () {
const queries = [{ query: '@timestamp:"2018-04-03T19:04:17Z"', language: 'kuery' }];
const expectedESQueries = queries.map(query => {
return toElasticsearchQuery(fromKueryExpression(query.query), indexPattern);
});
const result = buildQueryFromKuery(indexPattern, queries, true);
expect(result.filter).to.eql(expectedESQueries);
});
});
});

View file

@ -66,4 +66,22 @@ describe('build query', function () {
});
it('should accept a date format in the decorated queries and combine that into the bool\'s must clause', function () {
const queries = [
{ query: 'foo:bar', language: 'lucene' },
{ query: 'bar:baz', language: 'lucene' },
];
const dateFormatTZ = 'America/Phoenix';
const expectedESQueries = queries.map(
(query) => {
return decorateQuery(luceneStringToDsl(query.query), {}, dateFormatTZ);
}
);
const result = buildQueryFromLucene(queries, {}, dateFormatTZ);
expect(result.must).to.eql(expectedESQueries);
});
});

View file

@ -0,0 +1,66 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import expect from '@kbn/expect';
import { getEsQueryConfig } from '../get_es_query_config';
const config = {
get(item) {
return config[item];
},
'query:allowLeadingWildcards': {
allowLeadingWildcards: true,
},
'query:queryString:options': {
queryStringOptions: {},
},
'courier:ignoreFilterIfFieldNotInIndex': {
ignoreFilterIfFieldNotInIndex: true,
},
'dateFormat:tz': {
dateFormatTZ: 'Browser',
},
};
describe('getEsQueryConfig', function () {
it('should return the parameters of an Elasticsearch query config requested', function () {
const result = getEsQueryConfig(config);
const expected = {
allowLeadingWildcards: {
allowLeadingWildcards: true,
},
dateFormatTZ: {
dateFormatTZ: 'Browser',
},
ignoreFilterIfFieldNotInIndex: {
ignoreFilterIfFieldNotInIndex: true,
},
queryStringOptions: {
queryStringOptions: {},
},
};
expect(result).to.eql(expected);
expect(result).to.have.keys(
'allowLeadingWildcards',
'dateFormatTZ',
'ignoreFilterIfFieldNotInIndex',
'queryStringOptions'
);
});
});

View file

@ -28,6 +28,7 @@ import { buildQueryFromLucene } from './from_lucene';
* @param filters - a filter object or array of filter objects
* @param config - an objects with query:allowLeadingWildcards and query:queryString:options UI
* settings in form of { allowLeadingWildcards, queryStringOptions }
* config contains dateformat:tz
*/
export function buildEsQuery(
indexPattern,
@ -37,15 +38,15 @@ export function buildEsQuery(
allowLeadingWildcards: false,
queryStringOptions: {},
ignoreFilterIfFieldNotInIndex: false,
dateFormatTZ: null,
}) {
queries = Array.isArray(queries) ? queries : [queries];
filters = Array.isArray(filters) ? filters : [filters];
const validQueries = queries.filter((query) => has(query, 'query'));
const queriesByLanguage = groupBy(validQueries, 'language');
const kueryQuery = buildQueryFromKuery(indexPattern, queriesByLanguage.kuery, config.allowLeadingWildcards);
const luceneQuery = buildQueryFromLucene(queriesByLanguage.lucene, config.queryStringOptions);
const kueryQuery = buildQueryFromKuery(indexPattern, queriesByLanguage.kuery, config.allowLeadingWildcards, config.dateFormatTZ);
const luceneQuery = buildQueryFromLucene(queriesByLanguage.lucene, config.queryStringOptions, config.dateFormatTZ);
const filterQuery = buildQueryFromFilters(filters, indexPattern, config.ignoreFilterIfFieldNotInIndex);
return {

View file

@ -18,16 +18,22 @@
*/
import _ from 'lodash';
import { getTimeZoneFromSettings } from '../utils/get_time_zone_from_settings';
/**
* Decorate queries with default parameters
* @param query object
* @param queryStringOptions query:queryString:options from UI settings
* @param dateFormatTZ dateFormat:tz from UI settings
* @returns {object}
*/
export function decorateQuery(query, queryStringOptions) {
export function decorateQuery(query, queryStringOptions, dateFormatTZ = null) {
if (_.has(query, 'query_string.query')) {
_.extend(query.query_string, queryStringOptions);
if (dateFormatTZ) {
_.defaults(query.query_string, { time_zone: getTimeZoneFromSettings(dateFormatTZ) });
}
}
return query;

View file

@ -19,7 +19,7 @@
import { fromLegacyKueryExpression, fromKueryExpression, toElasticsearchQuery, nodeTypes } from '../kuery';
export function buildQueryFromKuery(indexPattern, queries = [], allowLeadingWildcards) {
export function buildQueryFromKuery(indexPattern, queries = [], allowLeadingWildcards, dateFormatTZ = null) {
const queryASTs = queries.map(query => {
try {
return fromKueryExpression(query.query, { allowLeadingWildcards });
@ -32,12 +32,12 @@ export function buildQueryFromKuery(indexPattern, queries = [], allowLeadingWild
throw Error('OutdatedKuerySyntaxError');
}
});
return buildQuery(indexPattern, queryASTs);
return buildQuery(indexPattern, queryASTs, { dateFormatTZ });
}
function buildQuery(indexPattern, queryASTs) {
function buildQuery(indexPattern, queryASTs, config = null) {
const compoundQueryAST = nodeTypes.function.buildNode('and', queryASTs);
const kueryQuery = toElasticsearchQuery(compoundQueryAST, indexPattern);
const kueryQuery = toElasticsearchQuery(compoundQueryAST, indexPattern, config);
return {
must: [],
filter: [],

View file

@ -21,10 +21,10 @@ import _ from 'lodash';
import { decorateQuery } from './decorate_query';
import { luceneStringToDsl } from './lucene_string_to_dsl';
export function buildQueryFromLucene(queries, queryStringOptions) {
export function buildQueryFromLucene(queries, queryStringOptions, dateFormatTZ = null) {
const combinedQueries = _.map(queries, (query) => {
const queryDsl = luceneStringToDsl(query.query);
return decorateQuery(queryDsl, queryStringOptions);
return decorateQuery(queryDsl, queryStringOptions, dateFormatTZ);
});
return {

View file

@ -21,5 +21,6 @@ export function getEsQueryConfig(config) {
const allowLeadingWildcards = config.get('query:allowLeadingWildcards');
const queryStringOptions = config.get('query:queryString:options');
const ignoreFilterIfFieldNotInIndex = config.get('courier:ignoreFilterIfFieldNotInIndex');
return { allowLeadingWildcards, queryStringOptions, ignoreFilterIfFieldNotInIndex };
const dateFormatTZ = config.get('dateFormat:tz');
return { allowLeadingWildcards, queryStringOptions, ignoreFilterIfFieldNotInIndex, dateFormatTZ };
}

View file

@ -24,6 +24,7 @@ import indexPatternResponse from '../../../__fixtures__/index_pattern_response.j
// Helpful utility allowing us to test the PEG parser by simply checking for deep equality between
// the nodes the parser generates and the nodes our constructor functions generate.
function fromLegacyKueryExpressionNoMeta(text) {
return ast.fromLegacyKueryExpression(text, { includeMetadata: false });
}
@ -416,6 +417,14 @@ describe('kuery AST API', function () {
expect(ast.toElasticsearchQuery(unknownTypeNode)).to.eql(expected);
});
it('should return the given node type\'s ES query representation including a time zone parameter when one is provided', function () {
const config = { dateFormatTZ: 'America/Phoenix' };
const node = nodeTypes.function.buildNode('is', '@timestamp', '"2018-04-03T19:04:17"');
const expected = nodeTypes.function.toElasticsearchQuery(node, indexPattern, config);
const result = ast.toElasticsearchQuery(node, indexPattern, config);
expect(result).to.eql(expected);
});
});
describe('doesKueryExpressionHaveLuceneSyntaxError', function () {

View file

@ -51,15 +51,19 @@ function fromExpression(expression, parseOptions = {}, parse = parseKuery) {
return parse(expression, parseOptions);
}
// indexPattern isn't required, but if you pass one in, we can be more intelligent
// about how we craft the queries (e.g. scripted fields)
export function toElasticsearchQuery(node, indexPattern) {
/**
* @params {String} indexPattern
* @params {Object} config - contains the dateFormatTZ
*
* IndexPattern isn't required, but if you pass one in, we can be more intelligent
* about how we craft the queries (e.g. scripted fields)
*/
export function toElasticsearchQuery(node, indexPattern, config = {}) {
if (!node || !node.type || !nodeTypes[node.type]) {
return toElasticsearchQuery(nodeTypes.function.buildNode('and', []));
}
return nodeTypes[node.type].toElasticsearchQuery(node, indexPattern);
return nodeTypes[node.type].toElasticsearchQuery(node, indexPattern, config);
}
export function doesKueryExpressionHaveLuceneSyntaxError(expression) {

View file

@ -23,7 +23,6 @@ import { nodeTypes } from '../../node_types';
import * as ast from '../../ast';
import indexPatternResponse from '../../../__fixtures__/index_pattern_response.json';
let indexPattern;
const childNode1 = nodeTypes.function.buildNode('is', 'machine.os', 'osx');
@ -57,8 +56,6 @@ describe('kuery functions', function () {
[childNode1, childNode2].map((childNode) => ast.toElasticsearchQuery(childNode, indexPattern))
);
});
});
});
});

View file

@ -199,6 +199,52 @@ describe('kuery functions', function () {
expect(result.bool.should[0]).to.have.key('script');
});
it('should support date fields without a dateFormat provided', function () {
const expected = {
bool: {
should: [
{
range: {
'@timestamp': {
gte: '2018-04-03T19:04:17',
lte: '2018-04-03T19:04:17',
}
}
}
],
minimum_should_match: 1
}
};
const node = nodeTypes.function.buildNode('is', '@timestamp', '"2018-04-03T19:04:17"');
const result = is.toElasticsearchQuery(node, indexPattern);
expect(result).to.eql(expected);
});
it('should support date fields with a dateFormat provided', function () {
const config = { dateFormatTZ: 'America/Phoenix' };
const expected = {
bool: {
should: [
{
range: {
'@timestamp': {
gte: '2018-04-03T19:04:17',
lte: '2018-04-03T19:04:17',
time_zone: 'America/Phoenix',
}
}
}
],
minimum_should_match: 1
}
};
const node = nodeTypes.function.buildNode('is', '@timestamp', '"2018-04-03T19:04:17"');
const result = is.toElasticsearchQuery(node, indexPattern, config);
expect(result).to.eql(expected);
});
});
});
});

View file

@ -23,7 +23,6 @@ import { nodeTypes } from '../../node_types';
import * as ast from '../../ast';
import indexPatternResponse from '../../../__fixtures__/index_pattern_response.json';
let indexPattern;
const childNode = nodeTypes.function.buildNode('is', 'extension', 'jpg');
@ -32,7 +31,6 @@ describe('kuery functions', function () {
describe('not', function () {
beforeEach(() => {
indexPattern = indexPatternResponse;
});
@ -56,6 +54,7 @@ describe('kuery functions', function () {
expect(result.bool).to.only.have.keys('must_not');
expect(result.bool.must_not).to.eql(ast.toElasticsearchQuery(childNode, indexPattern));
});
});
});
});

View file

@ -23,7 +23,6 @@ import { nodeTypes } from '../../node_types';
import * as ast from '../../ast';
import indexPatternResponse from '../../../__fixtures__/index_pattern_response.json';
let indexPattern;
const childNode1 = nodeTypes.function.buildNode('is', 'machine.os', 'osx');
@ -33,11 +32,11 @@ describe('kuery functions', function () {
describe('or', function () {
beforeEach(() => {
indexPattern = indexPatternResponse;
});
describe('buildNodeParams', function () {
it('arguments should contain the unmodified child nodes', function () {

View file

@ -22,7 +22,6 @@ import * as range from '../range';
import { nodeTypes } from '../../node_types';
import indexPatternResponse from '../../../__fixtures__/index_pattern_response.json';
let indexPattern;
describe('kuery functions', function () {
@ -136,6 +135,52 @@ describe('kuery functions', function () {
expect(result.bool.should[0]).to.have.key('script');
});
it('should support date fields without a dateFormat provided', function () {
const expected = {
bool: {
should: [
{
range: {
'@timestamp': {
gt: '2018-01-03T19:04:17',
lt: '2018-04-03T19:04:17',
}
}
}
],
minimum_should_match: 1
}
};
const node = nodeTypes.function.buildNode('range', '@timestamp', { gt: '2018-01-03T19:04:17', lt: '2018-04-03T19:04:17' });
const result = range.toElasticsearchQuery(node, indexPattern);
expect(result).to.eql(expected);
});
it('should support date fields with a dateFormat provided', function () {
const config = { dateFormatTZ: 'America/Phoenix' };
const expected = {
bool: {
should: [
{
range: {
'@timestamp': {
gt: '2018-01-03T19:04:17',
lt: '2018-04-03T19:04:17',
time_zone: 'America/Phoenix',
}
}
}
],
minimum_should_match: 1
}
};
const node = nodeTypes.function.buildNode('range', '@timestamp', { gt: '2018-01-03T19:04:17', lt: '2018-04-03T19:04:17' });
const result = range.toElasticsearchQuery(node, indexPattern, config);
expect(result).to.eql(expected);
});
});
});
});

View file

@ -25,13 +25,13 @@ export function buildNodeParams(children) {
};
}
export function toElasticsearchQuery(node, indexPattern) {
export function toElasticsearchQuery(node, indexPattern, config) {
const children = node.arguments || [];
return {
bool: {
filter: children.map((child) => {
return ast.toElasticsearchQuery(child, indexPattern);
return ast.toElasticsearchQuery(child, indexPattern, config);
})
}
};

View file

@ -23,6 +23,7 @@ import * as literal from '../node_types/literal';
import * as wildcard from '../node_types/wildcard';
import { getPhraseScript } from '../../filters';
import { getFields } from './utils/get_fields';
import { getTimeZoneFromSettings } from '../../utils/get_time_zone_from_settings';
export function buildNodeParams(fieldName, value, isPhrase = false) {
if (_.isUndefined(fieldName)) {
@ -35,19 +36,16 @@ export function buildNodeParams(fieldName, value, isPhrase = false) {
const fieldNode = typeof fieldName === 'string' ? ast.fromLiteralExpression(fieldName) : literal.buildNode(fieldName);
const valueNode = typeof value === 'string' ? ast.fromLiteralExpression(value) : literal.buildNode(value);
const isPhraseNode = literal.buildNode(isPhrase);
return {
arguments: [fieldNode, valueNode, isPhraseNode],
};
}
export function toElasticsearchQuery(node, indexPattern) {
export function toElasticsearchQuery(node, indexPattern = null, config = {}) {
const { arguments: [ fieldNameArg, valueArg, isPhraseArg ] } = node;
const fieldName = ast.toElasticsearchQuery(fieldNameArg);
const value = !_.isUndefined(valueArg) ? ast.toElasticsearchQuery(valueArg) : valueArg;
const type = isPhraseArg.value ? 'phrase' : 'best_fields';
if (fieldNameArg.value === null) {
if (valueArg.type === 'wildcard') {
return {
@ -67,7 +65,6 @@ export function toElasticsearchQuery(node, indexPattern) {
}
const fields = indexPattern ? getFields(fieldNameArg, indexPattern) : [];
// If no fields are found in the index pattern we send through the given field name as-is. We do this to preserve
// the behaviour of lucene on dashboards where there are panels based on different index patterns that have different
// fields. If a user queries on a field that exists in one pattern but not the other, the index pattern without the
@ -116,6 +113,22 @@ export function toElasticsearchQuery(node, indexPattern) {
}
}];
}
/*
If we detect that it's a date field and the user wants an exact date, we need to convert the query to both >= and <= the value provided to force a range query. This is because match and match_phrase queries do not accept a timezone parameter.
dateFormatTZ can have the value of 'Browser', in which case we guess the timezone using moment.tz.guess.
*/
else if (field.type === 'date') {
const timeZoneParam = config.dateFormatTZ ? { time_zone: getTimeZoneFromSettings(config.dateFormatTZ) } : {};
return [...accumulator, {
range: {
[field.name]: {
gte: value,
lte: value,
...timeZoneParam,
},
}
}];
}
else {
const queryType = type === 'phrase' ? 'match_phrase' : 'match';
return [...accumulator, {
@ -134,3 +147,4 @@ export function toElasticsearchQuery(node, indexPattern) {
};
}

View file

@ -25,12 +25,12 @@ export function buildNodeParams(child) {
};
}
export function toElasticsearchQuery(node, indexPattern) {
export function toElasticsearchQuery(node, indexPattern, config) {
const [ argument ] = node.arguments;
return {
bool: {
must_not: ast.toElasticsearchQuery(argument, indexPattern)
must_not: ast.toElasticsearchQuery(argument, indexPattern, config)
}
};
}

View file

@ -25,13 +25,13 @@ export function buildNodeParams(children) {
};
}
export function toElasticsearchQuery(node, indexPattern) {
export function toElasticsearchQuery(node, indexPattern, config) {
const children = node.arguments || [];
return {
bool: {
should: children.map((child) => {
return ast.toElasticsearchQuery(child, indexPattern);
return ast.toElasticsearchQuery(child, indexPattern, config);
}),
minimum_should_match: 1,
},

View file

@ -22,6 +22,7 @@ import { nodeTypes } from '../node_types';
import * as ast from '../ast';
import { getRangeScript } from '../../filters';
import { getFields } from './utils/get_fields';
import { getTimeZoneFromSettings } from '../../utils/get_time_zone_from_settings';
export function buildNodeParams(fieldName, params) {
params = _.pick(params, 'gt', 'lt', 'gte', 'lte', 'format');
@ -35,7 +36,7 @@ export function buildNodeParams(fieldName, params) {
};
}
export function toElasticsearchQuery(node, indexPattern) {
export function toElasticsearchQuery(node, indexPattern = null, config = {}) {
const [ fieldNameArg, ...args ] = node.arguments;
const fields = indexPattern ? getFields(fieldNameArg, indexPattern) : [];
const namedArgs = extractArguments(args);
@ -60,7 +61,17 @@ export function toElasticsearchQuery(node, indexPattern) {
script: getRangeScript(field, queryParams),
};
}
else if (field.type === 'date') {
const timeZoneParam = config.dateFormatTZ ? { time_zone: getTimeZoneFromSettings(config.dateFormatTZ) } : {};
return {
range: {
[field.name]: {
...queryParams,
...timeZoneParam,
}
}
};
}
return {
range: {
[field.name]: queryParams

View file

@ -31,7 +31,6 @@ describe('kuery node types', function () {
let indexPattern;
beforeEach(() => {
indexPattern = indexPatternResponse;
});

View file

@ -21,8 +21,8 @@ import _ from 'lodash';
import { functions } from '../functions';
export function buildNode(functionName, ...functionArgs) {
const kueryFunction = functions[functionName];
const kueryFunction = functions[functionName];
if (_.isUndefined(kueryFunction)) {
throw new Error(`Unknown function "${functionName}"`);
}
@ -47,8 +47,8 @@ export function buildNodeWithArgumentNodes(functionName, argumentNodes) {
};
}
export function toElasticsearchQuery(node, indexPattern) {
export function toElasticsearchQuery(node, indexPattern, config = {}) {
const kueryFunction = functions[node.function];
return kueryFunction.toElasticsearchQuery(node, indexPattern);
return kueryFunction.toElasticsearchQuery(node, indexPattern, config);
}

View file

@ -0,0 +1,36 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import expect from '@kbn/expect';
import { getTimeZoneFromSettings } from '../get_time_zone_from_settings';
describe('get timezone from settings', function () {
it('should return the config timezone if the time zone is set', function () {
const result = getTimeZoneFromSettings('America/Chicago');
expect(result).to.eql('America/Chicago');
});
it('should return the system timezone if the time zone is set to "Browser"', function () {
const result = getTimeZoneFromSettings('Browser');
expect(result).to.not.equal('Browser');
});
});

View file

@ -0,0 +1,28 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import moment from 'moment-timezone';
const detectedTimezone = moment.tz.guess();
export function getTimeZoneFromSettings(dateFormatTZ) {
if (dateFormatTZ === 'Browser') {
return detectedTimezone;
}
return dateFormatTZ;
}

View file

@ -0,0 +1,20 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
export * from './get_time_zone_from_settings';