Overblog Folge diesem Blog
Edit post Administration Create my blog
Blog von Olaf Helper

Datum in ISO Kalenderwoche (1)

29. März 2009 , Geschrieben von Olaf Helper Veröffentlicht in #T-SQL

Im Bereich der Waren-, Lagerwirtschaft und Disposition arbeitet man in der Regel eher mit der Kalenderwoche statt mit einem fixen Datum; natürlich bevorzugt im der Kalenderwoche nach ISO Norm.

Bis einschließlich dem Microsoft SQL Server 2005 gab es kein Bordmittel zum Umrechnen in die ISO-KW, man fand aber in der BOL unter dem Thema CREATE FUNCTION (Transact-SQL)“ im Beispiel A. ein Script für eine benutzerdefinierte Funktion „ISOWeek“, mit der man umrechnen kann.

Im MS SQL Server 2008 hat die ISO Woche nun auch im Standard Einzug gehalten mit dem Parameter ISO_WEEK / ISOWK / ISOWW für die Funktion DATEPART:

 
SELECT
DATEPART(ISOWK,
  CAST('20060101' AS datetime)) AS IsoWeek 


Was mich aber an den Funktionen stört, ist das das Jahr nicht mitgeliefert bzw. das ich bei dem Beispiel mit dem 2006-01-01 darauf achten muss, das die resultierende KW 52 ins Jahr 2005 fällt, nicht in 2006.

Ich habe mir deshalb auf Basis der ISOWeek Funktion eine eigene erstellt, die es mir im Format YYYYWW als Integer zurückliefert. Das auf splitten in ein separates Jahr / Woche ist dann leicht.

 SELECT dbo.fnDate2ISOYearWeek(GetDate()) / 100 AS Jahr, 
  dbo.fnDate2ISOYearWeek(GetDate()) % 100 AS Woche  


Hier das Anlage-Script für die Funktion
fnDate2ISOYearWeek

 
-- Alte Version ggf. DROPen
 IF OBJECT_ID (N'dbo.fnDate2ISOYearWeek', N'FN') IS NOT NULL 
  DROP FUNCTION dbo.fnDate2ISOYearWeek; 
 GO 
   
 CREATE FUNCTION dbo.fnDate2ISOYearWeek(@Date datetime) 
  RETURNS int 
 AS 
 -- fnDate2ISOYearWeek - Stand 23.03.2009 
 -- Liefert zu einem Datum die Kalenderwoche und -Jahr 
 -- nach ISO im Format YYYYWW als Integer  
 BEGIN 
  DECLARE @ISOweek smallint, 
   @ISOYear int;  
  SET @ISOYear = DATEPART(yy, @Date); 
  SET @ISOweek = DATEPART(wk, @DATE) + 1 
  - DATEPART(wk, CAST(@ISOYear as CHAR(4)) + '0104'); 
   
  -- Sonderfall: Erste KW <> 4 Tage 
  IF (@ISOweek = 0)  
  BEGIN 
  SET @ISOYear = @ISOYear - 1; 
  SET @ISOweek = DATEPART(wk, CAST(@ISOYear AS CHAR(4)) 
  + '12'  
  + CAST(24 + DATEPART(DAY, @DATE) AS CHAR(2)) 
  ) + 1 
  - DATEPART(wk, CAST(@ISOYear as CHAR(4)) + '0104') 
  + 1; 
  END; 
   
  --Sonderfall: Letzte 3 Tage falen in erste KW Folgejahr 
  IF DATEPART(mm, @DATE) = 12  
  AND DATEPART(dd, @DATE) - DATEPART(dw, @DATE) >= 28 
  BEGIN 
  SET @ISOweek = 1; 
  SET @ISOYear = @ISOYear + 1; 
  END; 
   
  RETURN(@ISOYear * 100 + @ISOweek); 
 END; 
 GO 
   
 -- Unit-Test mit Sonder- und Normalfällen 
 SELECT Datum, DATENAME(dw, Datum) AS WochenTag, 
   DATENAME(isowk, Datum) AS InternalIsoWeek,  
  dbo.ISOweek(Datum) AS MSIsoWeek, 
  dbo.fnDate2ISOYearWeek(Datum) AS myIsoYearWeek 
 FROM (SELECT CAST('20060101' as datetime) AS DATUM UNION 
  SELECT CAST('20060102' as datetime) AS DATUM UNION 
  SELECT CAST('20061231' as datetime) AS DATUM UNION 
  SELECT CAST('20050101' as datetime) AS DATUM UNION 
  SELECT CAST('20050102' as datetime) AS DATUM UNION 
  SELECT CAST('20050103' as datetime) AS DATUM  
  ) AS DatumsQuelle 
 ORDER BY DATUM 

Diesen Post teilen

Repost 0

Kommentiere diesen Post

CH 01/27/2012 11:48

Hallo,
diese selbstgebaute Funktion funktioniert auf den ersten Anhieb ziemlich gut, nur der Versuch die Ergebnisse nach dieser Spalte zu gruppieren läuft gegen die Pumpe (GROUP BY) ist für mich so
spontan nicht gut nach zu voll ziehen.

Flugs 12/10/2010 11:57


Funktioniert leider nicht korrekt. Beispiel:
31.12.2009 und 01.01.2010 beide Tage fallen in KW 53/2009. die Funktion liefert aber KW 52 und KW 53.


tanimania 12/30/2014 14:53

Die Prozedur sollte m.E. allerdings ohne vorheriges Setzen der DATEFIRST-Einstellung korrekt funktionieren. Ich würde sie deshalb um folgende Zeilen erweitern:

DECLARE @datepartWeekDay INTEGER = DATEPART(dw, @DATE)
SET @datepartWeekDay = @datepartWeekDay + @@DATEFIRST - 1
IF (@datepartWeekDay > 7)
SET @datepartWeekDay = @datepartWeekDay - 7

Die Variable @datepartWeekDay sollte man nun im letzten Block statt des Ausdrucks "DATEPART(dw, @DATE)" verwenden.

Olaf Helper 02/15/2011 20:03



Hallo,


die Funktion funktioniert einwandfrei. Wenn Du Dich etwas mit dem Thema beschäftigst wird Du feststellen, dass das Ergebnis natürlich von den User Setting abhängt, genauer von SET DateFirst, also
an welchem Tag den die Woche beginnt und somit auch wann die erste ISO Woche ist.