/*---------------------------------------------------------------------*\ | Date class - properties & methods for dealing with date values | \*---------------------------------------------------------------------*/ define("TEXTDATE",2); // for text (Mmmmmmmmmm dd, yyyy) define("LONGDATE",1); // long result (yyyy-mm-dd hh:mm:ss) define("SHORTDATE",0); // short result (yyyy-mm-dd) define("VERYSHORTDATE",-1); // very short date (mm/dd/yy) define("ONEDAY",86400); // one day's seconds class Date { static $months = array ('January','February','March','April','May','June','July', 'August','September','October','November','December'); static $javascript = 0; // toggle for javascript date handler public $date; // getdate array /* *::Compare two Date objects: * P1 = first Date object * P2 = second Date object * returns -1, 0, or 1 (<,=,>) */ static function compare($first,$second) { if ($first->date[0] == $second->date[0]) return 0; return ($first->date[0] < $second->date[0]) ? -1 : 1; } /* *::Obtain the +/-days difference between two Date objects: * P1 = first Date object * P2 = second Date object * returns the (signed) difference in days */ static function difference($first,$second) { $days = ($first->date[0]-$second->date[0])/ONEDAY; return $days; } /* *::Convert any date to an internal date * P1 = date value as string--i.e. mm/dd/yyyy, etc. * P2 = format: LONGDATE,SHORTDATE or VERYSHORTDATE * returns an internal date in the requested format */ static function toInternal($date=null,$format=SHORTDATE) { $obj = $date ? new Date($date) : new Date; return $obj->internal($format); } /* *::Convert any date to an external date * P1 = date value as string--i.e. mm/dd/yyyy, etc. * P2 = format: LONGDATE,SHORTDATE or VERYSHORTDATE * returns an external date in the requested format */ static function toExternal($date=null,$format=SHORTDATE) { $obj = $date ? new Date($date) : new Date; return $obj->external($format); } /* * Constructor: * P1 = (optional) date value */ public function __construct($value=null) { if (!func_num_args()) $this->date = getdate(); else $this->set($value); } /* * Destructor: */ public function __destruct() {} /* * Determine if this object contains a valid date: * returns true (valid) or false (invalid) */ public function valid() { return ($this->date ? true : false); } /* * Set the date value for this object: * P1 = (optional) date value, default = now() */ public function set($value=null) { if (! $value) { $this->date = null; return; } $this->date = getdate(); while ($value) { // MySql timestamp: if (preg_match('/^\s*(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})\s*$/',$value,$parts)) { $this->date['year'] = 0+$parts[1]; $this->date['mon'] = 0+$parts[2]; $this->date['mday'] = 0+$parts[3]; $this->date['hours'] = 0+$parts[4]; $this->date['minutes'] = 0+$parts[5]; $this->date['seconds'] = 0+$parts[6]; break; } // Unix timestamp: if (preg_match('/^\s*([-]?\d{6,})\s*$/',$value,$parts)) { $this->date = getdate(0+$parts[1]); return; } // MySql internal date and time format: if (preg_match('/^(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2})$/',$value,$parts)) { $this->date['year'] = 0+$parts[1]; $this->date['mon'] = 0+$parts[2]; $this->date['mday'] = 0+$parts[3]; $this->date['hours'] = 0+$parts[4]; $this->date['minutes'] = 0+$parts[5]; $this->date['seconds'] = 0+$parts[6]; break; } // MySql internal date format: if (preg_match('/^(\d{4})-(\d{2})-(\d{2})$/',$value,$parts)) { $this->date['year'] = 0+$parts[1]; $this->date['mon'] = 0+$parts[2]; $this->date['mday'] = 0+$parts[3]; $this->date['hours'] = $this->date['minutes'] = $this->date['seconds'] = 0; break; } // only hour specified: if (preg_match('/^\s*(\d{1,2})\s*$/',$value,$parts)) { $this->date['hours'] = 0+$parts[1]; $this->date['minutes'] = $this->date['seconds'] = 0; break; } // only hour and meridian) specified: if (preg_match('/^\s*(\d{1,2})\s*([AaPp]{1}).*$/',$value,$parts)) { $this->date['hours'] = 0+$parts[1]; $this->date['minutes'] = $this->date['seconds'] = 0; $meridian = strtolower($parts[2]); if ($meridian=='a' && $this->date['hours']==12) $this->date['hours'] = 0; else if ($meridian=='p' && $this->date['hours']<12) $this->date['hours'] += 12; break; } // only hour and minutes (and maybe meridian) specified: if (preg_match('/^\s*(\d{1,2}):(\d{1,2})\s*([AaPp]?).*$/',$value,$parts)) { $this->date['hours'] = 0+$parts[1]; $this->date['minutes'] = 0+$parts[2]; $this->date['seconds'] = 0; $meridian = strtolower($parts[3]); if ($meridian=='a' && $this->date['hours']==12) $this->date['hours'] = 0; else if ($meridian=='p' && $this->date['hours']<12) $this->date['hours'] += 12; break; } // only hours, minutes and seconds (and maybe meridian) specified: if (preg_match('/^\s*(\d{1,2}):(\d{1,2}):(\d{1,2})\s*([AaPp]?).*$/',$value,$parts)) { $this->date['hours'] = 0+$parts[1]; $this->date['minutes'] = 0+$parts[2]; $this->date['seconds'] = 0+$parts[3]; $meridian = strtolower($parts[4]); if ($meridian=='a' && $this->date['hours']==12) $this->date['hours'] = 0; else if ($meridian=='p' && $this->date['hours']<12) $this->date['hours'] += 12; break; } $this->date['hours'] = $this->date['minutes'] = $this->date['seconds'] = 0; // look for m/d/y: if (preg_match('/^(\d{1,2})[\/\-\.](\d{1,2})[\/\-\.](\d{1,4})/',$value,$parts)) { if ($parts[3] < 100) if ($parts[3] < 50) $parts[3] += 2000; else $parts[3] += 1900; $this->date['mon'] = 0+$parts[1]; $this->date['mday'] = 0+$parts[2]; $this->date['year'] = 0+$parts[3]; } else // look for m/d: if (preg_match('/^(\d{1,2})[\/\-\.](\d{1,2})/',$value,$parts)) { $this->date['mon'] = 0+$parts[1]; $this->date['mday'] = 0+$parts[2]; } // look for hh:mm:ss if (preg_match('/(\d{1,2}):(\d{1,2}):(\d{1,2})/',$value,$parts)) { $this->date['hours'] = 0+$parts[1]; $this->date['minutes'] = 0+$parts[2]; $this->date['seconds'] = 0+$parts[3]; } else // look for hh:mm if (preg_match('/(\d{1,2}):(\d{1,2})/',$value,$parts)) { $this->date['hours'] = 0+$parts[1]; $this->date['minutes'] = 0+$parts[2]; } else if (preg_match('/(\d{1,2})[AaPp]/',$value,$parts)) $this->date['hours'] = 0+$parts[1]; if (preg_match('/[Aa]/',$value) && ($this->date['hours'] == 12)) $this->date['hours'] = 00; else if (preg_match('/[Pp]/',$value) && ($this->date['hours'] < 12)) $this->date['hours'] += 12; break; } $this->date[0] = mktime( $this->date['hours'], $this->date['minutes'], $this->date['seconds'], $this->date['mon'], $this->date['mday'], $this->date['year'] ); $this->date = getdate($this->date[0]); } /* * Return an internal (SQL) date for this object: * P1 = (optional) toggle, long or short result * returns a string as: yyyy-mm-dd( hh:mm:ss) */ public function internal($size=SHORTDATE) { if (! $this->valid()) return null; $result = sprintf("%04d-%02d-%02d", $this->date['year'],$this->date['mon'],$this->date['mday']); if ($size!=SHORTDATE) $result .= sprintf(" %02d:%02d:%02d",$this->date['hours'], $this->date['minutes'],$this->date['seconds']); return $result; } /* * Return an external date for this object: * P1 = (optional) toggle: text, long, short or very short result * returns a string as: mm/dd/(yy)yy( hh:mm:ss a|pm) or Mmmmmmmm dd, yyyy */ public function external($size=SHORTDATE) { if (! $this->valid()) return null; $result = sprintf("%d/%d/%04d",$this->date['mon'],$this->date['mday'],$this->date['year']); if ($size==VERYSHORTDATE) { $year = $this->date['year'] - (($this->date['year'] < 2000) ? 1900 : 2000); return sprintf("%d/%d/%02d",$this->date['mon'],$this->date['mday'],$year); } if ($size==TEXTDATE) { return sprintf( "%s %d, %04d", self::$months[$this->date['mon']-1], $this->date['mday'], $this->date['year'] ); } if ($size==LONGDATE) { $hour = $this->date['hours']; $mer = "am"; if ($hour < 12) { $mer = "am"; if ($hour == 0) $hour = 12; } else { $mer = "pm"; if ($hour > 12) $hour -= 12; } $result .= sprintf(" %d:%02d %s",$hour,$this->date['minutes'],$mer); } return $result; } /* * Move the object's date by various intervals: * P1 = interval to move the date, i.e. * "(-)nn second(s)" * "(-)nn minute(s)" * "(-)nn hour(s)" * "(-)nn day(s)" * "(-)nn weekday(s)" * "(-)nn week(s)" * "(-)nn month(s)" * "(-)nn quarter(s)" * "(-)nn year(s)" * returns internal value for new date */ public function move($interval=null) { if (! $this->valid()) return null; preg_match('/([0-9-]+)\s*([a-zA-Z]+)*/',$interval,$parts); $reps = 0+$parts[1]; $step = strtolower($parts[2]); if (! $reps) return $this->internal(LONGDATE); if (preg_match('/weekday/',$step)) { $count = abs($reps); $cursor = ($reps < 0) ? -1 : 1; while ($count--) while (1) { $this->date = getdate(mktime( $this->date['hours'], $this->date['minutes'], $this->date['seconds'], $this->date['mon'], ($this->date['mday']+$cursor), $this->date['year'] )); if (($this->date['wday']>0) && ($this->date['wday']<6)) break; } return $this->internal(LONGDATE); } switch ($step) { case "hour": case "hours": $this->date['hours'] += $reps; break; case "minute": case "minutes": $this->date['minutes'] += $reps; break; case "second": case "seconds": $this->date['seconds'] += $reps; break; case "week": case "weeks": $this->date['mday'] += ($reps * 7); break; case "month": case "months": $this->date['mon'] += $reps; break; case "quarter": case "quarters": $this->date['mon'] += ($reps * 3); break; case "year": case "years": $this->date['year'] += $reps; break; case "day": case "days": default: $this->date['mday'] += $reps; break; } $this->date = getdate(mktime( $this->date['hours'], $this->date['minutes'], $this->date['seconds'], $this->date['mon'], $this->date['mday'], $this->date['year'] )); return $this->internal(LONGDATE); } /* * Return the html for selecting the date(& time) starting with object value: * P1 = name of the html object/form result * P2 = (optional) length of the returned value (SHORTDATE or LONGDATE) * P3 = (optional) css class for the fields * returns html string for the form fields */ public function select($name,$size=SHORTDATE,$class=null) { $html = ""; if (! self::$javascript++) $html = << // Build date(&time) field from parts // call w/ID of date field function buildDate(id) { var e=document.getElementById(id),n=e.name,f=e.form; if ( eval('f.'+n+'_yr.selectedIndex==0') || eval('f.'+n+'_mo.selectedIndex==0') || eval('f.'+n+'_dy.selectedIndex==0')) { e.value=''; return; } var yr=Number(eval('f.'+n+'_yr.options[f.'+n+'_yr.selectedIndex].value')); var mo=Number(eval('f.'+n+'_mo.options[f.'+n+'_mo.selectedIndex].value')); var dy=Number(eval('f.'+n+'_dy.options[f.'+n+'_dy.selectedIndex].value')); yr=yr.toString(); mo=mo.toString(); if (mo.length<2) mo='0'+mo; dy=dy.toString(); if (dy.length<2) dy='0'+dy; e.value=yr+'-'+mo+'-'+dy; if (eval('typeof f.'+n+'_hh')=='undefined') return; // no time if (eval('f.'+n+'_hh.selectedIndex==0')) return; if (eval('f.'+n+'_mm.selectedIndex')==0) eval('f.'+n+'_mm.selectedIndex=1'); var hh=Number(eval('f.'+n+'_hh.options[f.'+n+'_hh.selectedIndex].value')); var mm=Number(eval('f.'+n+'_mm.options[f.'+n+'_mm.selectedIndex].value')); var ss=0; var mer=eval('f.'+n+'_mer.options[f.'+n+'_mer.selectedIndex].value'); if (hh==12) hh=0; if (mer=='pm') hh+=12; hh=hh.toString(); if (hh.length<2) hh='0'+hh; mm=mm.toString(); if (mm.length<2) mm='0'+mm; ss=ss.toString(); if (ss.length<2) ss='0'+ss; e.value=e.value+' '+hh+':'+mm+':'+ss; } ETX; $two = "%02d"; $four = "%04d"; $css = $class ? " class=\"{$class}\"" : null; $mo = $this->date['mon']; $dy = $this->date['mday']; $yr = $this->date['year']; $hh = $this->date['hours']; $mm = $this->date['minutes']; $mer = "am"; if ($this->valid()) { if ($hh >= 12) { $mer = "pm"; if ($hh > 12) $hh -= 12; } if (! $hh) $hh = 12; } $default = $this->internal($size); if ($size && $default) $default = substr($default,0,-2) . "00"; $html .= "\n"; $html .= ""; $html .= ""; $html .= "\n"; if (! $size) return $html; $html .= ""; $html .= ""; $html .= "\n"; return $html; } }