Gregorianske kalender

Den gregorianske kalender følges i bl.a. Danmark

Den gregorianske kalender er den almindelige danske kalender, som vi bruger til at holde styr på, hvilken dato det er i løbet af året.

Historie

At lave en kalender, der præcis dækker et år, giver lidt problemer, da det "tropiske år" ikke er på 365 døgn, men på 365,24219878 døgn. Da den overskydende del siden oldtiden har været erkendt til at være et kvart døgn, indførte Julius Cæsar efter forslag af grækeren Sosigenes i år 46 f.Kr. den julianske kalender. Ifølge den julianske kalender skulle år delelige med tallet fire være skudår, dvs. indeholde 366 dage i stedet for normalår på 365 dage. Det julianske år har derfor længden 365,25 dage.

Årslængden på 365,25 dage gjorde dog, at der i 1500-tallet var kommet en afvigelse på ca. 10 døgn. Dette problem blev løst i 1582, da pave Gregor XIII indførte den gregorianske kalender. Samtidig med indførelsen af denne kalender blev datoen rettet med 10 dage (den 4. oktober blev efterfulgt af den 15. oktober).

Det er bemærkelsesværdigt, at den gregorianske kalender blev fastlagt, medens det (fejlagtige) geocentriske verdensbillede endnu var det vedtagne.

Den gregorianske kalender har, ligesom den julianske, skudår hvert fjerde år, men til gengæld er år delelige med 100 ikke skudår. Dog er disse hele hundredeår alligevel skudår, hvis de er delelige med 400. Denne sidste regel skal i sagens natur kun benyttes sjældent, men kom i anvendelse i år 2000, som var skudår.

Denne beregningsmetode giver en årslængde på i snit 365,2425 dage, meget tæt på det ønskede. Denne kalender giver kun en fejl på ca. 3 dage på 10.000 år.

I Danmark blev den gregorianske kalender indført den 1. marts 1700 efter forarbejde af Ole Rømer. Man stoppede med brug af den julianske kalender den 18. februar, (altså et spring i datoen på 11 dage).

Den gregorianske kalender blev imidlertid indført af paven kort efter Luther og reformationen, så mange protestantiske og ortodokse fyrstedømmer og lande valgte først at indføre den nye kalender meget senere for ikke at give indrømmelser over for modparten. Storbritannien indførte den nye kalender i 1752. Sverige og Finland overgik til kalenderen i 1753 ved at udelade 11 dage af året, den 17. februar 1753, som derved blev til den 1. marts.

Selv om Sovjetunionen overgik fra den julianske kalender til den gregorianske kalender den 14. februar 1918, benytter den russisk-ortodokse kirke stadig den gamle julianske kalender, og derved fejres julen i Rusland senere end i Vesteuropa; omtrent på samme tidspunkt som vi fejrer helligtrekonger. Desuden fejredes oktoberrevolutionen efter den gregorianske kalender i november, selv om den faktisk skete i oktober efter den julianske kalender.

I Storfyrstendømmet Finland, der var underlagt Det Russiske Kejserrige, anvendtes den gregorianske kalender, som i 1800-tallet afveg med 12 dage og i 1900-tallet med 13 dage fra de øvrige dele af kejserriget. Eftersom der fulgtes forskellige kalendere i Rusland og i Finland, blev alle dokumenter vedrørende Finland i Skt. Petersborg udfærdiget med dobbelt-dato, en ”ny” og en ”gammel” af praktiske årsager.

Algoritme til beregning af dato og ugedag mv.

Datostandard

I Danmark har vi to valgmuligheder for at skrive en dato. Den traditionelle danske er dd-mm-åååå, hvilket vil sige, at rækkefølgen er dag, måned og år. Et eksempel på dette kunne være 29-12-2005. Udover dette kan den internationale standard ISO-8601 også benyttes. Heraf fremgår det, at datoer skrives som åååå-mm-dd, hvor et eksempel kunne være 2005-12-29. Hvis du skriver månedens navn ud, skal det skrives i rækkefølgen dag, måned og år. Med det samme eksempel vil det blive d. 29. december 2005.

Ugenumre

Det er torsdagen, der bestemmer, hvilket år en uge tilhører. Derfor er ugen fra mandag den 28. december 2009 til søndag den 3. januar 2010 uge 2009-53, da torsdagen (den 31. december) er i 2009.

Genbrug af den gregorianske kalender

Den gregorianske kalender kan genbruges hvert 28. år. Dog med undtagelse af, når et århundredeskifte ikke er et skudår. Derfor havde bl.a. år 1900 og år 1928 ikke den samme kalender. År 1928 var et skudår, og havde altså 29 dage i februar, mens år 1900 ikke var et skudår (da 1900 ikke er deleligt med 400), og derfor kun havde 28 dage i februar.

Opbygning af algoritme

Skal man til at beregne ugedag, eller antal dage mellem to datoer i den gregorianske kalender, vil en algoritme kun give fornuftige data, såfremt man tager hensyn til hvilket land det drejer sig om, og datoen for den gregorianske kalenders indførelse, samt hvilken dato man foretog justeringen.

Det første, man opdager ved at se på kalenderen, er, at den er opbygget af år, måneder, og dage, hvor der ikke umiddelbart ser ud til at være nogen pæn lineær sammenhæng. Et brute force kodet program til ugedagsberegning vil derfor kunne komme til at bestå af mange "if/case" konstruktioner til at tage højde for de forskellige regler.

For at undgå dette indser man at der må laves en anden skala, f.eks. antal dage siden et "fiktivt" år 0. Dette er meget nemmere at udregne, idet reglerne i den gregorianske kalender er meget klare. Så antallet af dage fra år 0 til den 0. januar kan så beregnes på følgende måde:

 /* der benyttes heltals divison ! */
 Faktor = 365*ÅR + (ÅR-1)/4  (ÅR-1)/100 + (ÅR-1)/400 ;

Forkortes lidt fås:

Faktor = 365*ÅR + (ÅR-1)/4 – ((ÅR-1)/100)*3/4 ;

Næste problem bliver februar, som kan være på enten 28 eller 29 dage. Alle andre måneder har et fast antal dage. Det nemmeste er at flytte årets start til marts, idet februar derved kommer sidst. Nu er det ikke nødvendigt at tages hensyn til, om det er skudår eller ej, når den aktuelle "faktor" skal udregnes for en given dato. Derefter mangler der kun at skabe en lineær sammenhæng mellem dag i året og aktuel måned og dag. Hvis man starter med at tælle fra marts, får man følgende tabel:


Måned Antal dage Dag i året-
marts 31 0
april 30 31
maj 31 61
juni 30 92
juli 31 122
august 31 153
september 30 184
oktober 31 214
november 30 245
december 31 275
januar 31 306
februar 28/29 337
I alt   365/366

Nu kunne en sådan tabelløsning være ideel, og de fleste ville nok kunne stille sig tilfreds her. Algoritmen ville komme til at se ud som følgende:

/* der benyttes heltals divison ! */
if (Måned < 3 ) {
     /* da skuddagen er den 29/2, skal skuddag ikke medregnes i jan/feb */
     /* så derfor benyttes ÅR-1  */
     Faktor = 365*ÅR + (ÅR-1)/4 - (((ÅR-1)/100)*3)/4 + tabel[Måned] + Dag.
} else {
     Faktor = 365*ÅR + ÅR/4 - ((ÅR/100)*3)/4 + tabel[Måned] + Dag.
}

Tabellen kan forenkles noget. Tegner man tabellen på millimeterpapir, og gives januar og februar henholdsvis månedsnummeret 13 og 14, vil man opdage, at man (næsten) kan tegne en ret linje gennem de plottede punkter. Ved enten at aflæse eller ved at benytte lineær regression, kan man få hældningskoefficient (m) og skæring med Y-aksen (b):

m = 30,6013986 , b = -91,77855478 .

Ved beregningen fremkom korrelationskoefficienten 0,999996, som er et ganske godt resultat, da 1,00 ville være fuldkommen korrelation. Tabellen fra før kan derfor erstattes med:

    round ( Måned*30,60  91,78 ) 
    = Int ( Måned*30,60  91,78 + 0,5 )
    = Int ( Måned*30,60  91,28 )

For ikke at skulle benytte reelle tal (float), udregnes det hele i en heltal udgave, og samtidig forenkles beregningen ved januar og februar. Den færdige rutine bliver så:

  /* ------------------- factor -----------------------------*/
  #define LONGWORD unsigned int

  LONGWORD factor(RTCtime *tm)
  {
    WORD  y,m;

    y = tm->year;
    m = tm->month;
    if ( tm->month < 3 ) {  y--; m += 12; }
    return 365UL*y + y/4UL  ((y/100+1)*3)/4 + (m*3060-9135)/100 + tm->day + 59;
  }

Datastrukturen for RTCtime er lavet for at holde lidt styr på dag, måned og år.

Beregning af ugedag

Der er 7 dage i en uge, og dagene gentager sig hele tiden, så beregning af ugedag kan nemt gøres ved modulus 7. Ønskes derudover, at søndag er ugedag nr. 0, skal der først adderes 6 til faktoren.

    /*------------------- weekday ------------------------------*/
    /* returns weekday, sun=0, mon=1,..... : */
    int weekday(RTCtime *tm)
    {  
        return (int) ( (factor(tm)+6) % 7UL );
    }

Beregning af antal dage mellem to datoer

Denne kan gøres meget enkel med factor():

   Dage = labs ( factor(Dato1) – factor(Dato2) ).

C-funktionen labs() udregner den absolutte værdi.

Kontrol af om en dato er ok

Ved indtastning af datoer er der ofte behov for at kontrollere om datoen er gyldig, så f.eks. datoer som d. 29. februar 1995 eller 31. april ikke accepteres. Året kontrolleres på sædvanlig vis, evt. suppleret med, at det for Danmark skal være fra og med marts 1700. Måneden er nem at kontrollere, idet det selvfølgelig er et tal fra 1 til 12. Antallet af dage i måneden kan med factor() let beregnes, idet den fremgår som antallet af dage mellem den første i den aktuelle måned og den 1. i næste måned. En simpel procedure til at foretage en sådan kontrol er date_ok().

    /*------------------- date_ok ------------------------------*/
    int date_ok(RTCtime *t)
    /* returns 0 if date not ok, else days in month is returned */
    {
      LONGWORD f1;
      RTCtime tmp;
 
      if ( (t->year  < 1) || (t->year  >9998) ) return 0;
      if ( (t->month < 1) || (t->month >  12) ) return 0;
      if (  t->day   < 1 ) return 0;
      tmp = *t; tmp.day=1;
      f1 = factor(&tmp);
      tmp.month++;
      if ( (f1 = factor(&tmp)-f1) < t->day ) return 0;
      else  return (int) f1; /* if ok return days in month */
    }

Adder N dage til en dato, og udregn den nye dato

Det nemmeste er at udregne factor() for datoen og addere de N dage:

             F = factor(dato) + N ;

Derefter divideres med 365.2425, og det fremkomne tal skulle gerne være årstallet:

 	      ÅR= F * 10000UL / 3652425UL;

Som kontrol udregnes F1 = factor( 1.jan.ÅR), og F2 = factor( 1.jan.(ÅR+1). Hvis der på grund af afrundingsfejl ikke gælder uligheden:

 		F1 ≤ F < F2

Må ÅR korrigeres med +/- 1.

Måneden findes lettes ved at udregne Fm = factor(1.MD.ÅR) for alle måneder startende med MD=1, indtil Fm > F. Dagen kan så findes som differencen mellem Fm og F.

Litteratur

Se også

  • Symmetri454 (el. Symmetri454-kalenderen (Sym454)) - forslag fra 1970'erne til en reform af den gregorianske kalender