Edit detail for NalezeniPracovnihoDne revision 2 of 1

2
Editor: pepr
Time: 2011/03/16 15:43:27 GMT+1
Note: file() zaměněno za open()

changed:
-
Hledaní začalo mým dotazem v konferenci:

hledam funkci kalendare -neco jako rozsireni k modulu time- na overeni nepracovnich dnu a svatku(ceskych). 
Vim, ze bych si to mohl napsat sam, ale nechci vymyslet vec, kterou uz urcite nekdo vymyslel :-)

Pak následovalo pár odpovědí, které mě moc neuspokojovaly, takže jsem to vyřešil jednoduše pomocí modulu calendar. (jvit)

::
    
    def nepracovniDen(rrrr,mm,dd):
        """Vrati 0 kdyz je statni svatek nebo vikend."""
        import calendar
        datum = (mm,dd)
        svatky = ((1,1),velikonoce(rrrr),(5,1),(5,8),(7,5),(7,6),(9,28),
		 (10,28),(11,17),(12,24),(12,25),(12,26))
        vikend = (5,6)
        if datum in svatky or calendar.weekday(rrrr,mm,dd) in vikend: return 0
        else: return 1
   
    def velikonoce(year):
        import time
        century = year/100
        G = year % 19
        K = (century - 17)/25
        I = (century - century/4 - (century - K)/3 + 19*G + 15) % 30
        I = I - (I/28)*(1 - (I/28)*(29/(I + 1))*((21 - G)/11))
        J = (year + year/4 + I + 2 - century + century/4) % 7
        L = I - J
        EasterMonth = 3 + (L + 40)/44
        EasterDay = L + 28 - 31*(EasterMonth/4)
        pondeli = time.mktime((year,EasterMonth,EasterDay,) + time.localtime()[3:]) + 86400
    
        return time.localtime(pondeli)[1:3]
        
Pak jsem ještě potřeboval najít univerzálně nejbližší pracovní den, pokud je svátek nebo víkend. Funkce vrací string, který mi pro mé účely vyhovoval. Vzhledem k tomu, ze metoda mktime() chce jako argument 9. místnou n-tici, doplňuji to ořezaným time.localtime()[3:].  

::
    
    def najdiPracovniDen(stav,rrrr,mm,dd,den=86400):
        """Hleda nejblizsi pracovni den. Pokud je svatek nebo vikend, zkousi dalsi den. Stav: 1 - pro pracovni den; 0 - pro svatek.
           Hledame dopredu,dokud nenalezneme prvni mozny pracovni den. Vraci string ve formatu 'RRRRMMDD'"""
        import time
        sec = time.mktime((rrrr,mm,dd,) + time.localtime()[3:])
        while stav == 0:
            sec += den
            rrrr,mm,dd = time.localtime(sec)[:3]
            stav = nepracovniDen(rrrr,mm,dd)
        return time.strftime('%Y%m%d',time.localtime(sec))

Následující kód ukazuje celý skript pro výpočet Velikonočních nedělí. Ještě jednou... POZOR! Počítá to NEDĚLE! Kód vložte do souboru 'velikonoce.py'. Kódování si upravte podle sebe, případně vyhoďte české znaky (pepr)::

    # -*- coding: cp1250 -*-
    
    def velikonoce(year):
        u"""Oudinův algoritmus pro výpočet velikonoční neděle.
        
        Platí pro celé období Gregoriánského kalendáře, tj. od roku 1582.
        Zdroj: http://www.smart.net/~mmontes/oudin.html"""
    
        century = year/100
        G = year % 19
        K = (century - 17)/25
        I = (century - century/4 - (century - K)/3 + 19*G + 15) % 30
        I = I - (I/28)*(1 - (I/28)*(29/(I + 1))*((21 - G)/11))
        J = (year + year/4 + I + 2 - century + century/4) % 7
        L = I - J
        EasterMonth = 3 + (L + 40)/44
        EasterDay = L + 28 - 31*(EasterMonth/4)
    
        return "%d.%d.%d" % (EasterDay, EasterMonth, year)
        
    
    def main():
        f = open('velikonoce.txt', 'w')
        for year in xrange(1900, 3000):
            f.write(velikonoce(year) + '\n')
        f.close()
        
    if __name__=="__main__":
        main()    

Hledaní začalo mým dotazem v konferenci:

hledam funkci kalendare -neco jako rozsireni k modulu time- na overeni nepracovnich dnu a svatku(ceskych). Vim, ze bych si to mohl napsat sam, ale nechci vymyslet vec, kterou uz urcite nekdo vymyslel :-)

Pak následovalo pár odpovědí, které mě moc neuspokojovaly, takže jsem to vyřešil jednoduše pomocí modulu calendar. (jvit)

    def nepracovniDen(rrrr,mm,dd):
        """Vrati 0 kdyz je statni svatek nebo vikend."""
        import calendar
        datum = (mm,dd)
        svatky = ((1,1),velikonoce(rrrr),(5,1),(5,8),(7,5),(7,6),(9,28),
                 (10,28),(11,17),(12,24),(12,25),(12,26))
        vikend = (5,6)
        if datum in svatky or calendar.weekday(rrrr,mm,dd) in vikend: return 0
        else: return 1

    def velikonoce(year):
        import time
        century = year/100
        G = year % 19
        K = (century - 17)/25
        I = (century - century/4 - (century - K)/3 + 19*G + 15) % 30
        I = I - (I/28)*(1 - (I/28)*(29/(I + 1))*((21 - G)/11))
        J = (year + year/4 + I + 2 - century + century/4) % 7
        L = I - J
        EasterMonth = 3 + (L + 40)/44
        EasterDay = L + 28 - 31*(EasterMonth/4)
        pondeli = time.mktime((year,EasterMonth,EasterDay,) + time.localtime()[3:]) + 86400

        return time.localtime(pondeli)[1:3]

Pak jsem ještě potřeboval najít univerzálně nejbližší pracovní den, pokud je svátek nebo víkend. Funkce vrací string, který mi pro mé účely vyhovoval. Vzhledem k tomu, ze metoda mktime() chce jako argument 9. místnou n-tici, doplňuji to ořezaným time.localtime()[3:]?.

    def najdiPracovniDen(stav,rrrr,mm,dd,den=86400):
        """Hleda nejblizsi pracovni den. Pokud je svatek nebo vikend, zkousi dalsi den. Stav: 1 - pro pracovni den; 0 - pro svatek.
           Hledame dopredu,dokud nenalezneme prvni mozny pracovni den. Vraci string ve formatu 'RRRRMMDD'"""
        import time
        sec = time.mktime((rrrr,mm,dd,) + time.localtime()[3:])
        while stav == 0:
            sec += den
            rrrr,mm,dd = time.localtime(sec)[:3]
            stav = nepracovniDen(rrrr,mm,dd)
        return time.strftime('%Y%m%d',time.localtime(sec))

Následující kód ukazuje celý skript pro výpočet Velikonočních nedělí. Ještě jednou... POZOR! Počítá to NEDĚLE! Kód vložte do souboru velikonoce.py. Kódování si upravte podle sebe, případně vyhoďte české znaky (pepr):

    # -*- coding: cp1250 -*-

    def velikonoce(year):
        u"""Oudinův algoritmus pro výpočet velikonoční neděle.

        Platí pro celé období Gregoriánského kalendáře, tj. od roku 1582.
        Zdroj: http://www.smart.net/~mmontes/oudin.html"""

        century = year/100
        G = year % 19
        K = (century - 17)/25
        I = (century - century/4 - (century - K)/3 + 19*G + 15) % 30
        I = I - (I/28)*(1 - (I/28)*(29/(I + 1))*((21 - G)/11))
        J = (year + year/4 + I + 2 - century + century/4) % 7
        L = I - J
        EasterMonth = 3 + (L + 40)/44
        EasterDay = L + 28 - 31*(EasterMonth/4)

        return "%d.%d.%d" % (EasterDay, EasterMonth, year)

    def main():
        f = open('velikonoce.txt', 'w')
        for year in xrange(1900, 3000):
            f.write(velikonoce(year) + '\n')
        f.close()

    if __name__=="__main__":
        main()