Asked  7 Months ago    Answers:  5   Viewed   48 times

I'm trying to get the difference between two datetimes and return it as a datetime. I've found examples using diff but I can't seem to get it right.

$timein = date("Y-m-d H:i:s");
$timeout = date("Y-m-d 20:00:00");
$totaltime = $timein->diff($timeout);

However $totaltime logs 0000-00-00 00:00:00 to my DB. Is this because I'm not formatting my totaltime variable?

 Answers

41

I'm not sure what format you're looking for in your difference but here's how to do it using DateTime

$datetime1 = new DateTime();
$datetime2 = new DateTime('2011-01-03 17:13:00');
$interval = $datetime1->diff($datetime2);
$elapsed = $interval->format('%y years %m months %a days %h hours %i minutes %s seconds');
echo $elapsed;
Friday, June 4, 2021
 
Jesse
answered 7 Months ago
50

Hmm fast solution, not optimized

$result = array();
foreach($a1 as $va1) {
   $found = false;
   foreach($a2 as $va2) {
      $x = array_diff($va1, $va2);
      if (empty($x)) {
         $found = true;
      }
   }
   if (!$found) { 
      $result[] = $va1;
   }
}

foreach($a2 as $va2) {
   $found = false;
   foreach($a1 as $va1) {
      $x = array_diff($va2, $va1);
      if (empty($x)) {
         $found = true;
      }
   }
   if (!$found) { 
      $result[] = $va2;
   }
}

var_dump($result);

EDIT: A little optimized (unseting values that were found before):

$a1= array(
      array('a'=>1,'b'=>2, 'c'=>3), // similar to $a2[0]
      array('a'=>3,'b'=>4, 'c'=>5), // similar to $a2[1]
      array('a'=>9,'b'=>6, 'c'=>9)
);
$a2= array(
      array('a'=>1,'b'=>2, 'c'=>3),
      array('a'=>3,'b'=>4, 'c'=>5),
      array('a'=>5,'b'=>6, 'c'=>7),
      array('a'=>11,'b'=>4, 'c'=>13),
      array('a'=>14,'b'=>6, 'c'=>3)
);
$i=0;
$result = array();
    foreach($a1 as $ka1 => $va1) {
       $found = false;
       foreach($a2 as $ka2 => $va2) {
          $i++;
          $x = array_diff($va1, $va2);
          if (empty($x)) {
             $found = true;
             unset($a2[$ka2], $a1[$ka1]);
          }
       }
       if (!$found) { 
          $result[] = $va1;
       }
    }
    foreach($a2 as $ka2 => $va2) {
   $found = false;
   foreach($a1 as $ka1 => $va1) {
      $i++;
      $x = array_diff($va2, $va1);
      if (empty($x)) {
         unset($a2[$ka2], $a1[$ka1]);
         $found = true;
      }
   }
   if (!$found) { 
      $result[] = $va2;
   }
}

var_dump($result);echo $i;
Wednesday, March 31, 2021
 
wavyGravy
answered 9 Months ago
21

I am getting the error: ... xsl:version: only 1.0 features are supported

Here's a purely XSLT 1.0 solution:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="event">
    <xsl:variable name="start">
        <xsl:call-template name="dateTime-to-seconds">
            <xsl:with-param name="dateTime" select="start/@time" />
        </xsl:call-template>
    </xsl:variable> 
    
    <xsl:variable name="end">
        <xsl:call-template name="dateTime-to-seconds">
            <xsl:with-param name="dateTime" select="end/@time" />
        </xsl:call-template>
    </xsl:variable>
    
    <xsl:variable name="duration" select="$end - $start" />
    <xsl:variable name="d" select="floor($duration div 86400)"/>
    <xsl:variable name="t" select="$duration mod 86400"/>
    <xsl:variable name="h" select="floor($t div 3600)"/>
    <xsl:variable name="r" select="$t mod 3600"/>
    <xsl:variable name="m" select="floor($r div 60)"/>
    <xsl:variable name="s" select="$r mod 60"/>
    
    <xsl:copy>
        <xsl:copy-of select="name"/>
        <duration>
            <xsl:value-of select="$d"/>
            <xsl:text> days, </xsl:text>
            <xsl:value-of select="$h"/>
            <xsl:text> hours, </xsl:text>
            <xsl:value-of select="$m"/>
            <xsl:text> minutes and </xsl:text>
            <xsl:value-of select="$s"/>
            <xsl:text> seconds</xsl:text>
        </duration>
    </xsl:copy>
</xsl:template>

<xsl:template name="dateTime-to-seconds">
    <xsl:param name="dateTime"/>

    <xsl:variable name="date" select="substring-before($dateTime, 'T')" />
    <xsl:variable name="time" select="substring-after($dateTime, 'T')" />

    <xsl:variable name="local-time" select="substring($time, 1, string-length($time) - 6)" />
    <xsl:variable name="offset" select="substring-after($time, $local-time)" />

    <xsl:variable name="year" select="substring($date, 1, 4)" />
    <xsl:variable name="month" select="substring($date, 6, 2)" />
    <xsl:variable name="day" select="substring($date, 9, 2)" />

    <xsl:variable name="hour" select="substring($local-time, 1, 2)" />
    <xsl:variable name="minute" select="substring($local-time, 4, 2)" />
    <xsl:variable name="second" select="substring($local-time, 7)" />

    <xsl:variable name="offset-sign" select="1 - 2 * starts-with($offset, '-')" />
    <xsl:variable name="offset-hour" select="substring($offset, 2, 2) * $offset-sign" />
    <xsl:variable name="offset-minute" select="substring($offset, 5, 2) * $offset-sign" />

    <xsl:variable name="a" select="floor((14 - $month) div 12)"/>
    <xsl:variable name="y" select="$year + 4800 - $a"/>
    <xsl:variable name="m" select="$month + 12*$a - 3"/>    
    <xsl:variable name="jd" select="$day + floor((153*$m + 2) div 5) + 365*$y + floor($y div 4) - floor($y div 100) + floor($y div 400) - 32045" />

    <xsl:value-of select="86400*$jd + 3600*$hour + 60*$minute + $second - 3600*$offset-hour - 60*$offset-minute" />
</xsl:template> 

</xsl:stylesheet>

Demo: http://xsltfiddle.liberty-development.net/aiyndK

Wednesday, June 9, 2021
 
lechup
answered 6 Months ago
24

You need to call DateInterval::format() to display that difference as a string.

echo $diff->format('%d days');

See the manual for all of the available formatting options.

Wednesday, July 7, 2021
 
mattltm
answered 5 Months ago
71

The behavior is correct. Both date intervals represent same number of days (364). The month and date part represent the period that needs to be added to/subtracted from first date to reach second date:

1981-11-20 minus 1980-11-21 represents an interval of 11 month 30 day
1980-11-21 + 11 month = 1981-10-21
1981-10-21 + 30 day   = 1981-10-21

1980-11-21 minus 1981-11-20 represents an interval of 11 month 29 day
1981-11-20 - 11 month = 1980-12-20
1980-12-20 - 29 day   = 1980-11-21

A simpler example would be Oct 21 ... Dec 20:

  • You need to add 1 month 29 days to Oct 21 to reach Dec 20 (note that month before Dec has 30 days)
  • But ... you need to subtract 1 month 30 days from Dec 20 to reach Oct 21. Oct itself has 31 days which explains the difference.
Sunday, August 15, 2021
 
ala
answered 4 Months ago
ala
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share