@devexperts/dxcharts-lite 2.3.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chart/bootstrap.js +4 -3
- package/dist/chart/canvas/canvas-bounds-container.js +5 -3
- package/dist/chart/canvas/cursor.handler.js +2 -2
- package/dist/chart/components/chart/chart-area-pan.handler.js +3 -3
- package/dist/chart/components/chart/chart.component.d.ts +6 -3
- package/dist/chart/components/chart/chart.component.js +18 -7
- package/dist/chart/components/chart/chart.model.d.ts +1 -2
- package/dist/chart/components/chart/chart.model.js +2 -3
- package/dist/chart/components/cross_tool/types/cross-and-labels.drawer.js +4 -2
- package/dist/chart/components/high_low/high-low.drawer.js +9 -2
- package/dist/chart/components/highlights/highlights.drawer.js +1 -1
- package/dist/chart/components/pane/pane.component.js +6 -3
- package/dist/chart/components/volumes/volumes.drawer.js +1 -1
- package/dist/chart/components/x_axis/time/parser/time-formats-matchers.functions.js +1 -1
- package/dist/chart/components/x_axis/time/parser/time-formats.model.d.ts +1 -1
- package/dist/chart/components/x_axis/time/x-axis-weights.functions.js +2 -2
- package/dist/chart/components/x_axis/time/x-axis-weights.generator.js +6 -7
- package/dist/chart/components/x_axis/x-axis-labels.generator.d.ts +11 -3
- package/dist/chart/components/x_axis/x-axis-labels.generator.js +47 -19
- package/dist/chart/components/x_axis/x-axis-time-labels.drawer.js +0 -4
- package/dist/chart/components/x_axis/x-axis.component.js +7 -11
- package/dist/chart/components/y_axis/price_labels/last-candle-labels.provider.js +5 -5
- package/dist/chart/components/y_axis/price_labels/price-label.drawer.js +21 -22
- package/dist/chart/components/y_axis/y-axis-labels.drawer.d.ts +18 -6
- package/dist/chart/components/y_axis/y-axis-labels.drawer.js +23 -12
- package/dist/chart/components/y_axis/y-axis-scale.handler.d.ts +4 -0
- package/dist/chart/components/y_axis/y-axis-scale.handler.js +13 -6
- package/dist/chart/components/y_axis/y-axis.drawer.js +1 -1
- package/dist/chart/drawers/chart-background.drawer.d.ts +2 -3
- package/dist/chart/drawers/chart-background.drawer.js +16 -22
- package/dist/chart/drawers/data-series-drawers/candle-series-wrapper.js +1 -1
- package/dist/chart/drawers/data-series.drawer.d.ts +0 -2
- package/dist/chart/drawers/data-series.drawer.js +1 -6
- package/dist/chart/drawers/ht-data-series.drawer.js +1 -1
- package/dist/chart/inputhandlers/hover-producer.component.d.ts +1 -1
- package/dist/chart/model/compare-series-hover.d.ts +1 -1
- package/dist/chart/model/compare-series-hover.js +5 -0
- package/dist/chart/model/data-series.model.js +1 -1
- package/dist/chart/model/hit-test-canvas.model.js +2 -2
- package/dist/chart/model/scale.model.d.ts +3 -1
- package/dist/chart/model/scale.model.js +23 -4
- package/dist/chart/model/scaling/viewport.model.d.ts +2 -0
- package/dist/chart/model/scaling/viewport.model.js +13 -4
- package/dist/chart/model/time-zone.model.d.ts +0 -14
- package/dist/chart/model/time-zone.model.js +13 -33
- package/dist/chart/utils/canvas/canvas-drawing-functions.utils.d.ts +12 -1
- package/dist/chart/utils/canvas/canvas-drawing-functions.utils.js +16 -1
- package/dist/chart/utils/canvas/canvas-text-functions.utils.d.ts +3 -2
- package/dist/chart/utils/canvas/canvas-text-functions.utils.js +8 -3
- package/dist/chart/utils/math.utils.d.ts +1 -0
- package/dist/chart/utils/math.utils.js +3 -0
- package/dist/chart/utils/timezone.utils.d.ts +13 -0
- package/dist/chart/utils/timezone.utils.js +48 -0
- package/dist/dxchart.min.js +6 -6
- package/package.json +1 -2
|
@@ -92,6 +92,8 @@ export declare abstract class ViewportModel extends ChartBaseElement implements
|
|
|
92
92
|
start: number;
|
|
93
93
|
end: number;
|
|
94
94
|
}>;
|
|
95
|
+
protected doActivate(): void;
|
|
96
|
+
protected doDeactivate(): void;
|
|
95
97
|
/**
|
|
96
98
|
* Converts a unit value to pixels based on the current zoom level and xStart value.
|
|
97
99
|
* @param {Unit} unit - The unit value to be converted to pixels.
|
|
@@ -52,6 +52,13 @@ export class ViewportModel extends ChartBaseElement {
|
|
|
52
52
|
})), distinctUntilChanged((p, c) => p.start === c.start && p.end === c.end), share());
|
|
53
53
|
}
|
|
54
54
|
//endregion
|
|
55
|
+
doActivate() {
|
|
56
|
+
super.doActivate();
|
|
57
|
+
}
|
|
58
|
+
doDeactivate() {
|
|
59
|
+
super.doDeactivate();
|
|
60
|
+
this.changed.complete();
|
|
61
|
+
}
|
|
55
62
|
//region conversion methods
|
|
56
63
|
/**
|
|
57
64
|
* Converts a unit value to pixels based on the current zoom level and xStart value.
|
|
@@ -75,12 +82,13 @@ export class ViewportModel extends ChartBaseElement {
|
|
|
75
82
|
* @returns {Pixel} - The pixel value of the given unit value in the Y-axis.
|
|
76
83
|
*/
|
|
77
84
|
toY(unit) {
|
|
85
|
+
const bounds = this.getBounds();
|
|
78
86
|
if (this.inverseY) {
|
|
79
|
-
return
|
|
87
|
+
return bounds.y + unitToPixels(unit - this.yStart, this.zoomY);
|
|
80
88
|
}
|
|
81
89
|
else {
|
|
82
90
|
// inverse by default because canvas calculation [0,0] point starts from top-left corner
|
|
83
|
-
return
|
|
91
|
+
return bounds.y + bounds.height - unitToPixels(unit - this.yStart, this.zoomY);
|
|
84
92
|
}
|
|
85
93
|
}
|
|
86
94
|
/**
|
|
@@ -106,13 +114,14 @@ export class ViewportModel extends ChartBaseElement {
|
|
|
106
114
|
* @returns {void}
|
|
107
115
|
*/
|
|
108
116
|
fromY(px) {
|
|
109
|
-
const
|
|
117
|
+
const bounds = this.getBounds();
|
|
118
|
+
const normalizedPx = px - bounds.y;
|
|
110
119
|
if (this.inverseY) {
|
|
111
120
|
return pixelsToUnits(normalizedPx + unitToPixels(this.yStart, this.zoomY), this.zoomY);
|
|
112
121
|
}
|
|
113
122
|
else {
|
|
114
123
|
// inverse by default because canvas calculation [0,0] point starts from top-left corner
|
|
115
|
-
return pixelsToUnits(
|
|
124
|
+
return pixelsToUnits(bounds.height - normalizedPx + unitToPixels(this.yStart, this.zoomY), this.zoomY);
|
|
116
125
|
}
|
|
117
126
|
}
|
|
118
127
|
//endregion
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
|
4
4
|
* If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
5
|
*/
|
|
6
|
-
import { getTimezoneOffset as getTimezoneOffsetDateFnsTz } from 'date-fns-tz';
|
|
7
6
|
import { Observable } from 'rxjs';
|
|
8
7
|
import { DateFormatter, FullChartConfig } from '../chart.config';
|
|
9
8
|
import { DateTimeFormatter, DateTimeFormatterFactory } from './date-time.formatter';
|
|
@@ -13,8 +12,6 @@ export interface TimeZone {
|
|
|
13
12
|
readonly name: string;
|
|
14
13
|
readonly utcOffset: string;
|
|
15
14
|
}
|
|
16
|
-
export declare const memoizedTZOffset: typeof getTimezoneOffsetDateFnsTz;
|
|
17
|
-
export declare const getTimezoneOffset: (timezone: string, time: Timestamp) => number;
|
|
18
15
|
export declare class TimeZoneModel {
|
|
19
16
|
private config;
|
|
20
17
|
private timeZoneChangedSubject;
|
|
@@ -50,16 +47,5 @@ export declare class TimeZoneModel {
|
|
|
50
47
|
getFormatterFactory(): DateTimeFormatterFactory;
|
|
51
48
|
private formatterCache;
|
|
52
49
|
getDateTimeFormatter(format: string): DateTimeFormatter;
|
|
53
|
-
/**
|
|
54
|
-
* Calculates the offset of a given timezone from the local timezone.
|
|
55
|
-
* @private
|
|
56
|
-
* @param {string} timezone - The timezone to calculate the offset for.
|
|
57
|
-
*/
|
|
58
|
-
private getOffset;
|
|
59
|
-
/**
|
|
60
|
-
* Gets the timezone offset value in milliseconds
|
|
61
|
-
* @param {string} timezone name
|
|
62
|
-
* @returns {function(time:Number):Date}
|
|
63
|
-
*/
|
|
64
50
|
tzOffset(timezone: string): (time: number) => Date;
|
|
65
51
|
}
|
|
@@ -3,28 +3,20 @@
|
|
|
3
3
|
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
|
4
4
|
* If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
5
|
*/
|
|
6
|
-
import { getTimezoneOffset as getTimezoneOffsetDateFnsTz } from 'date-fns-tz';
|
|
7
6
|
import { ReplaySubject } from 'rxjs';
|
|
8
|
-
import { memoize } from '../utils/performance/memoize.utils';
|
|
9
7
|
import { dateTimeFormatterFactory } from './date-time.formatter';
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const localOffset = new Date(time).getTimezoneOffset() * 60 * 1000;
|
|
14
|
-
return localOffset + memoizedTZOffset(timezone, time);
|
|
15
|
-
};
|
|
8
|
+
import { getTimezoneOffset } from '../utils/timezone.utils';
|
|
9
|
+
// 1 hour in milliseconds
|
|
10
|
+
const timeMultiplier = 60 * 1000;
|
|
16
11
|
export class TimeZoneModel {
|
|
17
12
|
constructor(config) {
|
|
18
13
|
this.config = config;
|
|
19
14
|
this.timeZoneChangedSubject = new ReplaySubject();
|
|
20
|
-
this.currentTzOffset = (time) =>
|
|
15
|
+
this.currentTzOffset = (time) => {
|
|
16
|
+
// we must pass time here, because we can have daylight saving time, otherwise we will get wrong offset
|
|
17
|
+
return getTimezoneOffset(this.config.timezone, time) + new Date(time).getTimezoneOffset() * timeMultiplier;
|
|
18
|
+
};
|
|
21
19
|
this.formatterCache = {};
|
|
22
|
-
/**
|
|
23
|
-
* Calculates the offset of a given timezone from the local timezone.
|
|
24
|
-
* @private
|
|
25
|
-
* @param {string} timezone - The timezone to calculate the offset for.
|
|
26
|
-
*/
|
|
27
|
-
this.getOffset = (timezone, time) => getTimezoneOffset(timezone, time);
|
|
28
20
|
this.dateTimeFormatterFactory = this.initFormatterFactory(this.config.dateFormatter);
|
|
29
21
|
}
|
|
30
22
|
/**
|
|
@@ -87,28 +79,16 @@ export class TimeZoneModel {
|
|
|
87
79
|
}
|
|
88
80
|
return this.formatterCache[format];
|
|
89
81
|
}
|
|
90
|
-
/**
|
|
91
|
-
* Gets the timezone offset value in milliseconds
|
|
92
|
-
* @param {string} timezone name
|
|
93
|
-
* @returns {function(time:Number):Date}
|
|
94
|
-
*/
|
|
95
82
|
tzOffset(timezone) {
|
|
96
|
-
// we must pass time here, because we can have daylight saving time, otherwise we will get wrong offset
|
|
97
|
-
const localOffset = (time) => -new Date(time).getTimezoneOffset() * timeMultiplier;
|
|
98
|
-
let offset;
|
|
99
83
|
if (!timezone) {
|
|
100
|
-
|
|
84
|
+
return time => new Date(time);
|
|
101
85
|
}
|
|
102
86
|
else {
|
|
103
|
-
//
|
|
104
|
-
|
|
87
|
+
// In JS Date object is created with local tz offset,
|
|
88
|
+
// so we have to subtract localOffset from current time
|
|
89
|
+
return time => {
|
|
90
|
+
return new Date(time + getTimezoneOffset(timezone, time) + new Date(time).getTimezoneOffset() * timeMultiplier);
|
|
91
|
+
};
|
|
105
92
|
}
|
|
106
|
-
// In JS Date object is created with local tz offset,
|
|
107
|
-
// so we have to subtract localOffset from current time
|
|
108
|
-
return time => {
|
|
109
|
-
return new Date(+time + offset(time) - localOffset(time));
|
|
110
|
-
};
|
|
111
93
|
}
|
|
112
94
|
}
|
|
113
|
-
// 1 hour in milliseconds
|
|
114
|
-
const timeMultiplier = 60 * 1000;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
5
|
*/
|
|
6
6
|
import { YAxisAlign } from '../../chart.config';
|
|
7
|
+
import { Bounds } from '../../model/bounds.model';
|
|
7
8
|
/**
|
|
8
9
|
* Draws a rounded rectangle on a canvas context
|
|
9
10
|
* @param {CanvasRenderingContext2D} ctx - The canvas context to draw on
|
|
@@ -57,7 +58,7 @@ export declare function avoidAntialiasing(ctx: CanvasRenderingContext2D, draw: (
|
|
|
57
58
|
* @param {{x: number, y: number}} a - The first point of the rectangle.
|
|
58
59
|
* @param {{x: number, y: number}} b - The second point of the rectangle.
|
|
59
60
|
* @returns {void}
|
|
60
|
-
|
|
61
|
+
|
|
61
62
|
*/
|
|
62
63
|
export declare function fillRect(ctx: CanvasRenderingContext2D, a: {
|
|
63
64
|
x: number;
|
|
@@ -66,3 +67,13 @@ export declare function fillRect(ctx: CanvasRenderingContext2D, a: {
|
|
|
66
67
|
x: number;
|
|
67
68
|
y: number;
|
|
68
69
|
}): void;
|
|
70
|
+
/**
|
|
71
|
+
* Sets clipping region for a Canvas 2D context according to the provided bounds.
|
|
72
|
+
*
|
|
73
|
+
* @param {CanvasRenderingContext2D} ctx - The canvas 2D context which will get the new clip region.
|
|
74
|
+
* @param {object} bounds - The bounds of the clipping region. Object containing x, y, width and height properties.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* clipToBounds(ctx, {x: 50, y: 50, width: 100, height: 100});
|
|
78
|
+
*/
|
|
79
|
+
export declare const clipToBounds: (ctx: CanvasRenderingContext2D, bounds: Bounds) => void;
|
|
@@ -138,7 +138,7 @@ export function avoidAntialiasing(ctx, draw) {
|
|
|
138
138
|
* @param {{x: number, y: number}} a - The first point of the rectangle.
|
|
139
139
|
* @param {{x: number, y: number}} b - The second point of the rectangle.
|
|
140
140
|
* @returns {void}
|
|
141
|
-
|
|
141
|
+
|
|
142
142
|
*/
|
|
143
143
|
export function fillRect(ctx, a, b) {
|
|
144
144
|
const x = Math.min(a.x, b.x) + 0.5;
|
|
@@ -147,3 +147,18 @@ export function fillRect(ctx, a, b) {
|
|
|
147
147
|
const h = Math.abs(a.y - b.y);
|
|
148
148
|
ctx.fillRect(x, y, w, h);
|
|
149
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Sets clipping region for a Canvas 2D context according to the provided bounds.
|
|
152
|
+
*
|
|
153
|
+
* @param {CanvasRenderingContext2D} ctx - The canvas 2D context which will get the new clip region.
|
|
154
|
+
* @param {object} bounds - The bounds of the clipping region. Object containing x, y, width and height properties.
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* clipToBounds(ctx, {x: 50, y: 50, width: 100, height: 100});
|
|
158
|
+
*/
|
|
159
|
+
export const clipToBounds = (ctx, bounds) => {
|
|
160
|
+
ctx.beginPath();
|
|
161
|
+
ctx.rect(bounds.x, bounds.y, bounds.width, bounds.height);
|
|
162
|
+
ctx.clip();
|
|
163
|
+
ctx.closePath();
|
|
164
|
+
};
|
|
@@ -30,9 +30,10 @@ export declare function prepareTextForFill(ctx: CanvasRenderingContext2D, proper
|
|
|
30
30
|
/**
|
|
31
31
|
* Calculates the line height of a text based on the font size of the provided CanvasRenderingContext2D.
|
|
32
32
|
* @param {CanvasRenderingContext2D} ctx - The CanvasRenderingContext2D object used to draw the text.
|
|
33
|
+
* @param includeBaseLine
|
|
33
34
|
* @returns {number} The calculated line height of the text.
|
|
34
35
|
*/
|
|
35
|
-
export declare function getTextLineHeight(ctx: CanvasRenderingContext2D): number;
|
|
36
|
+
export declare function getTextLineHeight(ctx: CanvasRenderingContext2D, includeBaseLine?: boolean): number;
|
|
36
37
|
/**
|
|
37
38
|
* Calculates text bounds [textWidth, textHeight, lineHeight]
|
|
38
39
|
* @param ctx
|
|
@@ -53,7 +54,7 @@ export declare function getTextLines(text: string): string[];
|
|
|
53
54
|
* @param {number} y - The y-coordinate of the starting position of the text.
|
|
54
55
|
* @param {CanvasTextProperties} properties - An object containing properties for the text, such as font size, style, and alignment.
|
|
55
56
|
* @returns {void}
|
|
56
|
-
|
|
57
|
+
|
|
57
58
|
*/
|
|
58
59
|
export declare function drawText(ctx: CanvasRenderingContext2D, lines: string[], x: number, y: number, properties: CanvasTextProperties): void;
|
|
59
60
|
/**
|
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
* If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
5
|
*/
|
|
6
6
|
import Color from 'color';
|
|
7
|
+
/**
|
|
8
|
+
* Baseline Height in Project
|
|
9
|
+
*/
|
|
10
|
+
const BASELINE = 1.33;
|
|
7
11
|
/**
|
|
8
12
|
* Sets the font, fill style and text alignment of a canvas context based on the provided properties.
|
|
9
13
|
* @param {CanvasRenderingContext2D} ctx - The canvas context to modify.
|
|
@@ -32,9 +36,10 @@ export function prepareTextForFill(ctx, properties) {
|
|
|
32
36
|
/**
|
|
33
37
|
* Calculates the line height of a text based on the font size of the provided CanvasRenderingContext2D.
|
|
34
38
|
* @param {CanvasRenderingContext2D} ctx - The CanvasRenderingContext2D object used to draw the text.
|
|
39
|
+
* @param includeBaseLine
|
|
35
40
|
* @returns {number} The calculated line height of the text.
|
|
36
41
|
*/
|
|
37
|
-
export function getTextLineHeight(ctx) {
|
|
42
|
+
export function getTextLineHeight(ctx, includeBaseLine = true) {
|
|
38
43
|
const textSizeMatch = ctx.font.match(/(\d+.)?\d+(px|pt)/gi);
|
|
39
44
|
let textSize = '10px';
|
|
40
45
|
if (textSizeMatch && textSizeMatch.length) {
|
|
@@ -46,7 +51,7 @@ export function getTextLineHeight(ctx) {
|
|
|
46
51
|
textSize = textSizeMatch[0];
|
|
47
52
|
}
|
|
48
53
|
}
|
|
49
|
-
return parseInt(textSize, 10) *
|
|
54
|
+
return includeBaseLine ? parseInt(textSize, 10) * BASELINE : parseInt(textSize, 10);
|
|
50
55
|
}
|
|
51
56
|
/**
|
|
52
57
|
* Calculates text bounds [textWidth, textHeight, lineHeight]
|
|
@@ -80,7 +85,7 @@ export function getTextLines(text) {
|
|
|
80
85
|
* @param {number} y - The y-coordinate of the starting position of the text.
|
|
81
86
|
* @param {CanvasTextProperties} properties - An object containing properties for the text, such as font size, style, and alignment.
|
|
82
87
|
* @returns {void}
|
|
83
|
-
|
|
88
|
+
|
|
84
89
|
*/
|
|
85
90
|
export function drawText(ctx, lines, x, y, properties) {
|
|
86
91
|
ctx.save();
|
|
@@ -12,6 +12,7 @@ export declare class MathUtils {
|
|
|
12
12
|
static compare(a: number, b: number, eps: number): number;
|
|
13
13
|
static isZero(a: number): boolean;
|
|
14
14
|
static cutNumber(value: number, amountToCut: NumberFormatLabels, zeros?: number): string;
|
|
15
|
+
static isExponential(a: number): boolean;
|
|
15
16
|
}
|
|
16
17
|
/**
|
|
17
18
|
* Checks if first and second number are differs by specified times
|
|
@@ -75,6 +75,9 @@ export class MathUtils {
|
|
|
75
75
|
};
|
|
76
76
|
return cutMap[amountToCut](value).toFixed(zeros) + amountToCut;
|
|
77
77
|
}
|
|
78
|
+
static isExponential(a) {
|
|
79
|
+
return /\de(\-|\+)\d/.test(a.toString());
|
|
80
|
+
}
|
|
78
81
|
}
|
|
79
82
|
/**
|
|
80
83
|
* Checks if first and second number are differs by specified times
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2019 - 2023 Devexperts Solutions IE Limited
|
|
3
|
+
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
|
4
|
+
* If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
|
+
*/
|
|
6
|
+
export declare function getDateTimeFormat(timeZone: string): Intl.DateTimeFormat;
|
|
7
|
+
/**
|
|
8
|
+
* Calulates provided timezone offset.
|
|
9
|
+
* @param timeZone - timezone as IANA string ('Asia/Amman', 'Europe/Amsterdam')
|
|
10
|
+
* @param timestamp - timestamp as number (1701251319717)
|
|
11
|
+
* Returns offset from UTC
|
|
12
|
+
*/
|
|
13
|
+
export declare const getTimezoneOffset: (timeZone: string, timestamp?: number) => number;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2019 - 2023 Devexperts Solutions IE Limited
|
|
3
|
+
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
|
4
|
+
* If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Get a cached Intl.DateTimeFormat instance for the IANA `timeZone`. This can be used
|
|
8
|
+
* to get deterministic local date/time output according to the `en-US` locale which
|
|
9
|
+
* can be used to extract local time parts as necessary.
|
|
10
|
+
* Returns the [year, month, day, hour, minute] tokens of the provided timezone
|
|
11
|
+
*/
|
|
12
|
+
const dateTimeFormatCache = {};
|
|
13
|
+
export function getDateTimeFormat(timeZone) {
|
|
14
|
+
if (!dateTimeFormatCache[timeZone]) {
|
|
15
|
+
// New browsers use `hourCycle`, IE and Chrome <73 does not support it and uses `hour12`
|
|
16
|
+
dateTimeFormatCache[timeZone] = new Intl.DateTimeFormat('en-US', {
|
|
17
|
+
hourCycle: 'h23',
|
|
18
|
+
timeZone,
|
|
19
|
+
year: 'numeric',
|
|
20
|
+
month: 'numeric',
|
|
21
|
+
day: '2-digit',
|
|
22
|
+
hour: '2-digit',
|
|
23
|
+
minute: '2-digit',
|
|
24
|
+
second: '2-digit',
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return dateTimeFormatCache[timeZone];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Calulates provided timezone offset.
|
|
31
|
+
* @param timeZone - timezone as IANA string ('Asia/Amman', 'Europe/Amsterdam')
|
|
32
|
+
* @param timestamp - timestamp as number (1701251319717)
|
|
33
|
+
* Returns offset from UTC
|
|
34
|
+
*/
|
|
35
|
+
export const getTimezoneOffset = (timeZone, timestamp = Date.now()) => {
|
|
36
|
+
const formatter = getDateTimeFormat(timeZone);
|
|
37
|
+
const dateString = formatter.format(timestamp);
|
|
38
|
+
// exec() returns [, fMonth, fDay, fYear, fHour, fMinute]
|
|
39
|
+
const tokens = /(\d+)\/(\d+)\/(\d+),? (\d+):(\d+)/.exec(dateString);
|
|
40
|
+
if (tokens) {
|
|
41
|
+
const asUTC = Date.UTC(+tokens[3], +tokens[1] - 1, +tokens[2], +tokens[4] % 24, +tokens[5], 0);
|
|
42
|
+
let asTimezone = timestamp;
|
|
43
|
+
const over = asTimezone % 1000;
|
|
44
|
+
asTimezone -= over >= 0 ? over : 1000 + over;
|
|
45
|
+
return asUTC - asTimezone;
|
|
46
|
+
}
|
|
47
|
+
return 0;
|
|
48
|
+
};
|