Working with time zones
This doc describes what do you need to do if you want to add time zone support to your chart.
Backgroundβ
By default, lightweight-charts
doesn't support time zones of any kind, just because JavaScript doesn't have an API to do that.
Things that the library uses internally includes an API to:
- Format a date
- Get a date and/or time parts of a date object (year, month, day, hours, etc)
Out of the box we could rely on 2 APIs:
And even if to format a date we could (and we do) use Date
object with its toLocaleString
method (and we could even pass a timeZone
field as an option),
but how about date/time field?
All to solve this it seems that the only solution we have is Date
's getters, e.g. getHours
. Here we could use 2 APIs:
- UTC-based methods like
getUTCHours
to get the date/time in UTC - Client-based methods like
getHours
to get the date/time in a local (for the client) time zone
As you can see we just unable to get date/time parts in desired time zone without using custom libraries (like date-fns
) out of the box.
Because of this we decided not to handle time zones in the library. The library treats all dates and times as UTC internally.
But don't worry - it's easy to add time-zone support in your own code!
How to add time zone support to your chartβ
TL;DR - time for every bar should be "corrected" by a time zone offset.
The only way to do this is to change a time in your data.
As soon as the library relies on UTC-based methods, you could change a time of your data item so in UTC it could be as it is in desired time zone.
Let's consider an example.
Lets say you have a bar with time 2021-01-01T10:00:00.000Z
(a string representation is just for better readability).
And you want to display your chart in Europe/Moscow
time zone.
According to tz database, for Europe/Moscow
time zone a time offset at this time is UTC+03:00
, i.e. +3 hours (pay attention that you cannot use the same offset all the time, because of DST and many other things!).
By this means, the time for Europe/Moscow
is 2021-01-01 13:00:00.000
(so basically you want to display this time over the UTC one).
To display your chart in the Europe/Moscow
time zone you would need to adjust the time of your data by +3 hours. So 2021-01-01T10:00:00.000Z
would become 2021-01-01T13:00:00.000Z
.
Note that due a time zone offset the date could be changed as well (not only time part).
This looks tricky, but hopefully you need to implement it once and then just forget this ever happened π
Date
solutionβ
One of possible solutions (and looks like the most simplest one) is to use approach from this answer on StackOverflow:
// you could use this function to convert all your times to required time zone
function timeToTz(originalTime, timeZone) {
const zonedDate = new Date(new Date(originalTime * 1000).toLocaleString('en-US', { timeZone }));
return zonedDate.getTime() / 1000;
}
Note about converting to a "local" time zoneβ
If you don't need to work with time zones in general, but only needs to support a client time zone (i.e. local), you could use the following trick:
function timeToLocal(originalTime) {
const d = new Date(originalTime * 1000);
return Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds()) / 1000;
}
date-fns-tz
solutionβ
You could also achieve the result by using date-fns-tz
library in the following way:
import { utcToZonedTime } from 'date-fns-tz';
function timeToTz(originalTime, timeZone) {
const zonedDate = utcToZonedTime(new Date(originalTime * 1000), timeZone);
return zonedDate.getTime() / 1000;
}
tzdata
solutionβ
If you have lots of data items and the performance of other solutions doesn't fit your requirements you could try to implement more complex solution by using raw tzdata
.
The better performance could be achieved with this approach because:
- you don't need to parse dates every time you want to get an offset so you could use lowerbound algorithm (which is
O(log N)
) to find an offset of very first data point quickly - after you found an offset, you go through all data items and check whether an offset should be changed or not to the next one (based on a time of the next time shift)
Why we didn't implement it in the libraryβ
Date
solution is quite slow (in our tests it took more than 20 seconds for 100k points)- Albeit
date-fns-tz
solution is a bit faster that the solution withDate
but it is still very slow (~17-18 seconds for 100k points) and additionally it requires to add another set of dependencies to the package tzdata
solution requires to increase the size of the library by more than 31kB min.gz (which is almost the size of the whole library!)
Keep in mind that time zones feature is not an issue for everybody so this is up to you to decide whether you want/need to support it or not and so far we don't want to sacrifice performance/package size for everybody by this feature.
Note about converting business daysβ
If you're using a business day for your time (either object or string representation), for example because of DWM nature of your data, most likely you shouldn't convert that time to a zoned one, because this time represents a day.