ugrás a tartalomhoz

Dátumok különbsége hónapokban

makgab · 2014. Ápr. 1. (K), 11.16
Üdv!

Két dátumból szeretném megkapni, hogy a különbség hány hónap.
Egy bajom van vele, hogy a date_diff() fv nem jó, mert pl.:

$datetime1 = date_create('2014-03-31');
$datetime2 = date_create('2014-04-30');
$interval = date_diff($datetime1, $datetime2);
echo $interval->format('%m months');
0 months ad vissza, pedig ez egy hónap. Gondolom a 30 és 31 hónapvége miatt.
Így persze jó, csak áprilisban nincs 31-dik nap:

$datetime1 = date_create('2014-03-31');
$datetime2 = date_create('2014-04-31');
$interval = date_diff($datetime1, $datetime2);
echo $interval->format('%m months');
// result: 1 months
Hogyan tudnám két hónapvége különbségét jól kiszámítani független attól, hogy a hónap 30 v. 31 napos?


G.
 
1

Definíció

Endyl · 2014. Ápr. 1. (K), 11.36
Definiáld mi számít egy hónapnak a te esetedben.

A DateInterval objektum 31 nap időtartamot számít egy hónapnak.
2

Nem egyszerű

Hidvégi Gábor · 2014. Ápr. 1. (K), 11.37
3

date

makgab · 2014. Ápr. 2. (Sze), 08.00
Kösz! Ezt mintha tényleg működne:

$date1 = "2014-03-31";
$date2 = "2014-04-30";

$diff = abs(strtotime($date2) - strtotime($date1));

$years = floor($diff / (365*60*60*24));
$months = floor(($diff - $years * 365*60*60*24) / (30*60*60*24));
$days = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24)/ (60*60*24));

printf("%d years, %d months, %d days\n", $years, $months, $days);
4

Február?

Endyl · 2014. Ápr. 2. (Sze), 13.32
A februári hónapvéggel még így (30 nappal számolva) is bajod lesz.

$date1 = "2014-01-31";
$date2 = "2014-02-28";
Plusz a fenti nyakatekert számítás helyett ugyanezt az eredményt megkaphatnád DateTime/DateInterval használatával is, egyszerűbben.
5

Igen, ez macerás... :(

makgab · 2014. Ápr. 2. (Sze), 19.31
Igen, ez macerás... :(
6

Ezért mondtam, hogy fogalmazd

Endyl · 2014. Ápr. 3. (Cs), 10.09
Ezért mondtam, hogy fogalmazd meg pontosan, a lehető legtöbb részletre kitérően, hogy mire van szükséged ennél a hónapszámításnál. Ha megvan az egyértelmű, emberi nyelvű definíciója a feladatnak, azt könnyebb programozási nyelvre fordítani.
7

Az általam belinkelt

Hidvégi Gábor · 2014. Ápr. 3. (Cs), 10.22
Az általam belinkelt fórumválasz második részében van egy fullextrás megoldás, ami figyelembe veszi még a szökőéveket is.
8

És az a megoldás is 28 napot

Endyl · 2014. Ápr. 3. (Cs), 11.32
És az a megoldás is 28 napot ad vissza az idei január és február utolsó napja között (nem egy hónapot, pedig ha jól értem, a kérdező ezt szeretné). Lehet, hogy az a legjobb kalapács a világon, de most lehet, hogy nem szöget kell beverni.

Próbálhatunk gondolatolvasni, de egy nem ismert feladatot nehéz megoldani.

Szerkesztve; január helyett márciust írtam először.



Pár teszt a fullextrás megoldásból:
2014-01-31
2014-02-28
----------
Normál: 0 hónap, 28 nap
Inverz: 0 hónap, 28 nap

2014-02-01
2014-03-01
----------
Normál: 1 hónap, 0 nap
Inverz: 1 hónap, 0 nap

2014-01-31
2014-03-01
----------
Normál: 0 hónap, 29 nap
Inverz: 1 hónap, 1 nap

2014-01-31
2014-04-01
----------
Normál: 2 hónap, 1 nap
Inverz: 2 hónap, 1 nap

2014-02-28
2014-04-01
----------
Normál: 1 hónap, 4 nap
Inverz: 1 hónap, 1 nap
9

Legalább a kérdezőnek is lesz

Hidvégi Gábor · 2014. Ápr. 3. (Cs), 11.44
Legalább a kérdezőnek is lesz kis gondolkodnivalója, hogy hol kell finomítani a kódon.
10

A kérdés alapvetően hülyeség,

MadBence · 2014. Ápr. 3. (Cs), 12.36
A kérdés alapvetően hülyeség, hiszen a hónap nem egy fix érték, hanem a kontextustól függ. Milyen bemenetre mi az elvárt eredmény?
Praktikusan a hónap 30 napos, és ezzel nagyon sok fejfájástól kíméled meg magad.
11

Gondolatolvasás

Endyl · 2014. Ápr. 3. (Cs), 13.45
Ezt mondom én is.

Egyébként szerintem valami ilyesmi kéne neki, elsősorban a hónap része:
date1     	date2     	diff

2014-01-31	2014-02-27	0 month(s), 27 day(s)

2014-01-31	2014-02-28	1 month(s), 0 day(s)

2014-01-31	2014-03-01	1 month(s), 1 day(s)

2014-01-31	2014-04-01	2 month(s), 1 day(s)

2014-02-01	2014-02-28	0 month(s), 27 day(s)

2014-02-01	2014-03-01	1 month(s), 0 day(s)

2014-02-28	2014-03-31	1 month(s), 3 day(s)

2014-02-28	2014-04-01	1 month(s), 4 day(s)
12

Logikus káosz

pkadam · 2014. Ápr. 3. (Cs), 17.38
A gond az, hogy bár a PHP dátumkezelése teljesen ésszerűen működik, a hónapok változékonysága miatt mégis furcsaságokra képes.

A hónapművelet ugye úgy működik, hogy a hónapot módosítja, majd ha az adott nap nem létezik, akkor továbblép a következő hónaphoz – annyi nappal, amennyi az utolsó létező nap és az eredeti nap különbsége. Így lehet például, hogy 2014-03-31 mínusz 1 hónap eredménye 2014-03-03 – míg egy nappal később számolva mégis az ennél két nappal korábbi 2014-03-01-et kapjuk.

Ebből adódóan az sem mindegy, hogy milyen sorrendben végezzük a műveleteket. A nulla végösszegű -1 hónap és +1 hónap, valamint ennek fordítottja:
date('Y-m-d', strtotime('+1 month',strtotime('-1 month',strtotime('2014-01-31'))));
>> 2014-01-31

date('Y-m-d', strtotime('-1 month',strtotime('+1 month',strtotime('2014-01-31'))));
>> 2014-02-03
De a különség lehet fordított is:
date('Y-m-d', strtotime('+1 month',strtotime('-1 month',strtotime('2014-03-29'))));
>> 2014-04-01

date('Y-m-d', strtotime('-1 month',strtotime('+1 month',strtotime('2014-03-29'))));
>> 2014-03-29
Tehát vagy igyekezzük kerülni az ilyen műveleteket, vagy fogadjuk el, hogy pontatlan lehet az eredménye. Mindenesetre célszerű meghatározni azt, hogy az alkalmazás szempontjából mit tartunk egy hónapnak, és maradjunk ehhez konzisztensek.

Nem véletlen, hogy a BKV-bérlet is 30 napos, és nem 1 hónapos – hiszen január 31-én vásárolva mi lenne az érvényesség vége? Február 27., mert az a következő hónap utolsó előtti napja? Vagy PHP-san március 2.? Előbbi esetben a 3 nappal korábban váltott bérletünk ugyanakkor járna le, utóbbiban viszont a 3 nappal később vásárolt lenne ugyanaddig érvényes. Ezek miatt minden olyan alkalmazáslogikai kérdés, ahol hónapokkal kell számolni, egyedi elbírálást igényel.