Kalender-algorithmen

Zeller

Um den Kalender nach Wochen und Monaten optisch zu gliedern, ist es erforderlich, dass der Wochentag für ein gegebenes Datum bestimmt werden kann. Die Gesetzmäßigkeiten des immerwährenden Kalenders wurde von Christoph Zeller 1885 zu einer mathematischen Formel zusammengefass. Diese Formael erlaubt es, für jedes Datum den Wochentag zu bestimmen,

          w = (r+[2,61 + M - 0,2] + J + [J/4] + [H/4] - 2 * H) % 7

          H ==> Jahrhundert (e.g.: 2000 --> 19 || 2010 --> 20)
          J ==> Jahreszahl innerhalb des Jahrhunderts (e.g.: 2010 --> 10 || 1999 --> 99)
          M ==> Monat (e.g.: März == 1 && Februar == 12)
          T ==> Tag
          W ==> Wochentag (e.g.: Sonntag --> 0 && Samstag --> 6s)
          [x] ==> Gaußsche Klammerfunktion (e.g.: [2,8] --> 2 || [-2,8] --> -3)

          Beispiel: Auf welchen Wochentag fällt der 1.Januar 1998?

          H = 19, J = 97 (altrömische Zeitrechung), M = 11 (altrömische Zeitrechung), T = 1
          fx(T, M, J, H)
          = 116 % 7
          = 4

          Ergebnis: Der 1. Januar 1998 ist ein Donnerstag.
using System;
class Zeller{
  public static void Main(){
    Console.WriteLine(GetZeller(27, 09, 2016));
    Console.WriteLine(GetZeller(01, 01, 1998));
  }
  #region Calender calculation
  public static string GetZell(int h)
  {
    switch (h)
    {
      case 0:
        return "Saturday";
      case 1:
        return "Sunday";
      case 2:
        return "Monday";
      case 3:
        return "Tuesday";
      case 4:
        return "Wednesday";
      case 5:
        return "Thursday";
      case 6:
        return "Friday";
      default:
        return "Error: Maybe wrong Input Format?";
    }
  }
  public static string GetZeller(byte dd, byte mm, int yyyy)
  {
     int h = 0;
     double q = dd, m = mm, y = yyyy, J = 0, K = 0;
     switch ((int)m)
     {
         case 1:
             m = 13; y--; break;
         case 2:
             m = 14; y--; break;
     }
     J = Math.Floor(y / 100);
     K = y - J * 100;
     h = (int)((q + Math.Floor(((m + 1) * 26) / 10) + K + Math.Floor(K / 4) + Math.Floor(J / 4) - 2 * J) % 7);
     return GetZell(h < 0 ? h + 7 : h);
  }
  #endregion
}

Robertson

Seit Zeller ist von verschiedenen Mathematikern und Astronomen eine ganze Reihe von weiteren Kalenderformeln aufgestellt worden. Sie benötigen alle bestimmte Monatskennzahlen, die auch noch davon abhängig sind, obein Schaltjahr vorliegt oder nicht. Einen einfachen Kalender-Algorithmus liefert die Formel von J.D. Robertson aus Collected Algorithms (CA) CACM 689 - R1. Er korrigierte damit die Fehler im Algorithmus 398 von R.A. Stone.

        robertson
        Zusicherung: Gültiges Datum T.M.J des Gregorianischen Kalenders
        A = M + 10
        B = [(M - 14) / 12] + J
        C = A - 12 [A / 13]
        D = [(13C - 1) / 5]
        E = [5 * (B % 100) / 4]
        W = (D + T + 77 + E + [B / 400] - 2 * [B / 100]) % 7
        Nachbedingung: Wochentag W in normaler Zählung
using System;
class Robertson{
  public static void Main(){
    Console.WriteLine(GetRobin(27, 09, 2016));
    Console.WriteLine(GetRobin(01, 01, 1998));
  }
  #region Calender calculation
  public static object GetRobin(byte day, byte month, int year){
    switch(GetRobinson(day, month, year)){
      case 0:
        return "Sunday";
      case 1:
        return "Monday";
      case 2:
        return "Tuesday";
      case 3:
        return "Wednesday";
      case 4:
        return "Thursday";
      case 5:
        return "Friday";
      case 6:
        return "Saturday";
      default:
        return "Could not convert given number to a String.";
    }
  }
  private static int GetRobinson(byte day, byte month, int year){
    int  lmon;
    int  mmon;
    lmon = month + 10;
    mmon = (month - 14) / 12 + year;
    return ((((13 * (lmon - (lmon /  13) *  12) - 1) / 5 + day + 77
              + 5 * (mmon - (mmon / 100) * 100) / 4
             + mmon / 400 - (mmon / 100) *   2)
             - 1) % 7 + 1
           );
  }
  #endregion
}

Julian Calendar

In der Astronomie und Raumfahrt verwendet man einen fortlaufenden Kalender, das sog. Julianische Datum. Damit lassen sich alle Ereignisse wie Sonnen bzw. Mond Finsternisse, Perihel - Durchgänge von Kometen, Sternbedeckungen usw. berechnen. Das Julianische Datum zählt die Tage seit 1.1.4713 v.Chr., dem fiktiven Beginn der ägyptischen Kalenderrechnung (sog. Scalinger-Ära) Für ein Datum des Gregorianischen Kalenders kann da Julianische Datum mit Hilfe des Verfahrens von H.F. Fliegel und T.C. van Fladern (A Machine Algorithm for Processing Calendar Dates, ACM 11, 657, 1968) berechnet werden.

        juldat (ConvertToJulian)
        Zusicherung: Gültiges Datum T.M.J des Gregorianischen Kalenders
        K = [(M - 14) / 12]
        L = J + K + 4800
        JD = T - 32075 + 1461 * [L/4] + 367 * [(M - 2 - 12 * K) / 12] - 3 * [(L + 100) / 400]
        Nachbedingung: Julianisches Datum JD

Der Julianische Kalender wurde von Julius Caesar eingeführt, und war in manchen teilen der welt noch weit bis ins 20. Jahrhundert gültig, im kirlichen Bereich teilweise noch bis heute. Er wird heute in der Wissenschaft rückwirkend auch für die Jahre vor dem wirken Caesars verwendet. Er wurde seit dem 16. Jahrhundert sukzessiv durch den Gregorianischen Kalender abgelöst.

Beim Julianischen Kalender ist zu beachten, dass es das Jahr 0 nicht gegeben hat; d.h. auf jahr 1

2nd Algorithm:

        juldat2 (ConvertToJulian2)
        Zusicherung: Gültiges Datum T.M.J
        GREG = 588829
        Wenn J < 0
          Dann J = J + 1
        Wenn M > 2
          Dann M = M + 1
          Sonst J = J -1,
                M = M + 13
        JD = [1461 * J / 4] + [153 * M / 5] + T + 1720995
        D = T + 31 * (M + 12 * J)
        Wenn D >= GREG
          Dann A = [J/100],
               JD = JD + 2 - A + [A/4]
        Nachbedingung: Julianisches Datum JD

Mit Hilfe des Julianischen Datums lassen sich bequem auch die Tagesdifferenz zwischen zwei Daten und auch der Wochentage bestimmen.

    using System;
    class JulCal{
      public static void Main(){
        Console.WriteLine(ConvertToJulian(27, 09, 2016));
        Console.WriteLine(ConvertToJulian(01, 01, 1998));
        Console.WriteLine(ConvertToJulian2(27, 09, 2016));
        Console.WriteLine(ConvertToJulian2(01, 01, 1998));
      }
      #region Julianischer Calender
      public static long ConvertToJulian(int day, int month, int year){
        var K = ((month-14)/12);
        var L = year+K+4800;
        var JD = day - 32075 + 1461 * (L / 4) + 367 * ((month-2-12*K) / 12) -3 * ((L+100)/400);
        return JD;
      }
      public static long ConvertToJulian2(int Day, int Month, int Year)
      {
        if (Month < 3)
        {
         Month = Month + 12;
         Year = Year - 1;
        }
        long JD = Day + (153 * Month - 457) / 5 + 365 * Year + (Year / 4) - (Year / 100) + (Year / 400) + 1721119;
        return JD;
      }
      #endregion
    }

Gregorian Calendar

Folgender Algorithmus gregdat bestimmt zu einem Julianischen Datum JD das dazugehörige Gregorianische Datum T.M.J und liefert damit die Umkehrung des Algorithmus juldat. Er stammt ebenfalls von FLiegel/van Fladern.

        gregdat (ConvertToGregorian)
        Zusicherung: JD ist Julianisches Datum
        L = JD + 68569
        N = [(4 * L) / 146097]
        L = L - [(146097 * N + 3) / 4]
        J = [4000(L + 1) / 1461001]
        L = L - 1461 * [J / 4] + 31
        M = [80L / 2447]
        T = L - [2447M / 80]
        L = [M / 11]
        M = M + 2 - 12L
        J = 100(N - 49) + L + J
        Nachbedingung: Gregorianisches Datum T.M.J

Für beliebige Daten gibt es eine Umkehrung zum Algotithmus juldat2:

        gregdat2 (ConvertToGregorian2)
        Zusicherung: JD ist Julianisches Datum
        GREG = 2299161
        JD = JD + 1
        Wenn JD < GREG
            Dann A = JD
            Sonst ALPHA = [(JD-1867216.25) / 36524.25],
                  A = JD + 1 + ALPHA - [ALPHA / 4]
        B = A + 1524
        C = [(B - 122.1) / 365.25]
        D = [1461 * C / 4]
        E = [(B - D) / 30.6001]
        T = (B - D) - [30.6001 * E] - 1
        Wenn E < 13.5
            Dann  M = E - 1
            Sonst M = E - 13
        Wenn M > 2.5
            Dann  J = C - 4716
            Sonst J = C - 4715
        Nachbedingung: Gregorianisches Datum T.M.J

Die in der astronomischen Literatur angegebenen Algorithmen liefern meist einen um 1 höheren Wert für das Julianische Datum, da bei den Astronomen das Julianische Datum bereits um Mittag wechselt. Die hier gegebenen Versionen entsprechen der Zählweise aus dem ACM

    using System;
    class Greg<T> {
      T Day;
      T Month;
      T Year;
      public Greg(T d, T m, T y){
        Day = d;
        Month = m;
        Year = y;
      }
      public override string ToString(){
        return Day+"."+Month+"."+Year;
      }
    }
    class GregCal{
      public static void Main(){
        Console.WriteLine(ConvertToGregorian(2423));
        Console.WriteLine(ConvertToGregorian(234234));
        Console.WriteLine(ConvertToGregorian2(53464574));
        Console.WriteLine(ConvertToGregorian2(5566456));
      }
      #region Julianischer Calender
      public static Greg<long> ConvertToGregorian(long JD){
        var L = JD+68569;
        var N = ((4*L)/146097);
        L = L - ((146097 * N + 3) / 4);
        var J = (4000*(L+1)/1461001);
        L = L - 1461 * (J / 4) +31;
        var M = (80*L/2447);
        var T = L - (2447M/80);
        L = (M / 11);
        M = M + 2 - 12 * L;
        J = 100*(N-49)+L+J;
        return new Greg<long>((long)T, (long)M, (long)J);
      }
      public static Greg<long> ConvertToGregorian2(long JD)
      {
        var GREG = 2299161;
        JD = JD+1;
        long A = 0;
        if (JD < GREG) {
          A = JD;
        } else {
          var ALPHA = ((JD-1867216.25f) / 36524.25f);
          A = (long)Math.Round(JD+1+ALPHA - (ALPHA / 4));
        }
        var B = A + 1524;
        var C = ((B-122.1f) / 365.25f);
        var D = (1461*C/4);
        var E = ((B-D)/30.6001f);
        var T = (B-D) - (30.6001f * E) -1;
        long M = 0;
        long J = 0;
        if (E < 13.5f) {
          M = (long)Math.Round(E - 1);
        } else {
          M = (long)Math.Round(E - 13);
        }
        if (M > 2.5){
          J = (long)Math.Round(C-4716);
        } else {
          J = (long)Math.Round(C - 4715);
        }
        return new Greg<long>((long)T, (long)M, (long)J);
      }
      #endregion
    }

Gauss

Das zeug mit den 2 Tabellen (M, N)

    using System;
    class Date{
      public int Day {get;set;}
      public int Month {get;set;}
      public int Year {get;set;}
      public Date(int d, int m, int y){
        Day = d;
        Month = m;
        Year = y;
      }
      public override string ToString(){
        return String.Format("Ostern is am: {0}.{1}.{2}", Day, Month, Year);
      }
    }
    class Gauss{
      public static void Main(){
        Console.WriteLine(GetGauss(2016));
        Console.WriteLine(GetGauss(1998));
      }
      private static int M(int yyyy){
        if (yyyy >= 1582 && yyyy <= 1699){
          return 22;
        } else if (yyyy >= 1700 && yyyy <= 1799){
          return 23;
        } else if (yyyy >= 1800 && yyyy <= 1899){
          return 23;
        } else if (yyyy >= 1900 && yyyy <= 2099){
          return 24;
        } else if (yyyy >= 2100 && yyyy <= 2199){
          return 24;
        } else if (yyyy >= 2200 && yyyy <= 2299){
          return 25;
        } else if (yyyy >= 2300 && yyyy <= 2399){
          return 26;
        } else if (yyyy >= 2400 && yyyy <= 2499){
          return 25;
        } else {
          return -1;
        }
      }
      private static int N(int yyyy){
        if (yyyy >= 1582 && yyyy <= 1699){
          return 2;
        } else if (yyyy >= 1700 && yyyy <= 1799){
          return 3;
        } else if (yyyy >= 1800 && yyyy <= 1899){
          return 4;
        } else if (yyyy >= 1900 && yyyy <= 2099){
          return 5;
        } else if (yyyy >= 2100 && yyyy <= 2199){
          return 6;
        } else if (yyyy >= 2200 && yyyy <= 2299){
          return 0;
        } else if (yyyy >= 2300 && yyyy <= 2399){
          return 1;
        } else if (yyyy >= 2400 && yyyy <= 2499){
          return 2;
        } else {
          return -1;
        }
      }
      public static Date GetGauss(int yyyy){
        int A = yyyy % 19;
        int B = yyyy % 4;
        int C = yyyy % 7;
        int D = (19*A + M(yyyy)) % 30;
        int E = (2*B + 4*C + 6*D + N(yyyy)) % 7;
        if (22+D+E > 31){
          if (D+E-9 == 26) {
              return new Date(19, 4, yyyy);
          } else if ((D+E-9) == 25 && D == 28 && A > 10) {
              return new Date(18, 4, yyyy);
          } else {
              return new Date((D+E-9), 4, yyyy);
          }
        } else {
            return new Date((22+D+E), 3, yyyy);
        }
      }
    }

DayOfYear

Für viele Zwecke benötigt man die Nummer eines Tages im laufenden Jahr. Dies macht der Algorithmus tagesnr (GetDayOfYear), er stammt ebenfalls von Robertson.

        Zusicherung: Gültiges Datum T.M.J des Gregorianischen Kalenders
        A = J % 4
        B = J % 100
        C = J % 400
        D = [(M + 10) / 13]
        E = T + [3055 * (M + 2) / 100] - 2 * D - 91
        N = E + (1 - [(A + 3) / 4] + [(B + 99) / 100] - [(C + 399) / 400]) * D
        Nachbedngung: N ist Tagesnummer vom T.M.J
    using System;
    class DOY{
      public static void Main(){
        Console.WriteLine(GetDayOfYear(12, 4, 2016));
        Console.WriteLine(GetDayOfYear(5, 7, 1998));
      }
      public static int GetDayOfYear(int Day, int Month, int Year){
        int A = Year % 4;
        int B = Year % 100;
        int C = Year % 400;
        int D = (int)((Month+10)/13);
        int E = Day + (int)(3055*(Month+2)/100) - 2*D - 91;
        int N = E+(1-(int)((A+3)/4)+(int)((B+99)/100)-(int)((C+399)/400))*D;
        return N;
      }
    }

DayOfYear to date

Zur umkehrung von tagesnr (GetDayOfYear) kann der Algorithmus tagimjahr (DOYtoDate.GetDate) von A. Stone (Tableless data Conversion, CA CACM 398) verwendet werden.

        Tag_im_Jahr
        Zusicherung: Tagesnummer N im Jahr J
        Wenn J % 4 = 0
          Dann  A = 1
          Sonst A = 0
        Wenn N > 59
          Dann  H = 1
          Sonst H = 0
        Wenn H + A > 0
          Dann  B = 2 - A
          Sonst B = 0
        C = N + B + 91
        M = [100C / 3055]
        T = C - [3055M / 100]
        M = M - 2
        Nachbedingung: Tag ist T.M.J mit Tagesnummer N
    using System;
    class DOYtoDate{
      public static void Main(){
        Console.WriteLine(GetDate(271, 2016));
        Console.WriteLine(GetDate(1, 1998));
      }
      public static int GetDate(int DayOfYear, int Year){
        int A = Year % 4 == 0 ? 1 : 0;
        int H = DayOfYear > 59 ? 1 : 0;
        int B = H+A > 0 ? 2-A : 0;
        int C = DayOfYear+B+91;
        int M = (int)(100*C/3055);
        int T = C - (int)(3055*M/100);
        int M = M -2;
        return new Date(T, M, Year);
      }
    }

Beirne

Schränkt man den Ostertermin auf die Jahre 1900-2099 ein, so kann der Gaußsche Algorithmus wesentlich vereinfacht werden. Der 1965 von T.H.O’Beirne Algorithmus lautet O’Beirne

Zusicherung: Jahr J 1900..2099 des Gregorianischen Kalenders

        N = J-1900
        A = N mod 19
        B = [(7A+1)/19]
        M = (11A+4-B) mod 29
        Q = [N/4]
        W = (N+Q+31-M) mod 7
        P = 25-M-W

        Ostersonntag ist der P. April oder der (P+31). März
    using System;
    class Beirne{
      public static void Main(){
        Console.WriteLine(GetBeirne(2016));
        Console.WriteLine(GetBeirne(1998));
      }
      public static Date GetBeirne(int yyyy){
        int N = yyyy - 1900;
        int A = N % 19;
        int B = (int)((7*A+1)/19);
        int M = (11*A+4-B) % 29;
        int Q = (int)(N/4);
        int W = (N+Q+31-M) % 7;
        int P = 25 - M - W;
        if (P > 31 || P < 0){
            return new Date(P+31, 2, yyyy);
        } else {
            return new Date(P, 4, yyyy);
        }
      }
    }

Stored Procedures

Speicher Kunde

    CREATE PROCEDURE sp_SpeicherKunde
    @KundeId = -1 OUTPUT,@Name vc(50),@Vorname vc(50),@Straße vc(100),@TelefonNummer vc(50),@Email vc(100),@Plz vc(5),@Ort vc(50),@Bezeichnung vc(5)
    AS
        DECLARE @PersonId int, @AnredeId int, @OrtId int;
        BEGIN TRANSACTION
        BEGIN TRY
    END
    ELSE
        SELECT @AnredeId = AnredeId FROM tblAnrede WHERE Bezeichnung = @Bezeichnung
        IF (@AnredeId = 0)
        BEGIN
            SELECT @AnredeId = ISNULL(MAX(OrtId)+1, 1) FROM tblAnrede
            INSERT INTO tblAnrede (AnredeId, Bezeichnung) VALUES (@AnredeId, @Bezeichnung)
        END
        SELECT @OrtId = Count(OrtId) FROM tblOrt WHERE Plz = @Plz AND Ort =  @Ort
        IF (@OrtId = 0)
        BEGIN
            SELECT @OrtId = ISNULL(MAX(OrtId)+1, 1) FROM tblOrt
            INSERT INTO tblOrt (OrtId, Plz, Ort) VALUES (@OrtId, @Plz, @Ort)
        END
        ELSE
            SELECT @OrtId = OrtId FROM tblOrt WHERE Plz = @Plz AND Ort = @Ort
            SELECT @PersonId = ISNULL(MAX(PersonId)+1, 1) FROM tblPerson
            INSERT INTO tblPerson (PersonId, AnredeId, [Name], Vorname, OrtId, Straße, TelefonNummer, Email) VALUES (@PersonId, @AnredeId, @Name, @Vorname, @OrtId, @Straße, @Telefonnummer, @Email)
            SELECT @KundeId = ISNULL(MAX(KundeId)+1, 1) FROM tblKunde
            INSERT INTO tblKunde (KundeId, PersonId) VALUES (@KundeId, @PersonId)
    END TRY
    BEGIN CATCH
        SELECT ERROR_NUMBER() AS ErrorNumber, ERROR_SEVERITY() AS ErrorServerity, ERROR_STATE() AS ErrorState, ERROR_PROCEDURE() AS ErrorProcedure, ERROR_LINE() AS ErrorLine, ERROR_MESSAGE() AS ErrorMessage;
        IF @@TRANCOUNT > 0
            ROLLBACK TRANSACTION;
    END CATCH
    IF @@TRANCOUNT > 0
        COMMIT TRANSACTION;
    END

Lese Mitarbeiter

    sp_LeseMitarbeiter
    CREATE Procedure sp_LeseAlleMitarbeiter
    @MitarbeiterId int
    AS
    BEGIN
        SET NOCOUNT ON;
        SELECT tbl_Anrede.Bezeichnung as Anrede, tbl_Person.Name ,tbl_Person.Vorname, tbl_Ort.Plz, tbl_Ort.Ort, tbl_Person.Straße, tbl_Person.Telefon, tbl_Person.Mail
        From tbl_Anrede INNER JOIN tbl_Person ON tbl_Anrede.AnredeId = tbl_Person.AnredeId INNER JOIN tbl_Mitarbeiter ON tbl_Person.PersonId = tbl_Mitarbeiter.PersonId INNER JOIN tbl_Ort ON tbl_Person.OrtId = tbl_Ort.OrtId
        WHERE tbl_Mitarbeiter.MitarbeiterId = @MitarbeiterId
    END

Lese Alle Mitarbeiter

    sp_LeseAlleMitarbeiter
    CREATE Procedure sp_LeseAlleMitarbeiter
    AS
    BEGIN
        SET NOCOUNT ON;
        SELECT tbl_Anrede.Bezeichnung as Anrede, tbl_Person.Name ,tbl_Person.Vorname, tbl_Ort.Plz, tbl_Ort.Ort, tbl_Person.Straße, tbl_Person.Telefon, tbl_Person.Mail
        From tbl_Anrede INNER JOIN tbl_Person ON tbl_Anrede.AnredeId = tbl_Person.AnredeId INNER JOIN tbl_Mitarbeiter ON tbl_Person.PersonId = tbl_Mitarbeiter.PersonId INNER JOIN tbl_Ort ON tbl_Person.OrtId = tbl_Ort.OrtId
    END

Speicher Mitarbeiter

    sp_SpeicherMitarbeiter
    CREATE PROCEDURE sp_SpeicherMitarbeiter
    @MitarbeiterId = -1 OUTPUT,@Name vc(50),@Vorname vc(50),@Straße vc(100),@TelefonNummer vc(50),@Email vc(100),@Plz vc(5),@Ort vc(50),@Bezeichnung vc(5)
    AS
        DECLARE @PersonId int, @AnredeId int, @OrtId int;
        BEGIN TRANSACTION
        BEGIN TRY
    END
    ELSE
        SELECT @AnredeId = AnredeId FROM tblAnrede WHERE Bezeichnung = @Bezeichnung
        IF (@AnredeId = 0)
        BEGIN
            SELECT @AnredeId = ISNULL(MAX(OrtId)+1, 1) FROM tblAnrede
            INSERT INTO tblAnrede (AnredeId, Bezeichnung) VALUES (@AnredeId, @Bezeichnung)
        END
        SELECT @OrtId = Count(OrtId) FROM tblOrt WHERE Plz = @Plz AND Ort =  @Ort
        IF (@OrtId = 0)
        BEGIN
            SELECT @OrtId = ISNULL(MAX(OrtId)+1, 1) FROM tblOrt
            INSERT INTO tblOrt (OrtId, Plz, Ort) VALUES (@OrtId, @Plz, @Ort)
        END
        ELSE
            SELECT @OrtId = OrtId FROM tblOrt WHERE Plz = @Plz AND Ort = @Ort
            SELECT @PersonId = ISNULL(MAX(PersonId)+1, 1) FROM tblPerson
            INSERT INTO tblPerson (PersonId, AnredeId, [Name], Vorname, OrtId, Straße, TelefonNummer, Email) VALUES (@PersonId, @AnredeId, @Name, @Vorname, @OrtId, @Straße, @Telefonnummer, @Email)
            SELECT @MitarbeiterId = ISNULL(MAX(MitarbeiterId)+1, 1) FROM tblMitarbeiter
            INSERT INTO tblMitarbeiter (MitarbeiterId, PersonId) VALUES (@MitarbeiterId, @PersonId)
    END TRY
    BEGIN CATCH
        SELECT ERROR_NUMBER() AS ErrorNumber, ERROR_SEVERITY() AS ErrorServerity, ERROR_STATE() AS ErrorState, ERROR_PROCEDURE() AS ErrorProcedure, ERROR_LINE() AS ErrorLine, ERROR_MESSAGE() AS ErrorMessage;
        IF @@TRANCOUNT > 0
            ROLLBACK TRANSACTION;
    END CATCH
    IF @@TRANCOUNT > 0
        COMMIT TRANSACTION;
    END

Using a Stored Procedure in C#

    SQLConnection conn = new SQLConnection(host);

    SQLCommand cmd = new SQLCommand("sp_speicherKunde", conn);
    cmd.CommandTyppe = CommandType.StoredProcedure;

    int KundeId;
    cmd.Parameters.Add(new SQLParameter("@KundeId", SqlDbType.Int));
    cmd.Parameter["@KundeId"].Direction = ParameterDirection.Output;
    cmd.Parameter.AddWithValue("@Name", "Musil");
    ...
    cmd.ExecuteNonQuery();
    KundenId = (int)cmd.Parameters["@KundenId"].Value;