=" ) ) {
date_default_timezone_set( @date_default_timezone_get() );
}
$this->display_offset = $_display_offset;
$this->server_offset = mktime(0,0,0,1,2,1970) - gmmktime(0,0,0,1,2,1970);
}
/**
* Retrieves the user's preferred offset for displaying dates.
*
* @param int the logged-in user.
* @return int the preferred offset to UTC or 0 for straight UTC display
*/
public function get_display_offset($_user = false) {
global $gBitUser;
// Cache preference from DB
$display_tz = "UTC";
// Default to UTC get_display_offset
$this->display_offset = 0;
// Load pref from DB if cache is empty
$display_tz = $gBitUser->getPreference('site_display_utc', "Local");
// Recompute offset each request in case DST kicked in
if ( $display_tz == "Local" && isset($_COOKIE["tz_offset"]))
$this->display_offset = (int) ($_COOKIE["tz_offset"]);
else if ( $display_tz == "Fixed" )
$this->display_offset = $gBitUser->getPreference( 'site_display_timezone', 0 );
if ( version_compare( phpversion(), "5.1.0", ">=" ) and !is_numeric( $this->display_offset ) ) {
$dateTimeZoneUser = new \DateTimeZone( $this->display_offset );
$dtNow = new \DateTime( "now" );
$this->display_offset = $dateTimeZoneUser->getOffset( $dtNow );
}
return $this->display_offset;
}
/**
* Convert a UTC timestamp to the preferred display offset.
* @param string timestamp ISO format date
* yYYY-mM-dD hH:mM:sS.s ( Lower case letters optional, but should be 0 )
* @return int Seconds count based on 1st Jan 1970
*/
public function getDisplayDateFromUTC($_timestamp) {
global $gBitUser;
if ( $gBitUser->getPreference('site_display_utc', "Local") == "Fixed" && class_exists( 'DateTime' ) ) {
date_default_timezone_set( $gBitUser->getPreference( 'site_display_timezone', 'UTC' ) );
$dateTimeUser = is_numeric( $_timestamp )
? new \DateTime( '@'.$_timestamp )
: new \DateTime( $_timestamp );
$dateTimeUserZone = new \DateTimeZone( $gBitUser->getPreference( 'site_display_timezone', 'UTC' ) );
return strtotime( $dateTimeUser->format(DATE_ATOM) ) + timezone_offset_get( $dateTimeUserZone, $dateTimeUser );
}
return $this->getTimestampFromISO($_timestamp) + $this->display_offset;
}
/**
* Convert a display-offset timestamp to UTC.
* @param string timestamp ISO format date
* yYYY-mM-dD hH:mM:sS.s ( Lower case letters optional, but should be 0 )
* @return int Seconds count based on 1st Jan 1970
*/
public function getUTCFromDisplayDate($_timestamp) {
global $gBitUser;
if ( $gBitUser->getPreference('site_display_utc', "Local") == "Fixed" ) {
date_default_timezone_set( $gBitUser->getPreference( 'site_display_timezone', 'UTC' ) );
$dateTimeUser = is_numeric( $_timestamp )
? new \DateTime( '@'.$_timestamp )
: new \DateTime( $_timestamp );
$dateTimeUserZone = new \DateTimeZone( $gBitUser->getPreference( 'site_display_timezone', 'UTC' ) );
return strtotime( $dateTimeUser->format(DATE_ATOM) ) - timezone_offset_get( $dateTimeUserZone, $dateTimeUser );
}
return $this->getTimestampFromISO($_timestamp) - $this->display_offset;
}
/**
* Convert a UTC timestamp to the local server time.
* @param string timestamp UTC timestamp to convert.
* @return string timestamp Server timestamp.
*/
public function getServerDateFromUTC($_timestamp) {
return $this->getTimestampFromISO($_timestamp) + $this->server_offset;
}
/**
* Convert a local server timestamp to UTC.
* @param string timestamp Server timestamp to convert.
* @return string timestamp UTC timestamp.
*/
public function getUTCFromServerDate($_timestamp) {
return $this->getTimestampFromISO($_timestamp) - $this->server_offset;
}
/**
* Retrieve a current UTC timestamp as Unix epoch.
* @return int Unix epoch
*/
public function getUTCTime() {
return time();
}
/**
* Retrieve a current UTC Timestamp as an ISO formated date/time.
* @return string Current ISO formated date/time
*/
public function getUTCTimestamp() {
return $this->date("Y-m-d H:i:s",time(),true);
}
/**
* Retrieve a current UTC Date as an ISO formated date
* @return string Current ISO formated date
*/
public function getUTCDate() {
return $this->date("Y-m-d",time(),true);
}
/**
* Get the name of the current timezone.
* Currently, only "UTC" or an empty string (Local).
* @return string Current timezone
*/
public function getTzName() {
return $this->display_offset == 0 ? "UTC" : '';
}
/**
* Convert ISO date to numberic timestamp.
*
* @param string ISO format date
* yYYY-mM-dD hH:mM:sS.s ( Lower case letters optional, but should be 0 )
* @return int Seconds count based on 1st Jan 1970
* returns $iso_date if it is a number, or 0 if format invalid
*/
public function getTimestampFromISO( $iso_date, $reverse = false ) {
$ret = 0;
if ( is_numeric($iso_date) ) {
$ret = $iso_date;
} else if ( $reverse ) {
// Input d.m.y, h:m:s
if (preg_match(
"|^([0-9]{1,2})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{3,4}), ?(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,8}))?|",
$iso_date, $rr, ))
$ret = !isset($rr[5])
? $this->gmmktime(0,0,0,$rr[2],$rr[1],$rr[3])
: $ret = @$this->gmmktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[1],$rr[3]);
} else {
// Input y.m.d h:m:s
if (preg_match(
"|^([0-9]{3,4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ -]?(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|",
$iso_date, $rr, ))
$ret = !isset($rr[5])
? $this->gmmktime(0,0,0,$rr[2],$rr[3],$rr[1])
: $ret = @$this->gmmktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);
}
return $ret;
}
/**
* Returns day of week, 0 = Sunday,... 6=Saturday.
* Algorithm from PEAR::Date_Calc
* @param int
* @param int
* @param int
* @return int
*/
public function dayOfWeek($year, $month, $day) {
/*
Pope Gregory removed 10 days - October 5 to October 14 - from the year 1582 and
proclaimed that from that time onwards 3 days would be dropped from the calendar
every 400 years.
Thursday, October 4, 1582 (Julian) was followed immediately by Friday, October 15, 1582 (Gregorian).
*/
$greg_correction = $year <= 1582
? ($year < 1582 || ($year == 1582 && ($month < 10 || ($month == 10 && $day < 15))) ? 3: 0) : 0;
if($month > 2)
$month -= 2;
else {
$month += 10;
$year--;
}
$day = floor((13 * $month - 1) / 5) +
$day + ($year % 100) +
floor(($year % 100) / 4) +
floor(($year / 100) / 4) - 2 *
floor($year / 100) + 77 + $greg_correction;
return $day - 7 * floor($day / 7);
}
/**
* Returns week of year, 1 = first week of year.
* Algorithm from PEAR::Date_Calc
* This needs to be checked out for both start day and early date rules
* @param int
* @param int
* @param int
* @return int
*/
public function weekOfYear($year, $month, $day)
{
$iso = $this->gregorianToISO($year, $month, $day);
$parts = explode('-',$iso);
$week_number = (int) ($parts[1]);
if ( $week_number == 0 ) $week_number = 53;
return $week_number;
}
/**
* Checks for leap year, returns true if it is. No 2-digit year check. Also
* handles julian calendar correctly.
* @param int
* @return bool
*/
public function _is_leap_year($year)
{
if ($year % 4 != 0) return false;
if ($year % 400 == 0) {
return true;
// if gregorian calendar (>1582), century not-divisible by 400 is not leap
} else if ($year > 1582 && $year % 100 == 0 ) {
return false;
}
return true;
}
/**
* checks for leap year, returns true if it is. Has 2-digit year check
* @param int
* @return bool
*/
public function is_leap_year($year)
{
return $this->_is_leap_year($this->year_digit_check($year));
}
/**
* Fix 2-digit years. Works for any century.
* Assumes that if 2-digit is more than 30 years in future, then previous century.
* @todo This needs to be disabled when dates prior to 100AD are required in ISO format
* @param int
* @return int
*/
public function year_digit_check($y) {
if ($y < 100) {
$yr = (int) date("Y");
$century = (int) ($yr /100);
if ($yr%100 > 50) {
$c1 = $century + 1;
$c0 = $century;
} else {
$c1 = $century;
$c0 = $century - 1;
}
$c1 *= 100;
// if 2-digit year is less than 30 years in future, set it to this century
// otherwise if more than 30 years in future, then we set 2-digit year to the prev century.
$y = ($y + $c1) < $yr+30 ? $y + $c1 : $y + $c0*100;
}
return $y;
}
/**
*Returns an array with date info.
* @param boolean
* @param boolean
* @return array
*/
public function getDate($d=false,$fast=false) {
if ($d === false) return $this->getdate();
if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer
return @$this->_getDate($d);
}
return $this->_getDate($d,$fast);
}
/*
* generate $YRS table for _adodb_getdate()
*
function _date_gentable($out=true)
{
for ($i=1970; $i >= 1600; $i-=10) {
$s = adodb_gmmktime(0,0,0,1,1,$i);
echo "$i => $s,
";
}
}
adodb_date_gentable();
for ($i=1970; $i > 1500; $i--) {
echo "
$i ";
adodb_date_test_date($i,1,1);
}
*/
/**
* Low-level function that returns the getdate() array. We have a special
* $fast flag, which if set to true, will return fewer array values,
* and is much faster as it does not calculate dow, etc.
* @param int Date to be converted in Unix epochs
* @param boolean Return short format array ( less weekday and month )
* @param boolean Ignore timezone
* @return array
*/
public function _getDate($origd=false,$fast=false,$is_gmt=false ) {
static $YRS;
$d = $origd - ($is_gmt ? 0 : adodb_get_gmt_diff(false,false,false));
$_day_power = 86400;
$_hour_power = 3600;
$_min_power = 60;
if ($d < -12219321600) $d -= 86400*10; // if 15 Oct 1582 or earlier, gregorian correction
$_month_table_normal = [ "", 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];
$_month_table_leaf = [ "", 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];
$d366 = $_day_power * 366;
$d365 = $_day_power * 365;
if ($d < 0) {
if (empty($YRS)) $YRS = [
1970 => 0,
1960 => -315619200,
1950 => -631152000,
1940 => -946771200,
1930 => -1262304000,
1920 => -1577923200,
1910 => -1893456000,
1900 => -2208988800,
1890 => -2524521600,
1880 => -2840140800,
1870 => -3155673600,
1860 => -3471292800,
1850 => -3786825600,
1840 => -4102444800,
1830 => -4417977600,
1820 => -4733596800,
1810 => -5049129600,
1800 => -5364662400,
1790 => -5680195200,
1780 => -5995814400,
1770 => -6311347200,
1760 => -6626966400,
1750 => -6942499200,
1740 => -7258118400,
1730 => -7573651200,
1720 => -7889270400,
1710 => -8204803200,
1700 => -8520336000,
1690 => -8835868800,
1680 => -9151488000,
1670 => -9467020800,
1660 => -9782640000,
1650 => -10098172800,
1640 => -10413792000,
1630 => -10729324800,
1620 => -11044944000,
1610 => -11360476800,
1600 => -11676096000,
];
if ($is_gmt) $origd = $d;
// The valid range of a 32bit signed timestamp is typically from
// Fri, 13 Dec 1901 20:45:54 GMT to Tue, 19 Jan 2038 03:14:07 GMT
//
$lastsecs = 0;
$lastyear = 1970;
foreach($YRS as $year => $secs) {
if ($d >= $secs) {
$a = $lastyear;
break;
}
$lastsecs = $secs;
$lastyear = $year;
}
$d -= $lastsecs;
if (!isset($a)) $a = $lastyear;
for (; --$a >= 0;) {
$lastd = $d;
if ($leaf = $this->is_leap_year($a)) $d += $d366;
else $d += $d365;
if ($d >= 0) {
$year = $a;
break;
}
}
$secsInYear = 86400 * ($leaf ? 366 : 365) + $lastd;
$d = $lastd;
$mtab = $leaf ? $_month_table_leaf : $_month_table_normal;
for ($a = 13 ; --$a > 0;) {
$lastd = $d;
$d += $mtab[$a] * $_day_power;
if ($d >= 0) {
$month = $a;
$ndays = $mtab[$a];
break;
}
}
$d = $lastd;
$day = $ndays + ceil(($d+1) / $_day_power);
$d += ($ndays - $day+1)* $_day_power;
$hour = floor($d/$_hour_power);
} else {
for ($a = 1970 ;; $a++) {
$lastd = $d;
if ($leaf = $this->is_leap_year($a)) $d -= $d366;
else $d -= $d365;
if ($d < 0) {
$year = $a;
break;
}
}
$secsInYear = $lastd;
$d = $lastd;
$mtab = $leaf ? $_month_table_leaf : $_month_table_normal;
for ($a = 1 ; $a <= 12; $a++) {
$lastd = $d;
$d -= $mtab[$a] * $_day_power;
if ($d < 0) {
$month = $a;
$ndays = $mtab[$a];
break;
}
}
$d = $lastd;
$day = ceil(($d+1) / $_day_power);
$d -= ($day-1) * $_day_power;
$hour = floor($d /$_hour_power);
}
$d -= $hour * $_hour_power;
$min = floor($d/$_min_power);
$secs = $d - $min * $_min_power;
if ($fast) {
return [
'seconds' => $secs,
'minutes' => $min,
'hours' => $hour,
'mday' => $day,
'mon' => $month,
'year' => $year,
'yday' => floor( $secsInYear / $_day_power ),
'leap' => $leaf,
'ndays' => $ndays,
];
}
$dow = adodb_dow($year,$month,$day);
return [
'seconds' => $secs,
'minutes' => $min,
'hours' => $hour,
'mday' => $day,
'wday' => $dow,
'mon' => $month,
'year' => $year,
'yday' => floor( $secsInYear / $_day_power ),
'weekday' => gmdate( 'l', $_day_power * ( 3 + $dow ) ),
'month' => gmdate( 'F', mktime( 0, 0, 0, $month, 2, 1971 ) ),
0 => $origd,
];
}
/*
* Accepts unix timestamp and iso date format
* ISO format date is converted into unix timestamp before calling date()
* @param string Format of date output
* @param int/string Date to be converted
* @param boolean Ignore timezone
* @return string In the format specified by $fmt
*/
public function date2($fmt, $d=false, $is_gmt=false) {
if ( is_numeric($d) ) $this->date($fmt,$d,$is_gmt);
if ($d !== false) {
if (!preg_match(
"|^([0-9]{3,4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ -]?(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|",
$d, $rr, )) return $this->date($fmt,false,$is_gmt);
if ($rr[1] <= 100 && $rr[2]<= 1) return adodb_date($fmt,false,$is_gmt);
// h-m-s-MM-DD-YY
$d = !isset($rr[5])
? adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1])
: @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);
}
return $this->date($fmt,$d,$is_gmt);
}
/**
* Return formatted date based on timestamp $d
* @param string Format of date output
* @param int Date to be converted
* @param boolean Ignore timezone
* @return string In the format specified by $fmt
*/
public function date($fmt,$d=false,$is_gmt=false){
static $daylight;
if ($d === false) return $is_gmt ? @gmdate($fmt) : @date($fmt);
if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer
return $is_gmt ? @gmdate($fmt,$d) : @date($fmt,$d);
}
$_day_power = 86400;
$arr = $this->_getdate($d,true,$is_gmt);
// if (!isset($daylight)) $daylight = function_exists('adodb_daylight_sv');
// if ($daylight) adodb_daylight_sv($arr, $is_gmt);
$year = $arr['year'];
$month = $arr['mon'];
$day = $arr['mday'];
$hour = $arr['hours'];
$min = $arr['minutes'];
$secs = $arr['seconds'];
$max = strlen($fmt);
$dates = '';
/*
at this point, we have the following integer vars to manipulate:
$year, $month, $day, $hour, $min, $secs
*/
for ($i=0; $i < $max; $i++) {
switch($fmt[$i]) {
case 'T': $dates .= $this->date('T'); break;
// YEAR
case 'L': $dates .= $arr['leap'] ? '1' : '0'; break;
case 'r': // Thu, 21 Dec 2000 16:01:07 +0200
// 4.3.11 uses '04 Jun 2004'
// 4.3.8 uses ' 4 Jun 2004'
$dates .= gmdate('D',$_day_power*(3+\adodb_dow($year,$month,$day))).', '
. ($day<10?'0'.$day:$day) . ' '.date('M',mktime(0,0,0,$month,2,1971)).' '.$year.' ';
if ($hour < 10) $dates .= '0'.$hour; else $dates .= $hour;
if ($min < 10) $dates .= ':0'.$min; else $dates .= ':'.$min;
if ($secs < 10) $dates .= ':0'.$secs; else $dates .= ':'.$secs;
$gmt = adodb_get_gmt_diff(false,false,false);
$dates .= sprintf(' %s%04d',($gmt<0)?'+':'-',abs($gmt)/36); break;
case 'Y': $dates .= $year; break;
case 'y': $dates .= substr($year,strlen($year)-2,2); break;
// MONTH
case 'm': if ($month<10) $dates .= '0'.$month; else $dates .= $month; break;
case 'Q': $dates .= ($month+3)>>2; break;
case 'n': $dates .= $month; break;
case 'M': $dates .= date('M',mktime(0,0,0,$month,2,1971)); break;
case 'F': $dates .= date('F',mktime(0,0,0,$month,2,1971)); break;
// DAY
case 't': $dates .= $arr['ndays']; break;
case 'z': $dates .= $arr['yday']; break;
case 'w': $dates .= adodb_dow($year,$month,$day); break;
case 'l': $dates .= gmdate('l',$_day_power*(3+adodb_dow($year,$month,$day))); break;
case 'D': $dates .= gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))); break;
case 'j': $dates .= $day; break;
case 'd': if ($day<10) $dates .= '0'.$day; else $dates .= $day; break;
case 'S':
$d10 = $day % 10;
if ($d10 == 1) $dates .= 'st';
else if ($d10 == 2 && $day != 12) $dates .= 'nd';
else if ($d10 == 3) $dates .= 'rd';
else $dates .= 'th';
break;
// HOUR
case 'Z':
$dates .= $is_gmt ? 0 : -adodb_get_gmt_diff(false,false,false); break;
case 'O':
$gmt = $is_gmt ? 0 : adodb_get_gmt_diff(false,false,false);
$dates .= sprintf('%s%04d',($gmt<0)?'+':'-',abs($gmt)/36); break;
case 'H':
if ($hour < 10) $dates .= '0'.$hour;
else $dates .= $hour;
break;
case 'h':
$hh = $hour > 12 ? $hour - 12 : ( $hour == 0 ? '12' : $hour );
if ($hh < 10) $dates .= '0'.$hh;
else $dates .= $hh;
break;
case 'G':
$dates .= $hour;
break;
case 'g':
$hh = $hour > 12 ? $hour - 12 : ( $hour == 0 ? '12' : $hour );
$dates .= $hh;
break;
// MINUTES
case 'i': if ($min < 10) $dates .= '0'.$min; else $dates .= $min; break;
// SECONDS
case 'U': $dates .= $d; break;
case 's': if ($secs < 10) $dates .= '0'.$secs; else $dates .= $secs; break;
// AM/PM
// Note 00:00 to 11:59 is AM, while 12:00 to 23:59 is PM
case 'a':
if ($hour>=12) $dates .= 'pm';
else $dates .= 'am';
break;
case 'A':
if ($hour>=12) $dates .= 'PM';
else $dates .= 'AM';
break;
default:
$dates .= $fmt[$i]; break;
// ESCAPE
case "\\":
$i++;
if ($i < $max) $dates .= $fmt[$i];
break;
}
}
return $dates;
}
/**
* Returns a timestamp given a GMT/UTC time.
* @param int Hour
* @param int Minute
* @param int Second
* @param int Month
* @param int Day
* @param int Year
* @param int $is_dst is not implemented and is ignored
* @return int
*/
public function gmmktime($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_dst=false)
{
return $this->mktime($hr,$min,$sec,$mon,$day,$year,$is_dst,true);
}
/**
* Return a timestamp given a local time. Originally by jackbbs.
* Not a very fast algorithm - O(n) operation. Could be optimized to O(1).
* @param int Hour
* @param int Minute
* @param int Second
* @param int Month
* @param int Day
* @param int Year
* @param int $is_dst is not implemented and is ignored
* @return int
*/
public function mktime($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_dst=false,$is_gmt=false)
{
if ($mon === false) {
return $is_gmt? @gmmktime($hr,$min,$sec): @mktime($hr,$min,$sec);
/* Need to check if this can be deleted
// for windows, we don't check 1970 because with timezone differences,
// 1 Jan 1970 could generate negative timestamp, which is illegal
if (1971 < $year && $year < 2038
|| !defined('ADODB_NO_NEGATIVE_TS') && (1901 < $year && $year < 2038)
) {
return $is_gmt ?
@gmmktime($hr,$min,$sec,$mon,$day,$year):
@mktime($hr,$min,$sec,$mon,$day,$year);
}
*/
}
$gmt_different = $is_gmt ? 0 : $this->server_offset;
/*
# disabled because some people place large values in $sec.
# however we need it for $mon because we use an array...
$hr = intval($hr);
$min = intval($min);
$sec = intval($sec);
*/
$mon = (int) $mon;
$day = (int) $day;
$year = (int) $year;
$year = $this->year_digit_check($year);
if ($mon > 12) {
$y = floor($mon / 12);
$year += $y;
$mon -= $y*12;
}
else if ( $mon <= 0 ) {
$mon += 12;
$year -= 1;
}
$_day_power = 86400;
$_hour_power = 3600;
$_min_power = 60;
$_month_table_normal = [ "", 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];
$_month_table_leaf = [ "", 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];
$_total_date = 0;
if ($year >= 1970) {
for ($a = 1970 ; $a <= $year; $a++) {
$leaf = $this->is_leap_year($a);
if ($leaf == true) {
$loop_table = $_month_table_leaf;
$_add_date = 366;
} else {
$loop_table = $_month_table_normal;
$_add_date = 365;
}
if ($a < $year) {
$_total_date += $_add_date;
} else {
for($b=1;$b<$mon;$b++) {
$_total_date += $loop_table[$b];
}
}
}
$_total_date +=$day-1;
$ret = $_total_date * $_day_power + $hr * $_hour_power + $min * $_min_power + $sec + $gmt_different;
} else {
for ($a = 1969 ; $a >= $year; $a--) {
$leaf = $this->is_leap_year($a);
if ($leaf == true) {
$loop_table = $_month_table_leaf;
$_add_date = 366;
} else {
$loop_table = $_month_table_normal;
$_add_date = 365;
}
if ($a > $year) { $_total_date += $_add_date;
} else {
for($b=12;$b>$mon;$b--) {
$_total_date += $loop_table[$b];
}
}
}
$_total_date += $loop_table[$mon] - $day;
$_day_time = $hr * $_hour_power + $min * $_min_power + $sec;
$_day_time = $_day_power - $_day_time;
$ret = -( $_total_date * $_day_power + $_day_time - $gmt_different);
if ($ret < -12220185600) $ret += 10*86400; // if earlier than 5 Oct 1582 - gregorian correction
else if ($ret < -12219321600) $ret = -12219321600; // if in limbo, reset to 15 Oct 1582.
}
//print " dmy=$day/$mon/$year $hr:$min:$sec => " .$ret;
return $ret;
}
public function gmstrftime($fmt, $ls=false)
{
return $this->strftime($fmt,$ls,true);
}
public function strtotime($time, $now=null)
{
if ($now == null)
return strtotime($time);
return strtotime($time, $now);
}
// hack - convert to adodb_date
public static function strftime($fmt, $ls=false,$is_gmt=false)
{
global $ADODB_DATE_LOCALE;
// TODO FIX GMT DATES using IntlDateFormatter::format
$formatter = new \IntlDateFormatter('en_GB', \IntlDateFormatter::LONG, \IntlDateFormatter::NONE);
if ((abs($ls) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
if (!defined('ADODB_NO_NEGATIVE_TS') || $ls >= 0) // if windows, must be +ve integer
return $is_gmt ? @$formatter->format($ls) : @$formatter->format($ls);
}
if (empty($ADODB_DATE_LOCALE)) {
$tstr = strtoupper($formatter->format(time())); // 30 Dec 1970, 1 am
$sep = substr($tstr,2,1);
$hasAM = strrpos($tstr,'M') !== false;
$ADODB_DATE_LOCALE = [];
$ADODB_DATE_LOCALE[] = strncmp($tstr,'30',2) == 0 ? 'd'.$sep.'m'.$sep.'y' : 'm'.$sep.'d'.$sep.'y';
$ADODB_DATE_LOCALE[] = $hasAM ? 'h:i:s a' : 'H:i:s';
}
$inpct = false;
$fmtdate = '';
for ($i=0,$max = strlen($fmt); $i < $max; $i++) {
$ch = $fmt[$i];
if ($ch == '%') {
if ($inpct) {
$fmtdate .= '%';
$inpct = false;
} else
$inpct = true;
} else if ($inpct) {
$inpct = false;
switch($ch) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'E':
case 'O':
/* ignore format modifiers */
$inpct = true;
break;
case 'a': $fmtdate .= 'D'; break;
case 'A': $fmtdate .= 'l'; break;
case 'h':
case 'b': $fmtdate .= 'M'; break;
case 'B': $fmtdate .= 'F'; break;
case 'c': $fmtdate .= $ADODB_DATE_LOCALE[0].$ADODB_DATE_LOCALE[1]; break;
case 'C': $fmtdate .= '\C?'; break; // century
case 'd': $fmtdate .= 'd'; break;
case 'D': $fmtdate .= 'm/d/y'; break;
case 'e': $fmtdate .= 'j'; break;
case 'g': $fmtdate .= '\g?'; break; //?
case 'G': $fmtdate .= '\G?'; break; //?
case 'H': $fmtdate .= 'H'; break;
case 'I': $fmtdate .= 'h'; break;
case 'j': $fmtdate .= '?z'; $parsej = true; break; // wrong as j=1-based, z=0-basd
case 'm': $fmtdate .= 'm'; break;
case 'M': $fmtdate .= 'i'; break;
case 'n': $fmtdate .= "\n"; break;
case 'p': $fmtdate .= 'a'; break;
case 'r': $fmtdate .= 'h:i:s a'; break;
case 'R': $fmtdate .= 'H:i:s'; break;
case 'S': $fmtdate .= 's'; break;
case 't': $fmtdate .= "\t"; break;
case 'T': $fmtdate .= 'H:i:s'; break;
case 'u': $fmtdate .= '?u'; $parseu = true; break; // wrong strftime=1-based, date=0-basde
case 'U': $fmtdate .= '?U'; $parseU = true; break;// wrong strftime=1-based, date=0-based
case 'x': $fmtdate .= $ADODB_DATE_LOCALE[0]; break;
case 'X': $fmtdate .= $ADODB_DATE_LOCALE[1]; break;
case 'w': $fmtdate .= '?w'; $parseu = true; break; // wrong strftime=1-based, date=0-basde
case 'W': $fmtdate .= '?W'; $parseU = true; break;// wrong strftime=1-based, date=0-based
case 'y': $fmtdate .= 'y'; break;
case 'Y': $fmtdate .= 'Y'; break;
case 'Z': $fmtdate .= 'T'; break;
}
} else if (('A' <= $ch && $ch <= 'Z' ) || ('a' <= $ch && $ch <= 'z' ))
$fmtdate .= "\\".$ch;
else
$fmtdate .= $ch;
}
//echo "fmt=",$fmtdate,"
";
if ($ls === false) $ls = time();
$ret = $is_gmt ? gmdate( $fmtdate, $ls ) : date( $fmtdate, $ls );
return $ret;
}
/**
* Converts from Gregorian Year-Month-Day to ISO YearNumber-WeekNumber-WeekDay
*
* Uses ISO 8601 definitions.
* Algorithm from Rick McCarty, 1999 at http://personal.ecu.edu/mccartyr/ISOwdALG.txt
*
* @param int $year
* @param int $month
* @param int $day
* @return string
* @access public
*/
// Transcribed to PHP by Jesus M. Castagnetto (blame him if it is fubared ;-)
public function gregorianToISO($year, $month, $day) {
$mnth = [0,31,59,90,120,151,181,212,243,273,304,334];
if ($month == 0) {
$year--;
$month = 12;
}
$y_isleap = $this->is_leap_year($year);
$y_1_isleap = $this->is_leap_year($year - 1);
$day_of_year_number = $day + $mnth[$month - 1];
if ($y_isleap && $month > 2) {
$day_of_year_number++;
}
// find Jan 1 weekday (monday = 1, sunday = 7)
$yy = ($year - 1) % 100;
$c = ($year - 1) - $yy;
$g = $yy + (int) ($yy/4);
$jan1_weekday = 1 + (int) (($c / 100 % 4 * 5 + $g) % 7);
// weekday for year-month-day
$h = $day_of_year_number + ($jan1_weekday - 1) - 1;
$weekday = 1 + (int) (($h - 1) % 7);
// find if Y M D falls in YearNumber Y-1, WeekNumber 52 or
if ($day_of_year_number <= (8 - $jan1_weekday) && $jan1_weekday > 4){
$yearnumber = $year - 1;
$weeknumber = $jan1_weekday == 5 || ($jan1_weekday == 6 && $y_1_isleap) ? 53 : 52;
} else {
$yearnumber = $year;
}
// find if Y M D falls in YearNumber Y+1, WeekNumber 1
if ($yearnumber == $year) {
$i = $y_isleap ? 366 : 365;
if (($i - $day_of_year_number) < (4 - $weekday)) {
$yearnumber++;
$weeknumber = 1;
}
}
// find if Y M D falls in YearNumber Y, WeekNumber 1 through 53
if ($yearnumber == $year) {
$j = $day_of_year_number + (7 - $weekday) + ($jan1_weekday - 1);
//$weeknumber = intval($j / 7) + 1; // kludge!!! - JMC
$weeknumber = (int) ($j / 7); // kludge!!! - JMC
if ($jan1_weekday > 4) {
$weeknumber--;
}
}
// put it all together
if ($weeknumber < 10)
$weeknumber = '0'.$weeknumber;
return "{$yearnumber}-{$weeknumber}-{$weekday}";
}
/**
* Get a list of timezones to be worked with
*/
public function get_timezone_list($use_default = false) {
static $timezone_options;
if (!$timezone_options) {
$timezone_options = [];
if ($use_default)
$timezone_options['default'] = '-- Use Default Time Zone --';
foreach ($GLOBALS['_DATE_TIMEZONE_DATA'] as $tz_key => $tz) {
$offset = $tz['offset'];
$absoffset = abs($offset /= 60000);
$plusminus = $offset < 0 ? '-' : '+';
$gmtoff = sprintf("GMT%1s%02d:%02d", $plusminus, $absoffset / 60, $absoffset - (int) ($absoffset / 60) * 60);
$tzlongshort = $tz['longname'] . ' (' . $tz['shortname'] . ')';
$timezone_options[$tz_key] = sprintf('%-28.28s: %-36.36s %s', $tz_key, $tzlongshort, $gmtoff);
}
}
return $timezone_options;
}
/**
* Per http://www.w3.org/TR/NOTE-datetime
*/
public function get_iso8601_datetime($timestamp, $user = false) {
return $this->strftime('%Y-%m-%dT%H:%M:%S%O', $timestamp, $user);
}
public function get_rfc2822_datetime($timestamp = false, $user = false) {
if (!$timestamp)
$timestamp = time();
# rfc2822 requires dates to be en formatted
$saved_locale = @setlocale(0, '');
@setlocale (0, 'en_US');
#was return date('D, j M Y H:i:s ', $time) . $this->timezone_offset($time, 'no colon');
$rv = $this->strftime('%a, %e %b %Y %H:%M:%S', $timestamp, $user). $this->get_rfc2822_timezone_offset($timestamp, $user);
# switch back to the 'saved' locale
if ($saved_locale)
@setlocale (0, $saved_locale);
return $rv;
}
/**
* Summary of get_rfc2822_timezone_offset
* @param mixed $time
* @param mixed $no_colon
* @param mixed $user
* @return string
*/
public function get_rfc2822_timezone_offset($time = false, $no_colon = false, $user = false) {
if ($time === false)
$time = time();
$secs = $this->strftime('%Z', $time, $user);
if ($secs < 0) {
$sign = '-';
$secs = -$secs;
} else {
$sign = '+';
}
$colon = $no_colon ? '' : ':';
$mins = (int) (($secs + 30) / 60);
return sprintf("%s%02d%s%02d", $sign, $mins / 60, $colon, $mins % 60);
}
/**
* Summary of set_locale - not used an nothing defined for get_locale
* @param mixed $user
* @return bool|string
* public function set_locale($user = false) {
* static $locale = false;
*
* if (!$locale) {
* # breaks the RFC 2822 code
* $locale = @setlocale(LC_TIME, get_locale($user));
* #print "set_locale(): locale=$locale\n
";
* }
*
* return $locale;
* }
*/
/**
* Returns the number of days in a month allowing for leap year
* @param integer $month
* @param integer $year
* @return integer (or fails if not between 0 and 12)
*/
public function daysInMonth( $month, $year ) {
switch( $month ) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
case 0: // == 12
return 31;
case 4:
case 6:
case 9:
case 11:
return 30;
case 2:
return $this->is_leap_year( $year ) ? 29 : 28;
default:
assert( false );
}
return 0;
}
/**
* Get a hash of holidays for a given year
* @param int $pYear the year in question
* @param string $pCountryCode -- the country in question - only US is supported currently
* @return array an associative array containing the holidays occuring in the given year they key is a date stamp of the form Y-m-d, the value is the name of the corresponding holiday
**/
public static function getHolidays( $pYear=null, $pCountryCode='US' ) {
$return = [];
if( empty( $pYear ) ) {
$pYear = date( 'Y' );
}
switch( $pCountryCode ) {
case 'UK':
$return[date( 'Y-m-d', strtotime("-1 week monday", strtotime("1 september $pYear")) + 43200)] = 'Bank Holiday';
break;
case 'CA':
$return[$pYear . '-12-26'] = 'Boxing Day';
$return[$pYear . '-07-01'] = 'Canada Day';
// Labor Day - first Monday in September
$return[date( 'Y-m-d', strtotime( 'monday', strtotime( "September 1, $pYear" ) ) + 43200 )] = 'Labor Day';
break;
case 'US':
//$return[$pYear . '-02-14'] = 'Valentine`s Day';
$return[$pYear . '-06-14'] = 'Flag Day';
$return[$pYear . '-07-04'] = 'Independence Day';
$return[$pYear . '-11-11'] = 'Veteran`s Day';
// Martin Luther King, Jr. Day - third Monday in January
$return[date( 'Y-m-d', strtotime( '2 weeks monday', strtotime( "January 1, $pYear" ) ) + 43200 )] = 'Martin Luther King, Jr. Day';
// Presidents` Day - third Monday in February
$return[date( 'Y-m-d', strtotime( '2 weeks monday', strtotime( "February 1, $pYear" ) ) + 43200 )] = 'Presidents` Day';
// Mardi Gras - Tuesday ~47 days before Easter
//$return[date( 'Y-m-d', strtotime( 'last tuesday 46 days ago', easter_date( $pYear ) ) + 43200 )] = 'Mardi Gras';
// Memorial Day - last Monday in May
$return[date( 'Y-m-d', strtotime( '-1 week monday', strtotime( "June 1, $pYear" ) ) + 43200 )] = 'Memorial Day';
// Labor Day - first Monday in September
$return[date( 'Y-m-d', strtotime( 'monday', strtotime( "September 1, $pYear" ) ) + 43200 )] = 'Labor Day';
// Columbus Day - second Monday in October
$return[date( 'Y-m-d', strtotime( '1 week monday', strtotime( "October 1, $pYear" ) ) + 43200 )] = 'Columbus Day';
// Thanksgiving - fourth Thursday in November
$return[date( 'Y-m-d', strtotime( '3 weeks thursday', strtotime( "November 1, $pYear" ) ) + 43200 )] = 'Thanksgiving';
ksort( $return );
break;
}
// Common to all
// First off, the simple ones
$return[$pYear . '-01-01'] = 'New Year`s Day';
$return[$pYear . '-12-25'] = 'Christmas';
// Easter - the Sunday after the first full moon which falls on or after the Spring Equinox
// Thank God (ha!) PHP has a function for that...
$return [date( 'Y-m-d', easter_date( $pYear ) - 3 * 86400 + 43200 )] = 'Good Friday';
$return [date( 'Y-m-d', easter_date( $pYear ) + 43200 )] = 'Easter';
return $return;
}
function calculateTimeZoneDate( $dateTime, $fromTZ, $toTZ, $fromLocation = 'North America', $toLocation = 'GMT' ) {
$retval = $dateTime;
$timeStamp = strtotime( $dateTime );
$timeZonesArray = [
'GMT' => [
'GMT' => +0, // GMT
],
'North America' => [
'NST' => -3.5, // Newfoundland Standard Time
'NDT' => -2.5, // Newfoundland Daylight Time
'AST' => -4, // Atlantic Standard Time
'ADT' => -3, // Atlantic Daylight Time
'EST' => -5, // Eastern Standard Time
'EDT' => -4, // Eastern Daylight Time
'CST' => -6, // Central Standard Time
'CDT' => -5, // Central Daylight Time
'MST' => -7, // Central Daylight Time
'MDT' => -6, // Mountain Daylight Time
'PST' => -8, // Pacific Standard Time
'PDT' => -7, // Pacific Daylight Time
'AKST' => -9, // Alaska Standard Time
'AKDT' => -8, // Alaska Daylight Time
'HAST' => -10, // Hawaii-Aleutian Standard Time
'HADT' => -9, // Hawaii-Aleutian Daylight Time
],
'Australia' => [
'NFT' => +11.5, // Norfolk (Island) Time
'EST' => +10, // Eastern Standard Time
'EDT' => +11, // Eastern Daylight Time
'CST' => +9.5, // Central Standard Time
'CDT' => +10.5, // Central Daylight Time
'WST' => +8, // Western Standard Time
'CXT' => +7, // Christmas Island Time
],
'Europe' => [
'GMT' => +0, // Greenwich Mean Time
'BST' => +1, // British Summer Time
'IST' => +1, // Irish Summer Time
'WET' => +0, // Western European Time
'WEST' => +1, // Western European Summer Time
'CET' => +1, // Central European Time
'CEST' => +2, // Central European Summer Time
'EET' => +2, // Eastern European Time
'EEST' => +3, // Eastern European Summer Time
],
'Military' => [
'Z' => +0, // Zulu Time Zone
'Y' => -12, // Yankee Time Zone
'X' => -11, // X-ray Time Zone
'W' => -10, // Whiskey Time Zone
'V' => -9, // Victor Time Zone
'U' => -8, // Uniform Time Zone
'T' => -7, // Tango Time Zone
'S' => -6, // Sierra Time Zone
'R' => -5, // Romeo Time Zone
'Q' => -4, // Quebec Time Zone
'P' => -3, // Papa Time Zone
'O' => -2, // Oscar Time Zone
'N' => -1, // November Time Zone
'A' => +1, // Alpha Time Zone
'B' => +2, // Bravo Time Zone
'C' => +3, // Charlie Time Zone
'D' => +4, // Delta Time Zone
'E' => +5, // Echo Time Zone
'F' => +6, // Foxtrot Time Zone
'G' => +7, // Golf Time Zone
'H' => +8, // Hotel Time Zone
'I' => +9, // India Time Zone
'K' => +10, // Kilo Time Zone
'L' => +11, // Lima Time Zone
'M' => +12, // Mike Time Zone
],
];
$fromGMTDiff = $timeZonesArray[$fromLocation][$fromTZ];
$toGMTDiff = $timeZonesArray[$toLocation][$toTZ];
if(( '' != trim( $fromGMTDiff )) && ( '' != trim( $toGMTDiff ))) {
$netDiff = $fromGMTDiff > $toGMTDiff ? $fromGMTDiff - $toGMTDiff : $toGMTDiff - $fromGMTDiff;
$retval = date( 'Y-m-d h:i:sa', $timeStamp + 3600 * $netDiff );
}
return $retval;
} // end function calculateTimeZoneDate()
}