I have found out that the code doesn't work properly on the day of DST switch if your locale doesn't have Sunday as the first weekday.
The fix is simple, just tell the function Date.DayOfWeek, what the first day of week is: Date.DayOfWeek(LastDayOfMarch, Day.Sunday)
I've already fixed that on GitHub and here is the new code:
let
/**********************************************************
*
* Author: Michal Dvorak WITH(NOLOCK)
* Since: 20.07.2019
* Twitter: @nolockcz
*
* Source code: https://github.com/nolockcz/PowerQuery
*
*********************************************************/
StandardOffset = #duration(0, 1, 0, 0),
DaylightSavingTimeOffset = #duration(0, 2, 0, 0),
// get start and end of daylight saving time
// this code implements the rules of EU counties
// if it doesn't fill your expectations, visit https://en.wikipedia.org/wiki/Daylight_saving_time_by_country and implement your own function
fnDaylightSavingTimePeriod = (
now as datetime
) as record =>
let
// the daylight saving time starts on the last Sunday of March at 1am UTC
LastDayOfMarch = #date(Date.Year(now), 3, 31),
StartOfDaylightSavingTime = Date.AddDays(LastDayOfMarch, -Date.DayOfWeek(LastDayOfMarch, Day.Sunday)) & #time(1, 0, 0),
// the daylight saving time ends on the last Sunday in October at 1am UTC
LastDayOfOctober = #date(Date.Year(now), 10, 31),
EndOfDaylightSavingTime = Date.AddDays(LastDayOfOctober, -Date.DayOfWeek(LastDayOfOctober, Day.Sunday)) & #time(1, 0, 0)
in
[From = StartOfDaylightSavingTime, To = EndOfDaylightSavingTime],
// get a timestamp in UTC (with offset 00:00 all year long)
UtcNow = DateTimeZone.UtcNow(),
// convert UTC datetime with offset to datetime
UtcNowWithoutZone = DateTimeZone.RemoveZone(UtcNow),
// get daylight saving time period
DaylightSavingTimePeriod = fnDaylightSavingTimePeriod(UtcNowWithoutZone),
// convert UTC time to the local time with respect to current offset
LocalTimeWithOffset =
if UtcNowWithoutZone >= DaylightSavingTimePeriod[From] and UtcNowWithoutZone < DaylightSavingTimePeriod[To] then
DateTimeZone.SwitchZone(
UtcNow,
Duration.Hours(DaylightSavingTimeOffset),
Duration.Minutes(DaylightSavingTimeOffset)
)
else
DateTimeZone.SwitchZone(
UtcNow,
Duration.Hours(StandardOffset),
Duration.Minutes(StandardOffset)
),
// current date time without offset
LocalTime = DateTimeZone.RemoveZone(LocalTimeWithOffset),
// result table
Result = #table(
type table
[
#"UTC timestamp" = datetime,
#"UTC date" = date,
#"Local timestamp with offset" = datetimezone,
#"Local timestamp without offset" = datetime
],
{
{
UtcNowWithoutZone,
DateTime.Date(UtcNowWithoutZone),
LocalTimeWithOffset,
LocalTime
}
}
)
in
Result