Obliczanie Daty - bład w algorytmie

0

Mam taki kodzik:

var
  Liczby: array[0..6] of Integer; // 0-lata, 1-miesiace, 2-tygodnie, 3-dni, 4-godziny, 5-minuty, 6-sekundy
begin
  Liczby[0] := YearsBetween(Data2, Data1);
  Liczby[1] := MonthsBetween(Data2, Data1);
  Liczby[2] := WeeksBetween(Data2, Data1);
  Liczby[3] := DaysBetween(Data2, Data1);
  Liczby[4] := HoursBetween(Data2, Data1);
  Liczby[5] := MinutesBetween(Data2, Data1);
  Liczby[6] := SecondsBetween(Data2, Data1);

  Liczby[6] := Liczby[6] - Liczby[5] * 60;
  Liczby[5] := Liczby[5] - Liczby[4] * 60;
  Liczby[4] := Liczby[4] - Liczby[3] * 24;
  Liczby[3] := Liczby[3] - Liczby[2] * 7;
  Liczby[2] := Liczby[2] - Liczby[1] * 4;
  Liczby[1] := Liczby[1] - Liczby[0] * 12;

w tablicy Liczby sa dane ile dni, miesiecy itp minelo lub pozostalo do okreslonej daty... problem jednak w tym ze te liczby sa nie dokladne

np gdy wybiore sobie jako pierwsza date 06.05.2004 a za druga 05.12.2004 to zamiast wyswietlic mi:
Liczby[0] = 0 // lat
Liczby[1] = 6 // miesiecy
Liczby[2] = 3 // tygodnie
Liczby[3] = 6 // dni
Liczby[4-6] = tu godziny wyswietla prawidlowo
pokazuje:
Liczby[0] = 0 // lat
Liczby[1] = 6 // miesiecy
Liczby[2] = 6 // tygodnie
Liczby[3] = 3 // dni

prawdopodobnie jest to zwiazane z tym ze nie kazdy miech ma rowne 4 tyg tylko jak to zrobic?

0

Hmm .. wydaje mi się, że źle do tego podchodzisz. Robisz moim zdaniem odwrotnie jak powinno być. Wg mnie trzeba najpierw wyznaczyć ten "największy dzielnik", później to co zostanie znowu dzielić przez największy, i to co zostanie - znowu .. itd. (wszystko na operatorach div i mod) Ale problem pojawi się w tygodniach - jak u Ciebie (*4) <-- miesiąc przecież nie ma dokładnie tylu tygodni i powstaje błąd "dokładności".

Ale ta metoda o której wspomniałem też chyba nie znajdzie tu zastosowania - właśnie przez te zmienne ilości.

W sumie nie wiem jak to obliczyć.

0

Prawda, najlepiej zrobić to na mod i div...

Uwzględniaj lata przestępne (czy ROK/4=0)
Zacznij od sprawdzenia różnicy lat, potem miesięcy, tygodni, dni.... godzin, minut itp... ;) - zawsze od największego!
Użyj tablicy dni dla miesięcy (stała liczba - z wyjątkiem roku przest.), uwzględnij miesiąc początkowy i końcowy....

Właściwie to proste.... musisz nieco tylko pokombinować...

0

heheh no wlasnie pokombinowac... ala ja juz kombinuje od paru dni i jakos wymyslic nie moge... bo kazdy miesiac ma 28 29 30 lub 31 dni a to mi jakos nie pasi z algorytmem... gdyby jakies rozwiazanie bogom z 4p przyszlo na mysl to bylbym bardzooo wdzieczny :P moze nawet byc w pseudokodzie nawet to zniose bo jestem hmm na fazie ? :P

0

Zobacz w kalendarzu!
Liczba dni w danym miesiącu jest zawsze stała (z wyjątkiem roku przest. wtedy luty ma o jeden dzionek więcej ;) )
W kolejności os St-Gr: 31, (28/29), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31.

Więc:
Sprawdzasz przestępność roku w obu datach
i w zależności od wyniku uwzględniasz poprawkę na luty.

Stary, nie wygłupiaj się, pomalutku...
Przeanalizuj wszystko po kolei i rozpisz sobie algorytm...
Potem sprawdź czy działa...

Nikt tu chyba nie da ci gotowego kodu, jedynie może udzielic pewnych wskazówek!

Właśnie takie problemy uczą myślenia !!!

0

kurde max ja wiem ze takie cos uczy myslenia ale... no wlasnie ale: po pierwsze jesli mam dwie podane daty to skad mam wiedziec jakie miesiace sa miedzy nimi i jak niby mam obliczyc ilosc dni miedzy nimi? to nie jest tak chop przeskoczyc... nawet dla tak napranego goscia jak ja teraz :P

0

Heh...

Operuj na składowych daty: r,d,m ...i już wiesz który roczek, dzionek czy miesiąc.
Rozbijasz tak date początkową i końcową, potem sprawdzasz różnicę mdz. latami
i ich przestępność. np.
20.01.2004 i 21.03.2009 -> Sprawdzasz różnicę pełnych lat (5) - zwracasz tu uwagę na miesiąc (mniejszy/większy), lata przestępne(2004 i 2008)
-> obliczasz różnicę miesięcy (tu 3-1=2) i zostają tylko dni...

Zwracasz tylko uwagę na różnicę poszczególnych składowych daty początkowej i końcowej tzn. sposób dla np. mc_daty1>mc_daty2 <> mc_daty1<mc_daty2 to samo tyczy się dnia....

Najprostsze (nieraz najgłupsze) sposoby okazują się najbardziej skuteczne!

0

no dobra to jest pewien sposob.... cos mi sie jednak zdaje ze nie jestem w stanie tego zrobic w takim stanie... moze zasmiecam forum ale co ja na to poradze ze jestem czlowiekiem i do tego semi-informatykiem? a jak kazdy polak wypic musze =P zabiore sie do tego jutro popoludniem jak juz wytrzezwieje (daj bog - bo jutro wtorek licealny) i moze mi sie cos uda.... mej forc bi wit me :P

0

Dla ułatwienia masz tu uproszczony algorytm - nie daję gwarancji poprawności!!!

r1,m2,d1; // rok, miesiąc, dzień daty pocz.
r2,m2,d2; // rok, miesiąc, dzień daty końc.

if m1<m2
Tak: if d1<d2
Tak: r=r2-r1, m=m2-m1, d=d2-d1
Nie : r=r2-r1, m=(m2-m1)-1, d=(l_dni_m1-d1)+d2 // l_dni_m1 - liczba dni w tym miesiącu
Nie: if d1<d2
Tak: r=(r2-r1)-1, m=(12-m1)+m2, d=d2-d1
Nie : r=(r2-r1)-1, m=(12-m1)+m2, d=(l_dni_m1-d1)+d2

0
var
  OldDate, Date: TDateTime;
  wYear, wYear2, wMonth, wMonth2, wDay, wDay2 : Word;
  fYear, fMonth, fDay : Word;
begin
  OldDate := Now;   // pobieranie dziesiejszej daty
  DecodeDate(OldDate, wYear, wMonth, wDay);

  Date := StrToDate('01-10-10');
  DecodeDate(Date, wYear2, wMonth2, wDay2);

  fYear := wYear - wYear2;
  fMonth := wMonth - wMonth2;
  fDay := wDay - wDay2;
  ShowMessage(Format('Różnica dni: %d, miesięcy: %d, lat: %d',
  [fDay, fMonth, fYear]));
0

hmm no tak:

l_dni_m1 -> a skad mam niby widziec jaki to jest miesiac? i trzeba by uwzglednic jeszcze ze tych miesiecy jest wiecej a co za tym idzie petelka konieczna

ile dni ma miesiac to jest w miare proste.. ktory to miesiac tez by mozna wykombinowac (nawet z lutym "isinleapyear(date:tdatetime)") ale nalezalo by wyliczyc ile jest miesiacy i jakie to miesiace... moze to sie z tego punktu widzenia wydaje latwe ale wcale takie nie jest... to tak jak liczyc rowniania z kilkoma niewiadomymi nie mogac zrobic ukladu rownani ;P (nie czajcie mnie ja nadal pod wplywem jestem)

0

Supcio Bełdzio, tylko jest jeden mały problem...
Zakładam, sprawdź to:

  • OldDate := Now; * pobieranie dziesiejszej daty
    // DecodeDate(OldDate, wYear, wMonth, wDay);

Date := StrToDate('04-04-10');
DecodeDate(Date, wYear, wMonth, wDay);

Date := StrToDate('03-01-20');
DecodeDate(Date, wYear2, wMonth2, wDay2);

I zobacz, co ci wyjdzie?
Ten kod nie poradzi sobie z latami przestępnymi - będzie gubił dni,
jak i z miesiącem bądź dniem mniejszym od wejściowego !!!

0

no to trzeba dać warunek sprawdzający czy dany rok jest przestępczy :) + sprawdzenie ile było takich roczków w ciągu tych 2 dat

0

hmm no tak:

l_dni_m1 -> a skad mam niby widziec jaki to jest miesiac? i trzeba by uwzglednic jeszcze ze tych miesiecy jest wiecej a co za tym idzie petelka konieczna

ile dni ma miesiac to jest w miare proste.. ktory to miesiac tez by mozna wykombinowac (nawet z lutym "isinleapyear(date:tdatetime)") ale nalezalo by wyliczyc ile jest miesiacy i jakie to miesiace... moze to sie z tego punktu widzenia wydaje latwe ale wcale takie nie jest... to tak jak liczyc rowniania z kilkoma niewiadomymi nie mogac zrobic ukladu rownani ;P (nie czajcie mnie ja nadal pod wplywem jestem)

Masz dwie daty:
20.01.2004 i 10.04.2006
rozbijasz je na składowe np:
Date := StrToDate('04-01-20'); //dla daty obecnej: Date := Now;
DecodeDate(Date, r1, m1, d1);
podobnie dla drugiej daty tylko że: DecodeDate(Date, r2, m2, d2);

i z m1 (m1=1) już wiesz, że to styczeń, z r1 rok 2004/4 bez reszty więc rok przestępny (gdyby było potrzeba) styczeń ma 31 dni !!! więc podstawiasz do algorytmu np z tablicy l_dni_m1[0] (tablica dni miesięcy - od 0 dla stycznia do 11 dla grudnia).

Wszystko walisz do zmiennych, tak jak podane w algorku i na tych zmiennych operujesz... tak jak tam podane...

Zadnych układów równań itp. pierdół nie potrzeba... wszystko tam już masz! (jakie warunki sprawdzić, oraz co i kiedy zrobić)

0

Qrna... będę taki miły.... i dam rozwiązanie [!!!] [!!!] [!!!]
Ale... już więcej taki miły nie będe [diabel]

var
  Date: TDateTime;
  r1,m1,d1,r2,m2,d2 :word;
  r,m,d :word;
const  
  l_dn: array[0..11] of integer =(31,28,31,30,31,30,31,31,30,31,30,31);
begin

  Date := StrToDate('03-01-20');
  DecodeDate(Date, r1, m1, d1);

 // Date := Now;
  Date := StrToDate('04-03-10');
 // DecodeDate(Date, r2, m2, d2);  
  DecodeDate(Date, r2, m2, d2);

if m1<m2 then
 begin
  if d1<d2 then
    begin
     r:=r2-r1;
     m:=m2-m1;
     d:=d2-d1;
    end else
    begin
     r:=r2-r1;
     m:=(m2-m1)-1;
     d:=(l_dn[m1-1]-d1)+d2;
    end;
 end else if d1<d2 then
    begin
     r:=(r2-r1)-1;
     m:=(12-m1)+m2;
     d:=d2-d1;
    end else
    begin
     r:=(r2-r1)-1;
     m:=(12-m1)+m2;
     d:=(l_dn[m1-1]-d1)+d2;
    end;

  ShowMessage(Format('Ilość lat: %d, m-cy: %d, dni: %d', [r,m,d]));
end;

0

no nie powiem kodzik jest wyjefajny ^^ macie u mnie za to [browar]
no ale sprobujcie ustawic sobie ten sam miesiac :P

jesli ustawie date o dzien wczesniej wyswietla mi:
Ilosc lat: 65535, m-cy: 12, dni: 1

a to nie o to chyba chodzilo ^^
poza tym zostaje jeszcze ten luty i rok przstepny :/

0

No to pokombinuj , masz już z górki... dodasz jakiegoś ifa i po kłopocie...
Wszystkiego za ciebie robił nie będę, bo nie o to chodzi... ;)

A browarka puść przesyłką kurierską :D :d :D

0

A sprawdź ten kod:

var
Start,Koniec: TDateTime;
r1,m1,d1,r2,m2,d2,r,m,d :word;
begin

Start := StrToDate('2003-02-08');
DecodeDate(Start, r1, m1, d1);

Koniec := StrToDate('2004-03-06');
DecodeDate(Koniec, r2, m2, d2);

if r2 > r1 then r:=r2-r1 else r:=0;
if (m2>m1) and (d2>d1) then m:=m2-m1 else m:=0;
if d2>d1 then d:=d2-d1
else
case m1 of
1,3,5,7,9,11 : d:=(31-d1)+d2;
4,6,8,10,12 : d:=(30-d1)+d2;
else
begin
if (Frac(r1/4)= 0) then d:=(29-d1)+d2 else d:=(28-d1)+d2;
end;
end;
ShowMessage(Format('Ilość lat: %d, m-cy: %d, dni: %d', [r,m,d]));
end;

0

Hmm... można to zapisac na 1001 sposobów...

Ten kod nie radzi sobie z datami np. Start: 04-01-20 i Koniec: 04-03-10 ...
Różnicę wywala L=0, M=0, D=21 a powinien chyba L=0, M=1, D=21 - prawda???

0

A niech tam, raz kozie śmiertka... ;-)

Zamieszczam poprawiony kod - jest baaardzo prosty, tak by każdy lamer zrozumiał...
A lud znający Delphi'ego... będze sobie mógł skrócić, czy co tam jeszcze zapragnie... - Zwyczajnie, kod ten może wyglądać wtedy bardziej proff...

var
  Date: TDateTime;
  r1,m1,d1,r2,m2,d2 :word;
  r,m,d :word;
const
  l_dnz: array[0..11] of integer =(31,28,31,30,31,30,31,31,30,31,30,31);
  l_dnp: array[0..11] of integer =(31,29,31,30,31,30,31,31,30,31,30,31);
begin

  Date := StrToDate('04-01-20');
  DecodeDate(Date, r1, m1, d1);

 // Date := Now;
 // DecodeDate(Date, r2, m2, d2);  
  Date := StrToDate('04-02-25');
  DecodeDate(Date, r2, m2, d2);

if m1<=m2 then
 begin
  if d1<d2 then
    begin
     r:=r2-r1;
     m:=m2-m1;
     d:=d2-d1;
    end else
    begin
     r:=r2-r1;
     m:=(m2-m1)-1;
     if (r1 mod 4=0) then d:=(l_dnp[m1-1]-d1)+d2 else d:=(l_dnz[m1-1]-d1)+d2;
    end;
 end else if d1<d2 then
    begin
     r:=(r2-r1)-1;
     m:=(12-m1)+m2;
     d:=d2-d1;
    end else
    begin
     r:=(r2-r1)-1;
     m:=(12-m1)+m2;
     if (r1 mod 4=0) then d:=(l_dnp[m1-1]-d1)+d2 else d:=(l_dnz[m1-1]-d1)+d2;
    end;

  ShowMessage(Format('Różnica lat: %d, m-cy: %d, dni: %d', [r,m,d]));
end;

Teraz chyba każdy zkuma o co w tym biega - prościej chyba już nie dam rady ;-)

0

np kodzik jak zwykle wyjefajny :P poza tym ze (przynajmniej tak mi sie zdaje oblicza tylko w przeciagu 4 lat bo jak bedzie 8 lub wiecej (dwa lata przestepne) to juz bedzie lipa :/

nie wiem moze jestem noob lub jestem napity (albo to i to) ale jakos mi sie zdaje ze jak bedzie wiecej lat to ten algorytm nie wyjdzie :/

0

I w czym problem ?
Masz już tyle kodu totalnie za free, że z takim drobiazgiem chyba sobie sam poradzisz...
Sprawdzasz ile lat przestępnych i dodajesz tyle dni...

sorki... tyle dni-1 !!! który jest zawsze uwzględniany.

0

Max jeżeli chcesz być tak dokładny to w moim kodzie wystarczy w wierszu gdzie jest wyliczana ilośc miesięcy poprawić tak:
if (m2>m1) and (d2>d1) then
m:=m2-m1
else if m2-m1 > 1 then m:=(m2-m1)-1
else m:=0;

teraz OK?

0

Chyba OK, nie mam ochoty (ani czasu) sprawdzać ;-)

Chyba sam byłem .lekko zawiany (a może to wina przepracowania i braku snu ?)
odpowiadając na pytanie o brakujące dni zw. z latami przest. występującymi pomiędzy datą pocz. i końcową!!!....

To nie istotne!!!

Tealgorytmy mają zliczać ilość pełnych lat, miesięcy i dni...
więc (poza datą początkową!) to żadna różnica! bo luty 28 jak i 29 dniowy jest pełnym miesiącem!

Ten fakt miał by znaczenie, gdyby zliczać wszystko tylko jako dni...

To już jest koniec... i więcej nie będzie - (przynajmniej z mojej str)

0

echhh jestem okropny ale pragne <ort>zauwarzyc </ort>ze dane kody maja bledy :P

mianowicie przy jednym i drugim ustawiajac daty na 2004-12-09 i 2005-01-01 dla przykladu da nam 1 miesiac i 23 dni (co oczywiscie nie jest prawda :P )

0

A teraz pasuje?

var
Start,Koniec,DataTemp: TDateTime;
r1,m1,d1,r2,m2,d2,r,m,d :word;
begin

Start := StrToDate('2004-01-20');
DecodeDate(Start, r1, m1, d1);

Koniec := StrToDate('2004-03-10');
DecodeDate(Koniec, r2, m2, d2);
DataTemp:=EncodeDate(r1+1,m2,d2);

if (r2-r1<>1) then r:=r2-r1 else r:=0;
if (m2>m1) and (d2>d1) then m:=m2-m1 else if m2-m1 > 1 then m:=(m2-m1)-1 else if ((m1-m2=11) and (DaysBetween(start,DataTemp)>30)) then m:=1 else m:=0;
if d2>=d1 then d:=d2-d1+1
else
case m1 of
1,3,5,7,9,11 : d:=(31-d1)+d2;
4,6,8,10,12 : d:=(30-d1)+d2;
else
begin
if (Frac(r1/4)= 0) then d:=(29-d1)+d2 else d:=(28-d1)+d2;
end;
end;
ShowMessage(Format('Ilość lat: %d, m-cy: %d, dni: %d', [r,m,d]));

0

Ja od siebie ze nie wystarczy sprawdzic, czy rok/4 reszta =0 zeby byc pewny, ze rok przestepny...

0

rok jest przestępny, kiedy dzieli się (bez reszty) przez cztery, za wyjątkiem lat podzielnych przez 100. Jeżeli jednak rok dzieli się przez 400 jest przestępny. Lata: 1700, 1800 i 1900 nie były przestępnymi. Rok 2000 jest przestępny, gdyż dzieli się przez 400.

1 użytkowników online, w tym zalogowanych: 0, gości: 1