UNPKG

zigbee-herdsman

Version:

An open source Zigbee gateway solution with node.js.

126 lines 5.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getTimeClusterAttributes = getTimeClusterAttributes; exports.clearCachedTimeData = clearCachedTimeData; const tz_1 = require("@date-fns/tz"); const OneJanuary2000 = new Date("January 01, 2000 00:00:00 UTC+00:00").getTime(); const OneDayInMilliseconds = 24 * 60 * 60 * 1000; const cachedTimeData = { timeZone: 0, dstStart: 0, dstEnd: 0, dstShift: 0, validUntilTime: 0, }; function timestampToZigbeeUtcTime(timestamp) { return timestamp === 0xffffffff ? timestamp : Math.round((timestamp - OneJanuary2000) / 1000); } function recalculateTimeData(currentDate) { const currentTime = currentDate.getTime(); const currentYear = currentDate.getUTCFullYear(); // Default values considering the time zone has no DST. let timeZoneDifferenceToUtc = currentDate.getTimezoneOffset() !== 0 ? currentDate.getTimezoneOffset() * -1 * 60 : 0; let dstStart = 0xffffffff; let dstEnd = 0xffffffff; let dstShift = 0; const validUntilTime = currentTime + OneDayInMilliseconds; const localTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone; const dstChangesThisYear = (0, tz_1.tzScan)(localTimeZone, { start: new Date(currentYear, 1), end: new Date(currentYear, 12), }); // Countries may leave/introduce DST, which isn't supported here. // Therefore, we always have to check that the returned number // of changes is exactly 2. const hasRegularDst = dstChangesThisYear.length === 2; if (hasRegularDst) { const isNorthernHemisphere = dstChangesThisYear[0].change > 0; if (isNorthernHemisphere) { // getTimezoneOffset() called before includes the DST // offset, so, we can't use it when dstShift !== 0. timeZoneDifferenceToUtc = dstChangesThisYear[1].offset * 60; dstStart = dstChangesThisYear[0].date.getTime(); // tzScan returns the first second on which a new shift has to be applied. // This is fine for dstStart, but dstEnd has to be the last second of the // DST period. Otherwise, the following equation copied from the ZCL spec // isn't met anymore: // // Local Time = Standard Time + DstShift (if DstStart <= Time <= DstEnd) // // Therefore, we have to remove one second on all dstEnd times below. dstEnd = dstChangesThisYear[1].date.getTime() - 1000; dstShift = dstChangesThisYear[0].change * 60; } else { const dstStartIsInPreviousYear = currentTime < dstChangesThisYear[0].date.getTime(); if (dstStartIsInPreviousYear) { const dstChangesLastYear = (0, tz_1.tzScan)(localTimeZone, { start: new Date(currentYear - 1, 1), end: new Date(currentYear - 1, 12), }); const hadRegularDstLastYear = dstChangesLastYear.length === 2; if (hadRegularDstLastYear) { timeZoneDifferenceToUtc = dstChangesThisYear[0].offset * 60; dstStart = dstChangesLastYear[1].date.getTime(); dstEnd = dstChangesThisYear[0].date.getTime() - 1000; dstShift = dstChangesLastYear[1].change * 60; } } else { const dstChangesNextYear = (0, tz_1.tzScan)(localTimeZone, { start: new Date(currentYear + 1, 1), end: new Date(currentYear + 1, 12), }); const hasRegularDstNextYear = dstChangesNextYear.length === 2; if (hasRegularDstNextYear) { timeZoneDifferenceToUtc = dstChangesThisYear[0].offset * 60; dstStart = dstChangesThisYear[1].date.getTime(); dstEnd = dstChangesNextYear[0].date.getTime() - 1000; dstShift = dstChangesThisYear[1].change * 60; } } } } cachedTimeData.timeZone = timeZoneDifferenceToUtc; cachedTimeData.dstStart = timestampToZigbeeUtcTime(dstStart); cachedTimeData.dstEnd = timestampToZigbeeUtcTime(dstEnd); cachedTimeData.dstShift = dstShift; cachedTimeData.validUntilTime = timestampToZigbeeUtcTime(validUntilTime); } function getTimeClusterAttributes() { const currentDate = new Date(); const currentZigbeeUtcTime = timestampToZigbeeUtcTime(currentDate.getTime()); if (currentZigbeeUtcTime >= cachedTimeData.validUntilTime) { recalculateTimeData(currentDate); } const standardTime = currentZigbeeUtcTime + cachedTimeData.timeZone; let localTime = standardTime; if (currentZigbeeUtcTime >= cachedTimeData.dstStart && currentZigbeeUtcTime <= cachedTimeData.dstEnd) { localTime = standardTime + cachedTimeData.dstShift; } return { time: currentZigbeeUtcTime, // Bit 0: Master clock // Bit 1: Not synchronized (as Master bit is 1) // Bit 2: Master for Time Zone and DST // Bit 3: Time synchronization SHOULD be superseded timeStatus: 0b1101, timeZone: cachedTimeData.timeZone, dstStart: cachedTimeData.dstStart, dstEnd: cachedTimeData.dstEnd, dstShift: cachedTimeData.dstShift, standardTime: standardTime, localTime: localTime, lastSetTime: currentZigbeeUtcTime, validUntilTime: cachedTimeData.validUntilTime, }; } /** used by tests */ function clearCachedTimeData() { cachedTimeData.timeZone = 0; cachedTimeData.dstStart = 0; cachedTimeData.dstEnd = 0; cachedTimeData.dstShift = 0; cachedTimeData.validUntilTime = 0; } //# sourceMappingURL=timeService.js.map