Date Calculations

The times they are a-changin’.

This post seems to be older than 17 years—a long time on the internet. It might be outdated.

I’m working on the 1.8 release of Countdown Timer and I’m trying to rework part of it to do better accounting. As it stands, I have a simple function called cdt_hms (countdown timer hours minutes seconds) that does some pretty straight forward math. Originally, it assumes there are 31536000 seconds in a year (365*24*60*60), 2592000 seconds in a month (30*24*60*60), and so on.

There were some assumptions being made. First, a year is not always 365 days. On leap years, it’s 366. (And in reality, it’s 365.2425… days/year, we just round down and add the leap year in ever four instead). It also assumes that months are 30 days long. On integer average they are (365/12 = 30.4166 ≅ 30). However, over time, this creates comes discrepancies.

So I reworked the script a little to account for the fact that if you have 30 days in a month, you’d only have 3110400 seconds in a year and not the required 31536000 for an actual year. This was creating a weird situation where you would have 12 months that wouldn’t add up to a year. A no man’s land, if you will, for time.

Here’s the code as it stands now. This is for WordPress, so there are some WP specific functions in there. Just try to go with the flow:

function cdt_hms($s, $min=1){
	global $getOptions;
	load_plugin_textdomain('afdn_countdownTimer', 'wp-content/plugins');
		$years=intval($s/31536000); //How many years?
		$years = $years + (intval($s/31104000) - $years); //Deal with the discrepency between actual years and ideal years
		$s = $s - ($years*31536000);
		if ($years) //If there are any years, display them
			$r=$r.abs($years).' '.($years==1?__("year", "afdn_countdownTimer"):__("years", "afdn_countdownTimer")).', '; //Absolute values (ABS function) are used to be compatible with counting up from events
		$s = $s - $months*2592000;
		if($months) //If there are any years, display them
			$r=$r.abs($months).' '.($months==1?__("month", "afdn_countdownTimer"):__("months", "afdn_countdownTimer")).', ';
		$days=intval($s/86400); //How many days?
		$s = $s - $days*86400;
		if ($days) //If there are any days, display them
			$r=$r.abs($days).' '.($days==1?__("day", "afdn_countdownTimer"):__("days", "afdn_countdownTimer")).', ';
		$hours=intval($s/3600); //How many hours?
		$s = $s - $hours*3600;
		if ($hours) //If there are any hours, display them
			$r=$r.abs($hours).' '.($hours==1?__("hour", "afdn_countdownTimer"):__("hours", "afdn_countdownTimer")).', ';
		$minutes=intval($s/60); //How many minutes?
		$s = $s - $minutes*60;
		if($min) //If we want minutes, display them
			$r=$r.abs($minutes).' '.($minutes==1?__("minute", "afdn_countdownTimer"):__("minutes", "afdn_countdownTimer")).', ';
		$r = $r.abs($s).' '.($minutes==1?__("second", "afdn_countdownTimer"):__("seconds", "afdn_countdownTimer")).', ';
	return rtrim($r,", "); //...and return the result (a string)

However, even this code creates some issues. It does better accounting, but the accounting is wrong. It dealt with the 5 day discrepancy between actual years and ideal years by checking to see if the discrepancy between the two was more then 5 days. If it was, it would just round up to the year.

Thus, I whipped up some new code to try and deal with with this issue. Not entirely sure how to accomplish this, I took out a piece of paper and wrote down two days:

  Year Month Day Hour Minute Second
Target 2007 5 4 12 00 00
Current 2007 5 3 16 30 00
Difference 0 0 1 -4 -30 0

The target date is what I’m counting down to. The current date was the time at that point. The difference was the arithmetic difference between the two. But what to do about those negative numbers? The same thing you do with regular math. I ended up with 19 hours and 30 minutes to the target date. Perfect.

So I whipped up some code to do just that. The really isn’t that much more complex, it’s just really long:

function fergcorp_fuzzyDate($targetTime, $nowTime){
global $getOptions;

$rollover = 0;
$s = ”;

$nowYear = date(“Y”, $nowTime);
$nowMonth = date(“m”, $nowTime);
$nowDay = date(“d”, $nowTime);
$nowHour = date(“H”, $nowTime);
$nowMinute = date(“i”, $nowTime);
$nowSecond = date(“s”, $nowTime);

$targetYear = date(“Y”, $targetTime);
$targetMonth = date(“m”, $targetTime);
$targetDay = date(“d”, $targetTime);
$targetHour = date(“H”, $targetTime);
$targetMinute = date(“i”, $targetTime);
$targetSecond = date(“s”, $targetTime);

$resultantYear = $targetYear – $nowYear;
$resultantMonth = $targetMonth – $nowMonth;
$resultantDay = $targetDay – $nowDay;
$resultantHour = $targetHour – $nowHour;
$resultantMinute = $targetMinute – $nowMinute;
$resultantSecond = $targetSecond – $nowSecond;

if($resultantSecond < 0){ $resultantMinute--; $resultantSecond = 60 + $resultantSecond; } if($resultantMinute < 0){ $resultantHour--; $resultantMinute = 60 + $resultantMinute; } if($resultantHour < 0){ $resultantDay--; $resultantHour = 24 + $resultantHour; } if($resultantDay < 0){ $resultantMonth--; $resultantDay = $resultantDay + date("t", $targetMonth); } if($resultantMonth < 0){ $resultantYear--; $resultantMonth = $resultantMonth + 12; } load_plugin_textdomain('afdn_countdownTimer', 'wp-content/plugins'); //Year if($getOptions['showYear']){ $s = $resultantYear.' '.($resultantYear==1?__("year", "afdn_countdownTimer"):__("years", "afdn_countdownTimer")).', ';; } else{ $rollover = $resultantYear*31536000; } //Month if($getOptions['showMonth']){ $s = $s.($resultantMonth + intval($rollover/2592000)).' '.($resultantMonth==1?__("month", "afdn_countdownTimer"):__("months", "afdn_countdownTimer")).', '; $rollover = $rollover - intval($rollover/2592000)*2592000; } else{ $rollover = $rollover + $resultantMonth*2592000; } //Day if($getOptions['showDay']){ $s = $s.($resultantDay + intval($rollover/86400)).' '.($resultantDay==1?__("day", "afdn_countdownTimer"):__("days", "afdn_countdownTimer")).', '; $rollover = $rollover - intval($rollover/86400)*86400; } else{ $rollover = $rollover + $resultantDay*86400; } //Hour if($getOptions['showHour']){ $s = $s.($resultantHour + intval($rollover/3600)).' '.($resultantHour==1?__("hour", "afdn_countdownTimer"):__("hours", "afdn_countdownTimer")).', '; $rollover = $rollover - intval($rollover/3600)*3600; } else{ $rollover = $rollover + $resultantHour*3600; } //Minute if($getOptions['showMinute']){ $s = $s.($resultantMinute + intval($rollover/60)).' '.($resultantMinute==1?__("minute", "afdn_countdownTimer"):__("minutes", "afdn_countdownTimer")).', '; $rollover = $rollover - intval($rollover/60)*60; } else{ $rollover = $rollover + $resultantMinute*60; } //Second if($getOptions['showSecond']){ $s = $s.($resultantSecond + intval($rollover/86400)).' '.($resultantSecond==1?__("second", "afdn_countdownTimer"):__("seconds", "afdn_countdownTimer")).', '; } return rtrim($s,", "); //...and return the result (a string) } [/code] And now the dates should be calculated better!