ISO 8601 Kalenderwoche in Power Query berechnen

January 9, 2021
Denis Selimovic
Power Query / Mcomment 3Created with Sketch Beta.4 comments

This post is also available in: Englisch


Bereits letzte Woche haben wir uns mit der Thematik der korrekten Berechnung der ISO Kalenderwoche in DAX beschäftigt. Da die Frage aufkam, wie man dies in Power Query lösen könnte, werde ich diese Woche darauf eingehen. Für die Problemstellung der Kalenderwochen möchte ich auf den Post von letzter Woche verweisen.

Berechnung der US-Kalenderwoche mit Date.WeekOfYear Funktion

Wie auch in DAX gibt es auch in Power Query bereits eine Funktion zur Berechnung der Kalenderwoche. Diese lautet Date.WeekOfYear und gibt das US-Format mit Wochenstart am Sonntag zurück. Mit optionalem Parameter wird die Kalenderwoche mit Wochenstart an einem Montag zurückgegeben. Die Syntax lautet folgendermaßen:

Date.WeekOfYear(#date(2021, 01, 01), Day.Monday)

Berechnung mit Power Query Funktion

Leider gibt es im Power Query keinen versteckten Parameter wie im DAX, daher müssen wir uns die Kalenderwoche berechnen. Allerdings hat Robert K. Bell bereits die größte Vorarbeit geleistet. Basierend auf seinem Code habe ich die Funktion etwas für unsere Zwecke abgeändert. Den folgenden Code müsst ihr einfach im Power Query in eine neue Query einfügen:

/*
based on https://en.wikipedia.org/wiki/ISO_week_date#Calculating_the_week_number_of_a_given_date

M / Power Query doesn't have a native ISO8601 Week Number function, and DAX's
`weeknum(x, 21)` doesn't give the correct ISO Week-Year.

homepage: https://gist.github.com/r-k-b/18d898e5eed786c9240e3804b167a5ca
*/

let
    getISO8601Week = (someDate as date) =>
        let
            getDayOfWeek = (d as date) =>
                let
                    result = 1 + Date.DayOfWeek(d, Day.Monday)
                in
                    result,

            getNaiveWeek = (inDate as date) =>
                let
                    // monday = 1, sunday = 7
                    weekday = getDayOfWeek(inDate),

                    weekdayOfJan4th = getDayOfWeek(#date(Date.Year(inDate), 1, 4)),

                    ordinal = Date.DayOfYear(inDate),

                    naiveWeek = Number.RoundDown(
                        (ordinal - weekday + 10) / 7
                    )
                in
                    naiveWeek,

            thisYear = Date.Year(someDate),

            priorYear = thisYear - 1,

            nwn = getNaiveWeek(someDate),

            lastWeekOfPriorYear =
                getNaiveWeek(#date(priorYear, 12, 28)),

            // http://stackoverflow.com/a/34092382/2014893
            lastWeekOfThisYear =
                getNaiveWeek(#date(thisYear, 12, 28)),

            weekYear =
                if
                    nwn < 1
                then
                    priorYear
                else
                    if
                        nwn > lastWeekOfThisYear
                    then
                        thisYear + 1
                    else
                        thisYear,

            weekNumber =
                if
                    nwn < 1
                then
                    lastWeekOfPriorYear
                else
                    if
                        nwn > lastWeekOfThisYear
                    then
                        1
                    else
                        nwn,

            week_dateString =
                Text.PadStart(
                    Text.From(
                        Number.RoundDown(weekNumber)
                    ),
                    2,
                    "0"
                )
        in
            weekNumber
in
    getISO8601Week

Danach müsst ihr die Funktion nur noch als neue Spalte mit dem Parameter Datum aufrufen und ihr habt die korrekte Berechnung der Kalenderwoche auch bereits im Power Query:

Berechnung der Kalenderwoche im US-Format mit Sonntag und Montag als Start der Woche sowie im ISO-Format in Power Query
Berechnung der Kalenderwoche im US-Format mit Sonntag und Montag als Start der Woche sowie im ISO-Format in Power Query

Die Beispiel-Datei kann hier heruntergeladen werden: