Διαφορά δύο ημερομηνιών σε Ημέρες - Μήνες - Έτη

Σε αυτή την περιοχή μπορείτε να βρείτε ή να αναζητήσετε πληροφορίες σχετικές με την PHP

Συντονιστές: WebDev Moderators, Super-Moderators, PHP Moderators

Απάντηση
Άβαταρ μέλους
dva_dev
Script Master
Δημοσιεύσεις: 3790
Εγγραφή: 16 Σεπ 2005 01:32
Επικοινωνία:

Διαφορά δύο ημερομηνιών σε Ημέρες - Μήνες - Έτη

Δημοσίευση από dva_dev » 20 Σεπ 2012 19:38

Μετά από το πρόσφατο θέμα [^] , αλλά και προηγούμενα (ενδεικτικά: 1,2) για να υπολογίσουμε τη διαφορά δύο ημερομηνιών σε ημέρες η διαδικασία είναι αρκετά απλή:

Κώδικας: Επιλογή όλων

$dtStart = "2011-01-21";  //Αρχική ημερομηνία - προγενέστερη
$dtStop  = "2013-03-10";  //Τελική ημερομηνία - μεταγενέστερη
$diff = abs(strtotime($dtStop) - strtotime($dtStart));
//Εχουμε τη διαφορά σε δευτερόλεπτα και την κάνουμε ημέρες
$days = floor($diff / (60*60*24));
Αν θέλουμε όμως αυτή τη διαφορά να την κάνουμε ημέρες-μήνες-έτη, το πρώτο πράγμα (και το ευκολότερο) που μας έρχεται στο μυαλό είναι να θεωρήσουμε ότι ο χρόνος έχει 365 μέρες και ο μήνας 30. Να κάνουμε τις αντίστοιχες διαιρέσεις και να πάρουμε κάποια το αποτέλεσμα. Αλλά αν το σκεφτούμε λίγο περισσότερο, βλέπουμε ότι το πράγμα δεν είναι τόσο απλό γιατί οι μήνες δεν έχουν όλοι 30 ημέρες, και επιπλέον έχουμε και τον Φλεβάρη που είναι ακόμα πιο βιτσιόζικος που όποτε του καπνίσει έχει 28/29.

Η επόμενη λύση είναι να χρησιμοποιήσουμε τις functions που δίνει η php. Τις χρησιμοποιούμε τόσο καιρό και τις εμπιστευόμαστε με κλειστά τα μάτια.
Υπάρχει η DateTime::diff() που επιστρέφει τη διαφορά σε ένα DateInterval object που έχει member variables που μας δίνουν τα έτη, τους μήνες και τις μέρες ξεχωριστά.
Οπότε γράφουμε κώδικα σαν τον ακόλουθο (ή πιο object oriented και λιγότερο functional)

Κώδικας: Επιλογή όλων

    $dtStart = date_date_set(date_create(),2012,1,21);   //21/01/2012
    $dtStop  = date_date_set(date_create(),2013,3,10);   //10/03/2013
    $diff = date_diff($dtStart,$dtStop);
    echo 'Years  : ',$diff->y,PHP_EOL,
         'Months : ',$diff->m,PHP_EOL,
         'Days   : ',$diff->d,PHP_EOL;
Δουλεύει μια χαρά, αλλά έχει ένα "μικρό" πρόβλημα. Αρκετές φορές (όπως το συγκεκριμένο παράδειγμα) δεν επιστρέφει το σωστό αριθμό ημερών.

Τελικά η λύση που μένει είναι ο custom κώδικας. Με λίγο ή πολύ ψάξιμο στο internet μπορεί κάποιος να βρει κώδικα, αλλά για να μην χρειάζεται να ψάχνετε παραπέρα, ορίστε και μια εκδοχή σε php (είναι και έτοιμο στο πιάτο).

Κώδικας: Επιλογή όλων

function dmydiff($dateS, $dateE)
{
	$dS = getdate($dateS);
	$dE = getdate($dateE);

	$DMY = array('Y'=>0, 'M'=>0, 'D'=>0);

	$DMY['Y'] = $dE['year'] - $dS['year'];
	$DMY['M'] = $dE['mon']  - $dS['mon'];
	$DMY['D'] = $dE['mday'] - $dS['mday'];

	if &#40;$DMY&#91;'D'&#93; < 0&#41;
	&#123;
		$dT = mktime&#40;0, 0, 0,$dS&#91;'mon'&#93;+1, 1, $dS&#91;'year'&#93;&#41;;
		$dT = intval&#40;&#40;$dT - $dateS&#41; / 84600&#41;;  //84600 = 24*60*60
		$DMY&#91;'D'&#93; =  $dT + $dE&#91;'mday'&#93; - 1;
		$DMY&#91;'M'&#93;--;
	&#125;
	if &#40;$DMY&#91;'M'&#93; < 0&#41;
	&#123;
		$DMY&#91;'Y'&#93;--;
		$DMY&#91;'M'&#93; += 12;
	&#125;

	return $DMY;
&#125;
Η χρήση του θεωρητικά είναι απλή:

Κώδικας: Επιλογή όλων

$dtStart = strtotime&#40;'2012-01-21'&#41;;
$dtStop  = strtotime&#40;'2013-03-10'&#41;;
$diff = dmyDiff&#40;$dtStart, $dtStop&#41;;
echo 'Years  &#58; ',$diff&#91;'Y'&#93;,PHP_EOL,
     'Months &#58; ',$diff&#91;'M'&#93;,PHP_EOL,
     'Days   &#58; ',$diff&#91;'D'&#93;,PHP_EOL;
Θεωρητικά δεν υπάρχουν bugs, αλλά αν βρείτε κάποια, ξέρετε: finders keepers.

[edit]
Σημειώνω ότι δεν έχει μπει έλεγχος αν η $dateS είναι όντως προγενέστερη της $dateE. Αυτό αν χρειαστεί μπορεί να γίνει στο input validation.
Τελευταία επεξεργασία από το μέλος dva_dev την 20 Σεπ 2012 20:33, έχει επεξεργασθεί 1 φορά συνολικά.

Άβαταρ μέλους
korgr
Honorary Member
Δημοσιεύσεις: 5067
Εγγραφή: 07 Οκτ 2008 18:30
Τοποθεσία: Corinth
Επικοινωνία:

Διαφορά δύο ημερομηνιών σε Ημέρες - Μήνες - Έτη

Δημοσίευση από korgr » 20 Σεπ 2012 20:09

Πολύ ωραίος! :clap:

gvre
Δημοσιεύσεις: 990
Εγγραφή: 14 Οκτ 2010 11:34
Τοποθεσία: Ηράκλειο Κρήτης
Επικοινωνία:

Διαφορά δύο ημερομηνιών σε Ημέρες - Μήνες - Έτη

Δημοσίευση από gvre » 20 Σεπ 2012 21:03

dva_dev έγραψε:

Κώδικας: Επιλογή όλων

    $dtStart = date_date_set&#40;date_create&#40;&#41;,2012,1,21&#41;;   //21/01/2012
    $dtStop  = date_date_set&#40;date_create&#40;&#41;,2013,3,10&#41;;   //10/03/2013
    $diff = date_diff&#40;$dtStart,$dtStop&#41;;
    echo 'Years  &#58; ',$diff->y,PHP_EOL,
         'Months &#58; ',$diff->m,PHP_EOL,
         'Days   &#58; ',$diff->d,PHP_EOL;
Δουλεύει μια χαρά, αλλά έχει ένα "μικρό" πρόβλημα. Αρκετές φορές (όπως το συγκεκριμένο παράδειγμα) δεν επιστρέφει το σωστό αριθμό ημερών.
Σε εμένα πάντως λειτουργεί το συγκεκριμένο παράδειγμα και εμφανίζει το παρακάτω αποτέλεσμα.

Years : 1
Months : 1
Days : 17

Ο custom κώδικας εμφανίζει 20 ημέρες αντί 17.

Άβαταρ μέλους
dva_dev
Script Master
Δημοσιεύσεις: 3790
Εγγραφή: 16 Σεπ 2005 01:32
Επικοινωνία:

Διαφορά δύο ημερομηνιών σε Ημέρες - Μήνες - Έτη

Δημοσίευση από dva_dev » 20 Σεπ 2012 21:15

11 μερες μεχρι την 1η του επομενου μηνα
1 μηνας ακομα
9 μερες μεχρι την 10η του μηνα
1 χρονος ακομα
Συνολο: 1 ετος 1 μηνας 20 μερες

gvre
Δημοσιεύσεις: 990
Εγγραφή: 14 Οκτ 2010 11:34
Τοποθεσία: Ηράκλειο Κρήτης
Επικοινωνία:

Διαφορά δύο ημερομηνιών σε Ημέρες - Μήνες - Έτη

Δημοσίευση από gvre » 20 Σεπ 2012 21:33

Από 21/01/2012 έως 21/01/2013 είναι 1 έτος.
Από 21/01/2013 έως 21/02/2013 είναι 1 μήνας.
Από 21/02/2013 έως 10/03/2013 είναι 17 ημέρες.

Σύνολο: 1 έτος, 1 μήνας και 17 ημέρες :)

Άβαταρ μέλους
dva_dev
Script Master
Δημοσιεύσεις: 3790
Εγγραφή: 16 Σεπ 2005 01:32
Επικοινωνία:

Διαφορά δύο ημερομηνιών σε Ημέρες - Μήνες - Έτη

Δημοσίευση από dva_dev » 20 Σεπ 2012 21:40

Και από 31/1/2012 ώς την 20/3/2012 πόσο είναι;
(απλώς μετακίνησα όλο το διάστημα 10 μέρες πάνω).

Από 31/1/2012 - 31/1/2013 = 1 έτος
Από 31/1/2013 - ???? = ? μήνες
Από ???? - 20/3/2013 = ? μέρες

gvre
Δημοσιεύσεις: 990
Εγγραφή: 14 Οκτ 2010 11:34
Τοποθεσία: Ηράκλειο Κρήτης
Επικοινωνία:

Διαφορά δύο ημερομηνιών σε Ημέρες - Μήνες - Έτη

Δημοσίευση από gvre » 20 Σεπ 2012 22:47

dva_dev έγραψε:Και από 31/1/2012 ώς την 20/3/2012 πόσο είναι;
(απλώς μετακίνησα όλο το διάστημα 10 μέρες πάνω).

Από 31/1/2012 - 31/1/2013 = 1 έτος
Από 31/1/2013 - ???? = ? μήνες
Από ???? - 20/3/2013 = ? μέρες
1 μήνας και 18 ημέρες :)
Λογικό αυτό που λες αλλά ο υπολογισμός γίνεται μάλλον με άλλο τρόπο. Θα το ψάξω περισσότερο και αν βρω κάτι θα ενημερώσω.

Άβαταρ μέλους
dva_dev
Script Master
Δημοσιεύσεις: 3790
Εγγραφή: 16 Σεπ 2005 01:32
Επικοινωνία:

Διαφορά δύο ημερομηνιών σε Ημέρες - Μήνες - Έτη

Δημοσίευση από dva_dev » 20 Σεπ 2012 23:45

Δες και αυτό. Δεν χρειάζεται και πολύ ψάξιμο για να καταλάβεις ότι κάτι πάει στραβά στη DateTime. Kάθε φορά προσθέτω στο διάστημα 1 μήνα και οι ημερομηνίες είναι από την 1η μέχρι την 1η.

Κώδικας: Επιλογή όλων

                         DateTime    dmyDiff
                         EE-MM-HH   EE-MM-HH
01/01/2012-01/01/2012&#58;    0  0  0    0  0  0
01/01/2012-01/02/2012&#58;    0  1  0    0  1  0
01/01/2012-01/03/2012&#58;    0  1 29    0  2  0
01/01/2012-01/04/2012&#58;    0  3  0    0  3  0
01/01/2012-01/05/2012&#58;    0  3 30    0  4  0
01/01/2012-01/06/2012&#58;    0  5  0    0  5  0
01/01/2012-01/07/2012&#58;    0  5 30    0  6  0
01/01/2012-01/08/2012&#58;    0  7  0    0  7  0
01/01/2012-01/09/2012&#58;    0  8  0    0  8  0
01/01/2012-01/10/2012&#58;    0  8 30    0  9  0
01/01/2012-01/11/2012&#58;    0 10  0    0 10  0
01/01/2012-01/12/2012&#58;    0 10 30    0 11  0

01/01/2013-01/01/2013&#58;    0  0  0    0  0  0
01/01/2013-01/02/2013&#58;    0  1  0    0  1  0
01/01/2013-01/03/2013&#58;    0  1 28    0  2  0
01/01/2013-01/04/2013&#58;    0  3  0    0  3  0
Επίσης σύγκρινε και αυτά:

Κώδικας: Επιλογή όλων

01/01/2012-01/03/2012&#58;    0  1 29    0  2  0
01/01/2013-01/03/2013&#58;    0  1 28    0  2  0
Από 21/01/2012 έως 21/01/2013 είναι 1 έτος.
Από 21/01/2013 έως 21/02/2013 είναι 1 μήνας.
Από 21/02/2013 έως 10/03/2013 είναι 17 ημέρες.

Σύνολο: 1 έτος, 1 μήνας και 17 ημέρες
Για πάρτο και ανάποδα:
Από 21/01/2012 έως 10/02/2012 είναι 20 ημέρες.
Από 10/02/2013 έως 10/03/2012 είναι 1 μήνας.
Από 10/03/2012 έως 10/03/3013 είναι 1 έτος.

Σύνολο: 1 έτος, 1 μήνας και 20 ημέρες. :hammer:

Άβαταρ μέλους
fafos
Script Master
Δημοσιεύσεις: 6230
Εγγραφή: 30 Νοέμ 2004 03:09

Διαφορά δύο ημερομηνιών σε Ημέρες - Μήνες - Έτη

Δημοσίευση από fafos » 21 Σεπ 2012 02:48

To sosto einai 1 etos, 1 mhnas kai 17 hmeres... epishs prepei na prosexoume kai thn timezone otan prokeitai na metrhsoume kai ores,lepta,deyterolepta..

xrhsimopoiousa auto (den thymamai pou to vrhka):

Κώδικας: Επιλογή όλων

<?php
 
  //timezone
  date_default_timezone_set&#40;"UTC"&#41;;
 
  function dateDiff&#40;$time1, $time2, $precision = 6&#41; &#123;
    if &#40;!is_int&#40;$time1&#41;&#41; &#123;
      $time1 = strtotime&#40;$time1&#41;;
    &#125;
    if &#40;!is_int&#40;$time2&#41;&#41; &#123;
      $time2 = strtotime&#40;$time2&#41;;
    &#125;

    if &#40;$time1 > $time2&#41; &#123;
      $ttime = $time1;
      $time1 = $time2;
      $time2 = $ttime;
    &#125;
 
    $intervals = array&#40;'year','month','day','hour','minute','second'&#41;;
    $diffs = array&#40;&#41;;
 
    foreach &#40;$intervals as $interval&#41; &#123;
      $diffs&#91;$interval&#93; = 0;
      $ttime = strtotime&#40;"+1 " . $interval, $time1&#41;;
      while &#40;$time2 >= $ttime&#41; &#123;
	$time1 = $ttime;
	$diffs&#91;$interval&#93;++;
	$ttime = strtotime&#40;"+1 " . $interval, $time1&#41;;
      &#125;
    &#125;
 
    $count = 0;
    $times = array&#40;&#41;;
    foreach &#40;$diffs as $interval => $value&#41; &#123;
      if &#40;$count >= $precision&#41; &#123;
	break;
      &#125;
      if &#40;$value > 0&#41; &#123;
	if &#40;$value != 1&#41; &#123;
	  $interval .= "s";
	&#125;
	$times&#91;&#93; = $value . " " . $interval;
	$count++;
      &#125;
    &#125;
    return implode&#40;", ", $times&#41;;
  &#125;
  
$date1 = "2012-01-21 12&#58;20&#58;00";
$date2 = "2013-03-10 20&#58;50&#58;30"; 

echo $diff = dateDiff&#40;$date1, $date2&#41;;
 
?>

Οι πάνες και οι πολιτικοί πρέπει να αλλάζονται συχνά για τον ίδιο λόγο...

Άβαταρ μέλους
dva_dev
Script Master
Δημοσιεύσεις: 3790
Εγγραφή: 16 Σεπ 2005 01:32
Επικοινωνία:

Διαφορά δύο ημερομηνιών σε Ημέρες - Μήνες - Έτη

Δημοσίευση από dva_dev » 21 Σεπ 2012 09:40

Αν η DateTime έβγαζε σωστά αποτελέσματα για τους μήνες και τις ημέρες δεν θα έβγαζε μάτι με αυτά.

Κώδικας: Επιλογή όλων

                         DateTime    dmyDiff
                         EE-MM-HH   EE-MM-HH

Διάστημα 1 μηνός ολόκληρου
01/02/2012-01/03/2012&#58;    0  0 29    0  1  0

Διάστημα 2 μηνών
01/03/2012-01/05/2012&#58;    0  2  1    0  2  0

Διάστημα 3 μηνών
01/03/2012-01/06/2012&#58;    0  3  2    0  3  0
01/04/2012-01/07/2012&#58;    0  2 30    0  3  0
01/05/2012-01/08/2012&#58;    0  3  1    0  3  0

gvre
Δημοσιεύσεις: 990
Εγγραφή: 14 Οκτ 2010 11:34
Τοποθεσία: Ηράκλειο Κρήτης
Επικοινωνία:

Διαφορά δύο ημερομηνιών σε Ημέρες - Μήνες - Έτη

Δημοσίευση από gvre » 21 Σεπ 2012 09:47

Το πρόβλημα στους υπολογισμούς οφείλεται στο timezone. Αν οι υπολογισμοί γίνουν με UTC, τότε τα αποτελέσματα είναι σωστά.

Κώδικας: Επιλογή όλων

date_default_timezone_set&#40;'UTC'&#41;;
$datetime1 = new DateTime&#40;'2012-02-01'&#41;;
$datetime2 = new DateTime&#40;'2012-03-01'&#41;;
$interval = $datetime1->diff&#40;$datetime2&#41;;
echo $interval->format&#40;"%y years, %m months and %d days\n"&#41;;

$datetime1 = new DateTime&#40;'2012-03-01'&#41;;
$datetime2 = new DateTime&#40;'2012-05-01'&#41;;
$interval = $datetime1->diff&#40;$datetime2&#41;;
echo $interval->format&#40;"%y years, %m months and %d days\n"&#41;;

gvre
Δημοσιεύσεις: 990
Εγγραφή: 14 Οκτ 2010 11:34
Τοποθεσία: Ηράκλειο Κρήτης
Επικοινωνία:

Διαφορά δύο ημερομηνιών σε Ημέρες - Μήνες - Έτη

Δημοσίευση από gvre » 21 Σεπ 2012 10:18

Χρήσιμοι σύνδεσμοι σχετικά με διαχείριση και αποθήκευση ημερομηνιών.

Storing Date/Times in Databases
Daylight saving time and Timezone best practices

Απάντηση

Επιστροφή στο “PHP Προγραμματισμός”

Μέλη σε σύνδεση

Μέλη σε αυτήν τη Δ. Συζήτηση: Δεν υπάρχουν εγγεγραμμένα μέλη και 0 επισκέπτες