Egyszerűen - rövidebb

Hanyadik napja van az évnek?
Pascal:


MDays: array[1..12] of Integer =
(31,28,31,30,31,30,31,31,30,31,30);
DayNr:=0;
for j:= 1 to Mon-1 do DayNr:=DayNr+MDays[j];
DayNr:= DayNr+Day;

bash script (ugyanez):


MDays=(31 28 31 30 31 30 31 31 30 31 30)
DayNr=0
for i in $(seq 1 1 $(($honap-1))); do DayNr=$((DayNr+${MDays[$(($i-1))]})); done
DayNr=$(($DayNr+$nap))

egyszerűbben és szökőév helyesen


DayNr=$(date +%j | bc)

A bc a vezető nullák lecsapása miatt van.

Szerk.
zamboriz hozta a megoldást:

DayNr=$(date +%-j)

Hozzászólások

Aztán egyszer nehogy rádtámadjon egy nem-GNU date(1) implementáció, vagy derült égből egy szökőév :)

A bc helyett talán inkább egy DayNr=$((DayNr))-t csinálnék, franc sem akar forkolni egy dög nagy bc-t feleslegesen.

A Pascalos verzioban a for ciklust meg lehet sporolni, ha ilyen (ket, szokoev esetere) tombot hasznalsz:

MDays: array[1..12] of Integer =
(0,31,59,90,120,151,181,212,243,273,304,334);

Ezutan mar csak egy lookup meg egy osszeadas az egesz.

DayNr = MDays[Mon] + Day;

Ennyi erovel irhatsz egy celprogramot es elinditod:
./a - wow, milyen rovid!

...

Ettol a for i in seq-tol felall a hatamon a szor. (Eleve linuxism a seq, de raadasul meg csak azt se hasznalod ki a shell lehetosegebol, ami benne van.) Mit szolnal ehhez:

MDays=(31 28 31 30 31 30 31 31 30 31 30)
DayNr=0
for i in $( seq 1 ${#MDays} ) ; do DayNr=$(( $DayNr + ${MDay[$(( $i - 1 ))]} )) ; done
echo $DayNr

De oszinten en inkabb ebben a sokkal egyszerubb formaban irnam:

for i in ${MDays[*]} ; do DayNr=$(( $DayNr + $i )) ; done

A kiirast amugy semelyik programod nem csinalja meg, csak a date (magatol).

O.K. legyen hordozható (és hosszabb),
mert ez nem hordozható: DayNr=$(date +%-j)
Ha már számolok, akkor táblázat is kizárva.

A Sunrise/Sunset Algorithm innen: Almanac for Computers, 1990

1. first calculate the day of the year

N1 = floor(275 * month / 9)
N2 = floor((month + 9) / 12)
N3 = (1 + floor((year - 4 * floor(year / 4) + 2) / 3))
DayNr = N1 - (N2 * N3) + day - 30

nem volt felkészülve a 100-zal és 400-zal osztható évekre.

Korrigáltam:

if [ $# -lt 3 ]
then
year=$(date +%-Y)
month=$(date +%-m)
day=$(date +%-d)
else
year=$1
month=$2
day=$3
fi

# fix napok száma
# N1 = floor(275 * month / 9)
f_loor=$(echo "275*$month/9" | bc )
N1=${f_loor/.*}

# letelt az első két hónap?
# N2 = floor((month + 9) / 12)
f_loor=$(echo "($month+9)/12" | bc)
N2=${f_loor/.*}

function floor(){ # $1=dátumév $2=ciklus
f_loor=$(echo "$1/$2" | bc) ; f_loor=${f_loor/.*}
f_loor=$(echo "$1-$2*$f_loor+$2-2" | bc) ; f_loor=${f_loor/.*}
echo $(echo "1+$f_loor/($2-1)" | bc)
}

# négyévente (szökőév)
# N4 = (1 + floor((year - 4 * floor(year / 4) + 2) / 3))
N4=$(floor $year 4)

# századforduló (nem szökőév)
# N100 = (1 + floor((year - 100 * floor(year / 100) + 98) / 99))
N100=$(floor $year 100)

# a négyszázzal osztható (szökőév)
# N400 = (1 + floor((year - 400 * floor(year / 400) + 398) / 399))
N400=$(floor $year 400)

# N = N1 - (N2 * N4) - (N2 * (1 - N100)) + (N2 * (1 - N400)) + day - 30

DayNr=$(echo "$N1-($N2*$N4)-($N2*(1-$N100))+($N2*(1-$N400))+$day-30" | bc)
echo $year"."$month"."$day" az év "$DayNr". napja"

Hát, kicsit hosszabb :)

A bc-től nem érdemes megszabadulnom, mert ilyen soraim is lesznek:
dekl:=-23.5*COS(pi/180*(DayOffs+0.988*DayNr))

Utoljára ilyet (mikrovezérlőn kellett implementálni, brrr) úgy csináltam, hogy:
* A programba bekerült egy táblázat, hogy melyik év melyik Unix time pillanatban kezdődik, illetve melyik szökő
* Minden dátum formátumot egyből Unix time-ra alakítottam a fenti táblázat segítségével (a konverziós metódusok remekül unit tesztelhetőek)
* Ha Unix time-od van, akkor csak ki kell vonni az év elejét belőle, majd osztogatni, és megvan.

"Rendes" platformokon vannak dátumkezelő könyvtárak, amik némi olvasgatás és gondolkodás után helyes paraméterezéssel jól működnek. Pl Javában java.util.Calendar Javában.

Arra vigyázz, hogy a libek, parancsok többsége a gépen beállított local beállításokból veszi az időzónát. Így ugyanaz a program simán tud "hülyeségeket" adni egy másra kalibrált gépen.