Vlákno názorů ke zprávičce Kolaps 32-bitových PC v roku 2038? od Jet <jet@alfonso.homeip.net> - Ja jsem zrovna minuly tyden ladil rutiny pro...

  • Aktualita je stará, nové názory již nelze přidávat.
  • 25. 10. 2006 21:23

    Jet <jet@alfonso.homeip.net> (neregistrovaný)
    Ja jsem zrovna minuly tyden ladil rutiny pro prepocitavani datumu na pocet dni (od 1.1.2000). Pak jsem si je zkousel tak, ze jsem porovnaval co mi vypocita standardni glibc a co spocita moje rutina. Bohuzel, jestli bude fungovat i po roce 2k038, to jsem nezjistil :-). Moje glibc ma totiz time_t jenom 31+1 bitu.

    Ovsem zarizeni, ktere prave delam ma vaznejsi problem - je v nem rtc, ktere si mysli, ze rok 2100 bude prestupny. Kdyz jsem se smutnou tvari oznamil zakaznikovi, ze bude muset do manualu napsat, ze 1.3.2100 si uzivatel bude muset nechat nastavit spravne datum, protoze toto zarizeni si bude myslet ze je29.2.2100, musel jsem mu to zopakovat 2 krat, nez mu to doslo :-).


    Kdyz uz mluvim o te rutine, tady je, treba se bude nekomu hodit:


    #define M3 0 +31
    #define M4 M3 +30
    #define M5 M4 +31
    #define M6 M5 +30
    #define M7 M6 +31
    #define M8 M7 +31
    #define M9 M8 +30
    #define M10 M9 +31
    #define M11 M10+30
    #define M12 M11+31
    #define M1 M12+31
    #define M2 M1 +28

    static const int mtab[]=
    {
    0, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M1
    };

    // works from 1.3.2000 up to 2179, should be enough :-)
    word date_to_days(byte d, byte m, byte y) // y is year-2000, returns days since 1.1.2000
    {
    d--;
    m--;
    if (d>30) d=30;
    if (m>11) m=11;
    if (m<=1)
    {
    y--;
    m+=12;
    }
    return ( 31U // jan 2000
    +29 // feb 2000
    +(y/4) // regular leap days
    -(y/100) // not leap every 100 yrs
    // +(y/400) // could not occure in range 2000-2199
    +d // days of current month
    )
    +mtab[m-2] // past months
    +365U*y; // and finally all those years before
    }


    // the following function works fine from 1.1.2000 to 6.6.2179
    // day is number of days since 1.1.2000
    void day_to_date(word day, byte *y, byte *m, byte *d)
    {
    byte yl, ml;

    // extra handling for dates between 1.1.2000 and 1.3.2000
    if (day<31+29)
    {
    *y=0;
    ml=day/31;
    *m=ml+1;
    *d=day+(ml?-30:1);
    return;
    }
    day-=31+29; // day is now nr of days since 1.3.2000
    if (day>=(36525-1)) // 1.3.2100
    {
    day++; // correction for not leap year 2100 - this will be important for childs of our childs :-)
    }
    yl=(day*4UL+3)/(365*4+1); // years since 1.3.2000
    day-=yl*(365UL*4+1)/4-674; // day of year, 674 is correction for the following algoritm
    ml=(day<<6)/1959; // 1959>>6 is 30.6. int(n*30.6) makes just right sequence 30 31 30 31 31 30 etc
    *d=day-((ml*1959)>>6);
    if (ml>31)
    {
    ml-=31;
    yl++;
    }
    else
    {
    ml-=19;
    }
    *m=ml;
    *y=yl;
    }
  • 25. 10. 2006 22:42

    anonymní
    Taky mam rutinu na vypocty dnu.. jedine, me prekvapuje, ze nepouzivas bezny vypocet Julianskeho data ackoli jiste casti programu jsou az prilis podobne, nez aby slo o nahodu.
      function datjd (year,month,day)
    
        ! Compute Julian date from citizen year, month and day.
        ! Work for all years, inspired by Numerical Recipes.
    
        real(double), parameter :: break = 15 + 31*(10 + 12*1582)
    
        real(double), intent( in ) :: year,month,day
        real(double) ::  datjd,y,m,d,a
    
        if( abs(year) < epsilon(year) ) stop "datjd: there is no year zero." 
    
        y = year
        if( y < 0.0 ) y = y + 1
    
        if( month > 2.0 )then
           m = month + 1.0
           d = day
        else
           y = y - 1
           m = month + 13.0
           d = day
        endif
        datjd = int(365.25*y) + int(30.6001*m) + d + 1720994.5
        if( d + 31*(m + 12*y) ≥ break )then
           a = int(y/100.0)
           datjd = datjd + 2.0 - a + int(a/4.0)
        endif
       
      end function datjd