zigbee-herdsman
Version:
An open source Zigbee gateway solution with node.js.
126 lines • 5.8 kB
JavaScript
;
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