mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-22 06:30:59 +01:00
move egw_time class to Api\DateTime
This commit is contained in:
parent
49f75bc8dd
commit
a24c1121a2
726
api/src/DateTime.php
Normal file
726
api/src/DateTime.php
Normal file
@ -0,0 +1,726 @@
|
||||
<?php
|
||||
/**
|
||||
* EGroupware time and timezone handling
|
||||
*
|
||||
* @package api
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <RalfBecker@outdoor-training.de>
|
||||
* @copyright 2009-16 by RalfBecker@outdoor-training.de
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
namespace EGroupware\Api;
|
||||
|
||||
// we do not have an own implementation/extensions
|
||||
use DateTimeZone;
|
||||
|
||||
/**
|
||||
* EGroupware time and timezone handling class extending PHP's DateTime
|
||||
*
|
||||
* Api\DateTime class knows 2 timezones:
|
||||
* 1. Api\DateTime::$user_timezone timezone of the user, defined in his prefs $GLOBALS['egw_info']['user']['preferences']['common']['tz']
|
||||
* 2. Api\DateTime::$server_timezone timezone of the server, read via date_default_timezone_get()
|
||||
*
|
||||
* The class extends PHP5.2's DateTime object to:
|
||||
* - format date and time according to format in user prefs ($type===true: date, $type===false: time, $type==='' date+time)
|
||||
* - defaulting to a user timezone according to user prefs (not server timezone as DateTime!)
|
||||
* - deal with integer unix timestamps and DB timestamps in server-time ($type: 'ts'='integer' or 'server' timestamp in servertime)
|
||||
*
|
||||
* There are two static methods for simple conversation between server and user time:
|
||||
* - Api\DateTime::server2user($time,$type=null)
|
||||
* - Api\DateTime::user2server($time,$type=null)
|
||||
* (Replacing in 1.6 and previous used adding of tz_offset, which is only correct for current time)
|
||||
*
|
||||
* An other static method allows to format any time in several ways: Api\DateTime::to($time,$type) (exceed date($type,$time)).
|
||||
*
|
||||
* The constructor of Api\DateTime understand - in addition to DateTime - integer timestamps, array with values for
|
||||
* keys: ('year', 'month', 'day') or 'full' plus 'hour', 'minute' and optional 'second' or a DateTime object as parameter.
|
||||
* It defaults to user-time, not server time as DateTime!
|
||||
*
|
||||
* The constructor itself throws an Exception in that case (to be precise it does not handle the one thrown by DateTime constructor).
|
||||
* Static methods server2user, user2server and to return NULL, if given time could not be parsed.
|
||||
*
|
||||
* @link http://www.php.net/manual/en/class.datetime.php
|
||||
* @link http://www.php.net/manual/en/class.datetimezone.php
|
||||
*/
|
||||
class DateTime extends \DateTime
|
||||
{
|
||||
/**
|
||||
* Database timestamp format: Y-m-d H:i:s
|
||||
*/
|
||||
const DATABASE = 'Y-m-d H:i:s';
|
||||
|
||||
/**
|
||||
* etemplate2 format for ignoring timezones in the browser
|
||||
*/
|
||||
const ET2 = 'Y-m-d\TH:i:s\Z';
|
||||
/**
|
||||
* DateTimeZone of server, read from $GLOBALS['egw_info']['server']['server_timezone'], set by self::init()
|
||||
*
|
||||
* @var DateTimeZone
|
||||
*/
|
||||
static public $server_timezone;
|
||||
|
||||
/**
|
||||
* DateTimeZone of user, read from user prefs, set by self::init() or self::setUserPrefs()
|
||||
*
|
||||
* @var DateTimeZone
|
||||
*/
|
||||
static public $user_timezone;
|
||||
|
||||
/**
|
||||
* Time format from user prefs, set by self::setUserPrefs()
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
static public $user_timeformat = 'H:i';
|
||||
|
||||
/**
|
||||
* Date format from user prefs, set by self::setUserPrefs()
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
static public $user_dateformat = 'Y-m-d';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param int|string|array|DateTime $time ='now' integer timestamp, string with date+time, DateTime object or
|
||||
* array with values for keys('year','month','day') or 'full' plus 'hour','minute' and optional 'second'
|
||||
* @param DateTimeZone $tz =null timezone, default user time (PHP DateTime default to server time!)
|
||||
* @param string &$type=null on return type of $time (optional)
|
||||
* @throws Exception if $time can NOT be parsed
|
||||
*/
|
||||
public function __construct($time='now',DateTimeZone $tz=null,&$type=null)
|
||||
{
|
||||
if (is_null($tz)) $tz = self::$user_timezone; // default user timezone
|
||||
|
||||
switch(($type = gettype($time)))
|
||||
{
|
||||
case 'NULL':
|
||||
case 'boolean': // depricated use in calendar for 'now'
|
||||
$time = 'now';
|
||||
$type = 'string';
|
||||
// fall through
|
||||
case 'string':
|
||||
if (!(is_numeric($time) && ($time > 21000000 || $time < 19000000)))
|
||||
{
|
||||
$t_str = $time;
|
||||
if (is_numeric($time) && strlen($time) == 8) $t_str .= 'T000000'; // 'Ymd' string used in calendar to represent a date
|
||||
// $time ending in a Z (Zulu or UTC time), is unterstood by DateTime class itself
|
||||
try {
|
||||
parent::__construct($t_str,$tz);
|
||||
break;
|
||||
}
|
||||
catch(Exception $e) {
|
||||
// if string is nummeric, ignore the exception and treat string as timestamp
|
||||
if (!is_numeric($time)) throw $e;
|
||||
}
|
||||
}
|
||||
$type = 'integer';
|
||||
// fall through for timestamps
|
||||
case 'double': // 64bit integer (timestamps > 2038) are treated on 32bit systems as double
|
||||
case 'integer':
|
||||
/* ToDo: Check if PHP5.3 setTimestamp does the same, or always expects UTC timestamp
|
||||
if (PHP_VERSION >= 5.3)
|
||||
{
|
||||
parent::__construct('now',$tz);
|
||||
$datetime->setTimestamp($time);
|
||||
}
|
||||
else*/
|
||||
{
|
||||
parent::__construct(date('Y-m-d H:i:s',$time),$tz);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'array':
|
||||
parent::__construct('now',$tz);
|
||||
if (isset($time['Y'])) // array format used in eTemplate
|
||||
{
|
||||
$time = array(
|
||||
'year' => $time['Y'],
|
||||
'month' => $time['m'],
|
||||
'day' => $time['d'],
|
||||
'hour' => $time['H'],
|
||||
'minute' => $time['i'],
|
||||
'second' => $time['s'],
|
||||
);
|
||||
}
|
||||
if (!empty($time['full']) && empty($time['year']))
|
||||
{
|
||||
$time['year'] = (int)substr($time['full'],0,4);
|
||||
$time['month'] = (int)substr($time['full'],4,2);
|
||||
$time['day'] = (int)substr($time['full'],6,2);
|
||||
}
|
||||
if (isset($time['year'])) $this->setDate((int)$time['year'],(int)$time['month'],isset($time['day']) ? (int)$time['day'] : (int)$time['mday']);
|
||||
$this->setTime((int)$time['hour'],(int)$time['minute'],(int)$time['second']);
|
||||
break;
|
||||
|
||||
case 'object':
|
||||
if ($time instanceof \DateTime)
|
||||
{
|
||||
parent::__construct($time->format('Y-m-d H:i:s'),$time->getTimezone());
|
||||
$this->setTimezone($tz);
|
||||
break;
|
||||
}
|
||||
// fall through
|
||||
default:
|
||||
throw new egw_exception_assertion_failed("Not implemented for type ($type)$time!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Like DateTime::add, but additional allow to use a string run through DateInterval::createFromDateString
|
||||
*
|
||||
* @param DateInterval|string $interval eg. '1 day', '-2 weeks'
|
||||
*/
|
||||
public function add($interval)
|
||||
{
|
||||
if (is_string($interval)) $interval = DateInterval::createFromDateString($interval);
|
||||
|
||||
parent::add($interval);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set date to beginning of the week taking into account calendar weekdaystarts preference
|
||||
*/
|
||||
public function setWeekstart()
|
||||
{
|
||||
$wday = (int) $this->format('w'); // 0=sun, ..., 6=sat
|
||||
switch($GLOBALS['egw_info']['user']['preferences']['calendar']['weekdaystarts'])
|
||||
{
|
||||
case 'Sunday':
|
||||
$wstart = -$wday;
|
||||
break;
|
||||
case 'Saturday':
|
||||
$wstart = -(6-$wday);
|
||||
break;
|
||||
case 'Moday':
|
||||
default:
|
||||
$wstart = -($wday ? $wday-1 : 6);
|
||||
break;
|
||||
}
|
||||
if ($wstart) $this->add($wstart.'days');
|
||||
}
|
||||
|
||||
/**
|
||||
* return SQL implementing filtering by date
|
||||
*
|
||||
* @param string $name
|
||||
* @param int &$start
|
||||
* @param int &$end
|
||||
* @param string $column name of timestamp column to use in returned sql
|
||||
* @param array $filters $name => list($syear,$smonth,$sday,$sweek,$eyear,$emonth,$eday,$eweek) pairs with offsets
|
||||
* @return string
|
||||
*/
|
||||
public static function sql_filter($name, &$start, &$end, $column, array $filters=array())
|
||||
{
|
||||
if ($name == 'custom' && $start)
|
||||
{
|
||||
$start = new DateTime($start);
|
||||
$start->setTime(0, 0, 0);
|
||||
|
||||
if ($end)
|
||||
{
|
||||
$end = new DateTime($end);
|
||||
$end->setTime(0, 0, 0);
|
||||
$end->add('+1day');
|
||||
}
|
||||
else
|
||||
{
|
||||
$end = new DateTime($start);
|
||||
$end->add('+1week');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!isset($filters[$name]))
|
||||
{
|
||||
return '1=1';
|
||||
}
|
||||
$start = new DateTime('now');
|
||||
$start->setTime(0, 0, 0);
|
||||
$end = new DateTime('now');
|
||||
$end->setTime(0, 0, 0);
|
||||
|
||||
$year = (int) $start->format('Y');
|
||||
$month = (int) $start->format('m');
|
||||
|
||||
list($syear,$smonth,$sday,$sweek,$eyear,$emonth,$eday,$eweek) = $filters[$name];
|
||||
|
||||
// Handle quarters
|
||||
if(stripos($name, 'quarter') !== false)
|
||||
{
|
||||
$start->setDate($year, ((int)floor(($smonth+$month) / 3.1)) * 3 + 1, 1);
|
||||
$end->setDate($year, ((int)floor(($emonth+$month) / 3.1)+1) * 3 + 1, 1);
|
||||
}
|
||||
elseif ($syear || $eyear)
|
||||
{
|
||||
$start->setDate($year+$syear, 1, 1);
|
||||
$end->setDate($year+$eyear, 1, 1);
|
||||
}
|
||||
elseif ($smonth || $emonth)
|
||||
{
|
||||
$start->setDate($year, $month+$smonth, 1);
|
||||
$end->setDate($year, $month+$emonth, 1);
|
||||
}
|
||||
elseif ($sday || $eday)
|
||||
{
|
||||
if ($sday) $start->add($sday.'days');
|
||||
if ($eday) $end->add($eday.'days');
|
||||
}
|
||||
elseif ($sweek || $eweek)
|
||||
{
|
||||
$start->setWeekstart();
|
||||
if ($sweek) $start->add($sweek.'weeks');
|
||||
$end->setWeekstart();
|
||||
if ($eweek) $end->add($eweek.'weeks');
|
||||
}
|
||||
}
|
||||
// convert start + end from user to servertime for the filter
|
||||
$sql = '('.DateTime::user2server($start, 'ts').' <= '.$column.' AND '.$column.' < '.DateTime::user2server($end, 'ts').')';
|
||||
//error_log(__METHOD__."('$name', ...) syear=$syear, smonth=$smonth, sday=$sday, sweek=$sweek, eyear=$eyear, emonth=$emonth, eday=$eday, eweek=$eweek --> start=".$start->format().', end='.$end->format().", sql='$sql'");
|
||||
|
||||
// returned timestamps: $end is an inclusive date, eg. for today it's equal to start!
|
||||
$start = $start->format('ts');
|
||||
$end->add('-1day');
|
||||
$end = $end->format('ts');
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set user timezone, according to user prefs: converts current time to user time
|
||||
*
|
||||
* Does nothing if self::$user_timezone is current timezone!
|
||||
*/
|
||||
public function setUser()
|
||||
{
|
||||
$this->setTimezone(self::$user_timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set server timezone: converts current time to server time
|
||||
*
|
||||
* Does nothing if self::$server_timezone is current timezone!
|
||||
*/
|
||||
public function setServer()
|
||||
{
|
||||
$this->setTimezone(self::$server_timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format DateTime object as a specific type or string
|
||||
*
|
||||
* @param string $type ='' 'integer'|'ts'=timestamp, 'server'=timestamp in servertime, 'string'='Y-m-d H:i:s', 'object'=DateTime,
|
||||
* 'array'=array with values for keys ('year','month','day','hour','minute','second','full','raw') or string with format
|
||||
* true = date only, false = time only as in user prefs, '' = date+time as in user prefs
|
||||
* @return int|string|array|datetime see $type
|
||||
*/
|
||||
public function format($type='')
|
||||
{
|
||||
switch((string)$type)
|
||||
{
|
||||
case '': // empty string: date and time as in user prefs
|
||||
//case '': // boolean false: time as in user prefs
|
||||
case '1': // boolean true: date as in user prefs
|
||||
if (is_bool($type))
|
||||
{
|
||||
$type = $type ? self::$user_dateformat : self::$user_timeformat;
|
||||
}
|
||||
else
|
||||
{
|
||||
$type = self::$user_dateformat.', '.self::$user_timeformat;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
$type = self::DATABASE;
|
||||
break;
|
||||
|
||||
case 'server': // timestamp in servertime
|
||||
$this->setServer();
|
||||
// fall through
|
||||
case 'integer':
|
||||
case 'ts':
|
||||
// ToDo: Check if PHP5.3 getTimestamp does the same, or always returns UTC timestamp
|
||||
return mktime(parent::format('H'),parent::format('i'),parent::format('s'),parent::format('m'),parent::format('d'),parent::format('Y'));
|
||||
|
||||
case 'object':
|
||||
case 'datetime':
|
||||
case 'egw_time':
|
||||
case 'DateTime':
|
||||
return clone($this);
|
||||
|
||||
case 'array':
|
||||
$arr = array(
|
||||
'year' => (int)parent::format('Y'),
|
||||
'month' => (int)parent::format('m'),
|
||||
'day' => (int)parent::format('d'),
|
||||
'hour' => (int)parent::format('H'),
|
||||
'minute' => (int)parent::format('i'),
|
||||
'second' => (int)parent::format('s'),
|
||||
'full' => parent::format('Ymd'),
|
||||
);
|
||||
$arr['raw'] = mktime($arr['hour'],$arr['minute'],$arr['second'],$arr['month'],$arr['day'],$arr['year']);
|
||||
return $arr;
|
||||
|
||||
case 'date_array': // array with short keys used by date: Y, m, d, H, i, s (used in eTemplate)
|
||||
return array(
|
||||
'Y' => (int)parent::format('Y'),
|
||||
'm' => (int)parent::format('m'),
|
||||
'd' => (int)parent::format('d'),
|
||||
'H' => (int)parent::format('H'),
|
||||
'i' => (int)parent::format('i'),
|
||||
's' => (int)parent::format('s'),
|
||||
);
|
||||
}
|
||||
// default $type contains string with format
|
||||
return parent::format($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast object to string
|
||||
*
|
||||
* @return string eg. "Wednesday, 2009-11-11 11:11:11 (Europe/Berlin)"
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->format('l, '.self::DATABASE).' ('.$this->getTimezone()->getName().')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a server time into a user time
|
||||
*
|
||||
* @param int|string|array|DateTime $time
|
||||
* @param string $type =null type or return-value, default (null) same as $time
|
||||
* @return int|string|array|datetime null if time could not be parsed
|
||||
*/
|
||||
public static function server2user($time,$type=null)
|
||||
{
|
||||
$typeof='DateTime';
|
||||
if (!($time instanceof DateTime))
|
||||
{
|
||||
try
|
||||
{
|
||||
$time = new DateTime($time, self::$server_timezone, $typeof);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
unset($e);
|
||||
return null; // time could not be parsed
|
||||
}
|
||||
}
|
||||
$time->setUser();
|
||||
|
||||
if (is_null($type)) $type = $typeof;
|
||||
|
||||
//echo "<p>".__METHOD__."($time,$type) = ".print_r($format->format($type),true)."</p>\n";
|
||||
return $time->format($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a user time into a server time
|
||||
*
|
||||
* @param int|string|array|datetime $time
|
||||
* @param string $type =null type or return-value, default (null) same as $time
|
||||
* @return int|string|array|datetime null if time could not be parsed
|
||||
*/
|
||||
public static function user2server($time,$type=null)
|
||||
{
|
||||
$typeof='DateTime';
|
||||
if (!($time instanceof DateTime))
|
||||
{
|
||||
try
|
||||
{
|
||||
$time = new DateTime($time,self::$user_timezone,$typeof);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
unset($e);
|
||||
return null; // time could not be parsed
|
||||
}
|
||||
}
|
||||
$time->setServer();
|
||||
|
||||
if (is_null($type)) $type = $typeof;
|
||||
|
||||
//echo "<p>".__METHOD__."($time,$type) = ".print_r($format->format($type),true)."</p>\n";
|
||||
return $time->format($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert time to a specific format or string, static version of DateTime::format()
|
||||
*
|
||||
* @param int|string|array|DateTime $time ='now' see constructor
|
||||
* @param string $type ='' 'integer'|'ts'=timestamp, 'server'=timestamp in servertime, 'string'='Y-m-d H:i:s', 'object'=DateTime,
|
||||
* 'array'=array with values for keys ('year','month','day','hour','minute','second','full','raw') or string with format
|
||||
* true = date only, false = time only as in user prefs, '' = date+time as in user prefs
|
||||
* @return int|string|array|datetime see $type, null if time could not be parsed
|
||||
*/
|
||||
public static function to($time='now',$type='')
|
||||
{
|
||||
if (!($time instanceof DateTime))
|
||||
{
|
||||
try
|
||||
{
|
||||
$time = new DateTime($time);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
unset($e);
|
||||
return null; // time could not be parsed
|
||||
}
|
||||
}
|
||||
return $time->format($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for user timezone, should be called after reading user preferences
|
||||
*
|
||||
* @param string $tz timezone, eg. 'Europe/Berlin' or 'UTC'
|
||||
* @param string $dateformat ='' eg. 'Y-m-d' or 'd.m.Y'
|
||||
* @param string|int $timeformat ='' integer 12, 24, or format string eg. 'H:i'
|
||||
* @throws egw_exception_wrong_userinput if invalid $tz parameter
|
||||
* @return DateTimeZone
|
||||
*/
|
||||
public static function setUserPrefs($tz,$dateformat='',$timeformat='')
|
||||
{
|
||||
//echo "<p>".__METHOD__."('$tz','$dateformat','$timeformat') ".function_backtrace()."</p>\n";
|
||||
if (!empty($dateformat)) self::$user_dateformat = $dateformat;
|
||||
|
||||
switch($timeformat)
|
||||
{
|
||||
case '':
|
||||
break;
|
||||
case '24':
|
||||
self::$user_timeformat = 'H:i';
|
||||
break;
|
||||
case '12':
|
||||
self::$user_timeformat = 'h:i a';
|
||||
break;
|
||||
default:
|
||||
self::$user_timeformat = $timeformat;
|
||||
break;
|
||||
}
|
||||
try {
|
||||
self::$user_timezone = new DateTimeZone($tz);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
unset($e);
|
||||
// silently use server timezone, as we have no means to report the wrong timezone to the user from this class
|
||||
self::$user_timezone = clone(self::$server_timezone);
|
||||
}
|
||||
return self::$user_timezone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get offset in seconds between user and server time at given time $time
|
||||
*
|
||||
* Compatibility method for old code. It is only valid for the given time, because of possible daylight saving changes!
|
||||
*
|
||||
* @param int|string|DateTime $time ='now'
|
||||
* @return int difference in seconds between user and server time (for the given time!)
|
||||
*/
|
||||
public static function tz_offset_s($time='now')
|
||||
{
|
||||
if (!($time instanceof DateTime)) $time = new DateTime($time);
|
||||
|
||||
return self::$user_timezone->getOffset($time) - self::$server_timezone->getOffset($time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Init static variables, reading user prefs
|
||||
*/
|
||||
public static function init()
|
||||
{
|
||||
// if no server timezone set, use date_default_timezone_get() to determine it
|
||||
if (empty($GLOBALS['egw_info']['server']['server_timezone']))
|
||||
{
|
||||
$GLOBALS['egw_info']['server']['server_timezone'] = date_default_timezone_get();
|
||||
}
|
||||
// make sure we have a valid server timezone set
|
||||
try {
|
||||
self::$server_timezone = new DateTimeZone($GLOBALS['egw_info']['server']['server_timezone']);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
try {
|
||||
self::$server_timezone = new DateTimeZone(date_default_timezone_get());
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
self::$server_timezone = new DateTimeZone('Europe/Berlin');
|
||||
}
|
||||
error_log(__METHOD__."() invalid server_timezone='{$GLOBALS['egw_info']['server']['server_timezone']}' setting now '".self::$server_timezone->getName()."'!");
|
||||
config::save_value('server_timezone',$GLOBALS['egw_info']['server']['server_timezone'] = self::$server_timezone->getName(),'phpgwapi');
|
||||
}
|
||||
if (!isset($GLOBALS['egw_info']['user']['preferences']['common']['tz']))
|
||||
{
|
||||
$GLOBALS['egw_info']['user']['preferences']['common']['tz'] = $GLOBALS['egw_info']['server']['server_timezone'];
|
||||
}
|
||||
self::setUserPrefs($GLOBALS['egw_info']['user']['preferences']['common']['tz'],
|
||||
$GLOBALS['egw_info']['user']['preferences']['common']['dateformat'],
|
||||
$GLOBALS['egw_info']['user']['preferences']['common']['timeformat']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return "beautified" timezone list:
|
||||
* - no depricated timezones
|
||||
* - return UTC and oceans at the end
|
||||
* - if (user lang is a european language), move Europe to top
|
||||
*
|
||||
* @return array continent|ocean => array(tz-name => tz-label incl. current time)
|
||||
*/
|
||||
public static function getTimezones()
|
||||
{
|
||||
// prepare list of timezones from php, ignoring depricated ones and sort as follows
|
||||
$tzs = array(
|
||||
'Africa' => array(), // Contients
|
||||
'America' => array(),
|
||||
'Asia' => array(),
|
||||
'Australia' => array(),
|
||||
'Europe' => array(),
|
||||
'Atlantic' => array(), // Oceans
|
||||
'Pacific' => array(),
|
||||
'Indian' => array(),
|
||||
'Antarctica' => array(), // Poles
|
||||
'Arctic' => array(),
|
||||
'UTC' => array('UTC' => 'UTC'),
|
||||
);
|
||||
// no VTIMEZONE available in calendar_timezones --> do NOT return them
|
||||
static $no_vtimezone = array(
|
||||
'Europe/Tiraspol',
|
||||
'America/Atka',
|
||||
'America/Buenos_Aires',
|
||||
'America/Catamarca',
|
||||
'America/Coral_Harbour',
|
||||
'America/Cordoba',
|
||||
'America/Ensenada',
|
||||
'America/Fort_Wayne',
|
||||
'America/Indianapolis',
|
||||
'America/Jujuy',
|
||||
'America/Knox_IN',
|
||||
'America/Mendoza',
|
||||
'America/Porto_Acre',
|
||||
'America/Rosario',
|
||||
'America/Virgin',
|
||||
'Asia/Ashkhabad',
|
||||
'Asia/Beijing',
|
||||
'Asia/Chungking',
|
||||
'Asia/Dacca',
|
||||
'Asia/Macao',
|
||||
'Asia/Riyadh87',
|
||||
'Asia/Riyadh88',
|
||||
'Asia/Riyadh89',
|
||||
'Asia/Tel_Aviv',
|
||||
'Asia/Thimbu',
|
||||
'Asia/Ujung_Pandang',
|
||||
'Asia/Ulan_Bator',
|
||||
'Australia/ACT',
|
||||
'Australia/Canberra',
|
||||
'Australia/LHI',
|
||||
'Australia/North',
|
||||
'Australia/NSW',
|
||||
'Australia/Queensland',
|
||||
'Australia/South',
|
||||
'Australia/Tasmania',
|
||||
'Australia/Victoria',
|
||||
'Australia/West',
|
||||
'Australia/Yancowinna',
|
||||
'Pacific/Samoa',
|
||||
);
|
||||
foreach(DateTimeZone::listIdentifiers() as $name)
|
||||
{
|
||||
if (in_array($name,$no_vtimezone)) continue; // do NOT allow to set in EGroupware, as we have not VTIMEZONE component for it
|
||||
list($continent) = explode('/',$name,2);
|
||||
if (!isset($tzs[$continent])) continue; // old depricated timezones
|
||||
$datetime = new DateTime('now',new DateTimeZone($name));
|
||||
$tzs[$continent][$name] = str_replace(array('_','/'),array(' ',' / '),$name)." ".$datetime->format();
|
||||
unset($datetime);
|
||||
}
|
||||
foreach($tzs as $continent => &$data)
|
||||
{
|
||||
natcasesort($data); // sort cities
|
||||
}
|
||||
unset($data);
|
||||
|
||||
// if user lang or installed langs contain a european language --> move Europe to top of tz list
|
||||
$langs = class_exists('translation') ? translation::get_installed_langs() : array();
|
||||
if (array_intersect(array($GLOBALS['egw_info']['user']['preferences']['common']['lang'])+array_keys($langs),
|
||||
array('de','fr','it','nl','bg','ca','cs','da','el','es-es','et','eu','fi','hr','hu','lt','no','pl','pt','sk','sl','sv','tr','uk')))
|
||||
{
|
||||
$tzs = array_merge(array('Europe' => $tzs['Europe']),$tzs);
|
||||
}
|
||||
return $tzs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user timezones (the ones user selected in his prefs), plus evtl. an extra one
|
||||
*
|
||||
* @param string $extra extra timezone to add, if not already included in user timezones
|
||||
* @return array tzid => label
|
||||
*/
|
||||
public static function getUserTimezones($extra=null)
|
||||
{
|
||||
$tz = $GLOBALS['egw_info']['user']['preferences']['common']['tz'];
|
||||
$user_tzs = explode(',',$GLOBALS['egw_info']['user']['preferences']['common']['tz_selection']);
|
||||
if (count($user_tzs) <= 1)
|
||||
{
|
||||
$user_tzs = $tz ? array($tz) : array();
|
||||
}
|
||||
if ($tz && !in_array($tz,$user_tzs))
|
||||
{
|
||||
$user_tzs = array_merge(array($tz),$user_tzs);
|
||||
}
|
||||
if (!$user_tzs) // if we have no user timezones, eg. user set no pref --> use server default
|
||||
{
|
||||
$user_tzs = array($GLOBALS['egw_info']['server']['server_timezone']);
|
||||
}
|
||||
if ($extra && !in_array($extra,$user_tzs))
|
||||
{
|
||||
$user_tzs = array_merge(array($extra),$user_tzs);
|
||||
}
|
||||
$ret_user_tzs = array_combine($user_tzs,$user_tzs);
|
||||
foreach($ret_user_tzs as &$label)
|
||||
{
|
||||
$label = str_replace(array('_','/'),array(' ',' / '),$label);
|
||||
}
|
||||
return $ret_user_tzs;
|
||||
}
|
||||
}
|
||||
DateTime::init();
|
||||
|
||||
/*
|
||||
if (isset($_SERVER['SCRIPT_FILENAME']) && $_SERVER['SCRIPT_FILENAME'] == __FILE__) // some tests
|
||||
{
|
||||
// test timestamps/dates before 1970
|
||||
foreach(array('19690811',-3600,'-119322000') as $ts)
|
||||
{
|
||||
try {
|
||||
echo "<p>DateTime::to($ts,'Y-m-d H:i:s')=".DateTime::to($ts,'Y-m-d H:i:s')."</p>\n";
|
||||
$et = new DateTime($ts);
|
||||
echo "<p>DateTime($ts)->format('Y-m-d H:i:s')=".$et->format('Y-m-d H:i:s')."</p>\n";
|
||||
$dt = new DateTime($ts);
|
||||
echo "<p>DateTime($ts)->format('Y-m-d H:i:s')=".$dt->format('Y-m-d H:i:s')."</p>\n";
|
||||
} catch(Exception $e) {
|
||||
echo "<p><b>Exception</b>: ".$e->getMessage()."</p>\n";
|
||||
}
|
||||
}
|
||||
// user time is UTC
|
||||
echo "<p>user timezone = ".($GLOBALS['egw_info']['user']['preferences']['common']['tz'] = 'UTC').", server timezone = ".date_default_timezone_get()."</p>\n";
|
||||
|
||||
$time = time();
|
||||
echo "<p>time=$time=".date('Y-m-d H:i:s',$time)."(server) =".DateTime::server2user($time,'Y-m-d H:i:s')."(user) =".DateTime::server2user($time,'ts')."(user)=".date('Y-m-d H:i:s',DateTime::server2user($time,'ts'))."</p>\n";
|
||||
|
||||
echo "DateTime::to(array('full' => '20091020', 'hour' => 12, 'minute' => 0))='".DateTime::to(array('full' => '20091020', 'hour' => 12, 'minute' => 0))."'</p>\n";
|
||||
|
||||
$ts = DateTime::to(array('full' => '20091027', 'hour' => 10, 'minute' => 0),'ts');
|
||||
echo "<p>2009-10-27 10h UTC timestamp=$ts --> server time = ".DateTime::user2server($ts,'')." --> user time = ".DateTime::server2user(DateTime::user2server($ts),'')."</p>\n";
|
||||
|
||||
$ts = DateTime::to(array('full' => '20090627', 'hour' => 10, 'minute' => 0),'ts');
|
||||
echo "<p>2009-06-27 10h UTC timestamp=$ts --> server time = ".DateTime::user2server($ts,'')." --> user time = ".DateTime::server2user(DateTime::user2server($ts),'')."</p>\n";
|
||||
}
|
||||
*/
|
@ -1350,9 +1350,9 @@ class Db
|
||||
{
|
||||
case 'int':
|
||||
// if DateTime object given, convert it to a unix timestamp (NOT converting the timezone!)
|
||||
if (is_object($value) && ($value instanceof DateTime))
|
||||
if (is_object($value) && ($value instanceof \DateTime))
|
||||
{
|
||||
return ($value instanceof egw_time) ? $value->format('ts') : egw_time::to($value,'ts');
|
||||
return ($value instanceof DateTime) ? $value->format('ts') : DateTime::to($value,'ts');
|
||||
}
|
||||
case 'auto':
|
||||
// atm. (php5.2) php has only 32bit integers, it converts everything else to float.
|
||||
@ -1386,14 +1386,14 @@ class Db
|
||||
break; // handled like strings
|
||||
case 'date':
|
||||
// if DateTime object given, convert it (NOT converting the timezone!)
|
||||
if (is_object($value) && ($value instanceof DateTime))
|
||||
if (is_object($value) && ($value instanceof \DateTime))
|
||||
{
|
||||
return $this->Link_ID->qstr($value->format('Y-m-d'));
|
||||
}
|
||||
return $this->Link_ID->DBDate($value);
|
||||
case 'timestamp':
|
||||
// if DateTime object given, convert it (NOT converting the timezone!)
|
||||
if (is_object($value) && ($value instanceof DateTime))
|
||||
if (is_object($value) && ($value instanceof \DateTime))
|
||||
{
|
||||
return $this->Link_ID->qstr($value->format('Y-m-d H:i:s'));
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ use mime_magic;
|
||||
use common;
|
||||
use html;
|
||||
use HTTP_WebDAV_Server;
|
||||
use egw_time;
|
||||
|
||||
/**
|
||||
* Class containing static methods to use the new eGW virtual file system
|
||||
@ -1561,7 +1560,7 @@ class Vfs extends Vfs\StreamWrapper
|
||||
}
|
||||
|
||||
// Set a comment to help tell them apart
|
||||
$zip->setArchiveComment(lang('Created by %1', $GLOBALS['egw_info']['user']['account_lid']) . ' ' .egw_time::to());
|
||||
$zip->setArchiveComment(lang('Created by %1', $GLOBALS['egw_info']['user']['account_lid']) . ' ' .DateTime::to());
|
||||
|
||||
// Record total for debug, not available after close()
|
||||
$total_files = $zip->numFiles;
|
||||
|
@ -5,714 +5,16 @@
|
||||
* @package api
|
||||
* @link http://www.egroupware.org
|
||||
* @author Ralf Becker <RalfBecker@outdoor-training.de>
|
||||
* @copyright 2009 by RalfBecker@outdoor-training.de
|
||||
* @copyright 2009-16 by RalfBecker@outdoor-training.de
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
use EGroupware\Api;
|
||||
|
||||
/**
|
||||
* EGroupware time and timezone handling class extending PHP's DateTime
|
||||
*
|
||||
* egw_time class knows 2 timezones:
|
||||
* 1. egw_time::$user_timezone timezone of the user, defined in his prefs $GLOBALS['egw_info']['user']['preferences']['common']['tz']
|
||||
* 2. egw_time::$server_timezone timezone of the server, read via date_default_timezone_get()
|
||||
*
|
||||
* The class extends PHP5.2's DateTime object to:
|
||||
* - format date and time according to format in user prefs ($type===true: date, $type===false: time, $type==='' date+time)
|
||||
* - defaulting to a user timezone according to user prefs (not server timezone as DateTime!)
|
||||
* - deal with integer unix timestamps and DB timestamps in server-time ($type: 'ts'='integer' or 'server' timestamp in servertime)
|
||||
*
|
||||
* There are two static methods for simple conversation between server and user time:
|
||||
* - egw_time::server2user($time,$type=null)
|
||||
* - egw_time::user2server($time,$type=null)
|
||||
* (Replacing in 1.6 and previous used adding of tz_offset, which is only correct for current time)
|
||||
*
|
||||
* An other static method allows to format any time in several ways: egw_time::to($time,$type) (exceed date($type,$time)).
|
||||
*
|
||||
* The constructor of egw_time understand - in addition to DateTime - integer timestamps, array with values for
|
||||
* keys: ('year', 'month', 'day') or 'full' plus 'hour', 'minute' and optional 'second' or a DateTime object as parameter.
|
||||
* It defaults to user-time, not server time as DateTime!
|
||||
*
|
||||
* The constructor itself throws an Exception in that case (to be precise it does not handle the one thrown by DateTime constructor).
|
||||
* Static methods server2user, user2server and to return NULL, if given time could not be parsed.
|
||||
*
|
||||
* @link http://www.php.net/manual/en/class.datetime.php
|
||||
* @link http://www.php.net/manual/en/class.datetimezone.php
|
||||
* @deprecated use Api\DateTime
|
||||
*/
|
||||
class egw_time extends DateTime
|
||||
{
|
||||
/**
|
||||
* Database timestamp format: Y-m-d H:i:s
|
||||
*/
|
||||
const DATABASE = 'Y-m-d H:i:s';
|
||||
|
||||
/**
|
||||
* etemplate2 format for ignoring timezones in the browser
|
||||
*/
|
||||
const ET2 = 'Y-m-d\TH:i:s\Z';
|
||||
/**
|
||||
* DateTimeZone of server, read from $GLOBALS['egw_info']['server']['server_timezone'], set by self::init()
|
||||
*
|
||||
* @var DateTimeZone
|
||||
*/
|
||||
static public $server_timezone;
|
||||
|
||||
/**
|
||||
* DateTimeZone of user, read from user prefs, set by self::init() or self::setUserPrefs()
|
||||
*
|
||||
* @var DateTimeZone
|
||||
*/
|
||||
static public $user_timezone;
|
||||
|
||||
/**
|
||||
* Time format from user prefs, set by self::setUserPrefs()
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
static public $user_timeformat = 'H:i';
|
||||
|
||||
/**
|
||||
* Date format from user prefs, set by self::setUserPrefs()
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
static public $user_dateformat = 'Y-m-d';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param int|string|array|DateTime $time='now' integer timestamp, string with date+time, DateTime object or
|
||||
* array with values for keys('year','month','day') or 'full' plus 'hour','minute' and optional 'second'
|
||||
* @param DateTimeZone $tz=null timezone, default user time (PHP DateTime default to server time!)
|
||||
* @param string &$type=null on return type of $time (optional)
|
||||
* @throws Exception if $time can NOT be parsed
|
||||
* @return egw_time
|
||||
*/
|
||||
public function __construct($time='now',DateTimeZone $tz=null,&$type=null)
|
||||
{
|
||||
if (is_null($tz)) $tz = self::$user_timezone; // default user timezone
|
||||
|
||||
switch(($type = gettype($time)))
|
||||
{
|
||||
case 'NULL':
|
||||
case 'boolean': // depricated use in calendar for 'now'
|
||||
$time = 'now';
|
||||
$type = 'string';
|
||||
// fall through
|
||||
case 'string':
|
||||
if (!(is_numeric($time) && ($time > 21000000 || $time < 19000000)))
|
||||
{
|
||||
$t_str = $time;
|
||||
if (is_numeric($time) && strlen($time) == 8) $t_str .= 'T000000'; // 'Ymd' string used in calendar to represent a date
|
||||
// $time ending in a Z (Zulu or UTC time), is unterstood by DateTime class itself
|
||||
try {
|
||||
parent::__construct($t_str,$tz);
|
||||
break;
|
||||
}
|
||||
catch(Exception $e) {
|
||||
// if string is nummeric, ignore the exception and treat string as timestamp
|
||||
if (!is_numeric($time)) throw $e;
|
||||
}
|
||||
}
|
||||
$type = 'integer';
|
||||
// fall through for timestamps
|
||||
case 'double': // 64bit integer (timestamps > 2038) are treated on 32bit systems as double
|
||||
case 'integer':
|
||||
/* ToDo: Check if PHP5.3 setTimestamp does the same, or always expects UTC timestamp
|
||||
if (PHP_VERSION >= 5.3)
|
||||
{
|
||||
parent::__construct('now',$tz);
|
||||
$datetime->setTimestamp($time);
|
||||
}
|
||||
else*/
|
||||
{
|
||||
parent::__construct(date('Y-m-d H:i:s',$time),$tz);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'array':
|
||||
parent::__construct('now',$tz);
|
||||
if (isset($time['Y'])) // array format used in eTemplate
|
||||
{
|
||||
$time = array(
|
||||
'year' => $time['Y'],
|
||||
'month' => $time['m'],
|
||||
'day' => $time['d'],
|
||||
'hour' => $time['H'],
|
||||
'minute' => $time['i'],
|
||||
'second' => $time['s'],
|
||||
);
|
||||
}
|
||||
if (!empty($time['full']) && empty($time['year']))
|
||||
{
|
||||
$time['year'] = (int)substr($time['full'],0,4);
|
||||
$time['month'] = (int)substr($time['full'],4,2);
|
||||
$time['day'] = (int)substr($time['full'],6,2);
|
||||
}
|
||||
if (isset($time['year'])) $this->setDate((int)$time['year'],(int)$time['month'],isset($time['day']) ? (int)$time['day'] : (int)$time['mday']);
|
||||
$this->setTime((int)$time['hour'],(int)$time['minute'],(int)$time['second']);
|
||||
break;
|
||||
|
||||
case 'object':
|
||||
if ($time instanceof DateTime)
|
||||
{
|
||||
parent::__construct($time->format('Y-m-d H:i:s'),$time->getTimezone());
|
||||
$this->setTimezone($tz);
|
||||
break;
|
||||
}
|
||||
// fall through
|
||||
default:
|
||||
throw new egw_exception_assertion_failed("Not implemented for type ($type)$time!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Like DateTime::add, but additional allow to use a string run through DateInterval::createFromDateString
|
||||
*
|
||||
* @param DateInterval|string $interval eg. '1 day', '-2 weeks'
|
||||
*/
|
||||
public function add($interval)
|
||||
{
|
||||
if (is_string($interval)) $interval = DateInterval::createFromDateString($interval);
|
||||
|
||||
parent::add($interval);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set date to beginning of the week taking into account calendar weekdaystarts preference
|
||||
*/
|
||||
public function setWeekstart()
|
||||
{
|
||||
$wday = (int) $this->format('w'); // 0=sun, ..., 6=sat
|
||||
switch($GLOBALS['egw_info']['user']['preferences']['calendar']['weekdaystarts'])
|
||||
{
|
||||
case 'Sunday':
|
||||
$wstart = -$wday;
|
||||
break;
|
||||
case 'Saturday':
|
||||
$wstart = -(6-$wday);
|
||||
break;
|
||||
case 'Moday':
|
||||
default:
|
||||
$wstart = -($wday ? $wday-1 : 6);
|
||||
break;
|
||||
}
|
||||
if ($wstart) $this->add($wstart.'days');
|
||||
}
|
||||
|
||||
/**
|
||||
* return SQL implementing filtering by date
|
||||
*
|
||||
* @param string $name
|
||||
* @param int &$start
|
||||
* @param int &$end
|
||||
* @param string $column name of timestamp column to use in returned sql
|
||||
* @param array $filters $name => list($syear,$smonth,$sday,$sweek,$eyear,$emonth,$eday,$eweek) pairs with offsets
|
||||
* @return string
|
||||
*/
|
||||
public static function sql_filter($name, &$start, &$end, $column, array $filters=array())
|
||||
{
|
||||
if ($name == 'custom' && $start)
|
||||
{
|
||||
$start = new egw_time($start);
|
||||
$start->setTime(0, 0, 0);
|
||||
|
||||
if ($end)
|
||||
{
|
||||
$end = new egw_time($end);
|
||||
$end->setTime(0, 0, 0);
|
||||
$end->add('+1day');
|
||||
}
|
||||
else
|
||||
{
|
||||
$end = new egw_time($start);
|
||||
$end->add('+1week');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!isset($filters[$name]))
|
||||
{
|
||||
return '1=1';
|
||||
}
|
||||
$start = new egw_time('now');
|
||||
$start->setTime(0, 0, 0);
|
||||
$end = new egw_time('now');
|
||||
$end->setTime(0, 0, 0);
|
||||
|
||||
$year = (int) $start->format('Y');
|
||||
$month = (int) $start->format('m');
|
||||
|
||||
list($syear,$smonth,$sday,$sweek,$eyear,$emonth,$eday,$eweek) = $filters[$name];
|
||||
|
||||
// Handle quarters
|
||||
if(stripos($name, 'quarter') !== false)
|
||||
{
|
||||
$start->setDate($year, ((int)floor(($smonth+$month) / 3.1)) * 3 + 1, 1);
|
||||
$end->setDate($year, ((int)floor(($emonth+$month) / 3.1)+1) * 3 + 1, 1);
|
||||
}
|
||||
elseif ($syear || $eyear)
|
||||
{
|
||||
$start->setDate($year+$syear, 1, 1);
|
||||
$end->setDate($year+$eyear, 1, 1);
|
||||
}
|
||||
elseif ($smonth || $emonth)
|
||||
{
|
||||
$start->setDate($year, $month+$smonth, 1);
|
||||
$end->setDate($year, $month+$emonth, 1);
|
||||
}
|
||||
elseif ($sday || $eday)
|
||||
{
|
||||
if ($sday) $start->add($sday.'days');
|
||||
if ($eday) $end->add($eday.'days');
|
||||
}
|
||||
elseif ($sweek || $eweek)
|
||||
{
|
||||
$start->setWeekstart();
|
||||
if ($sweek) $start->add($sweek.'weeks');
|
||||
$end->setWeekstart();
|
||||
if ($eweek) $end->add($eweek.'weeks');
|
||||
}
|
||||
}
|
||||
// convert start + end from user to servertime for the filter
|
||||
$sql = '('.egw_time::user2server($start, 'ts').' <= '.$column.' AND '.$column.' < '.egw_time::user2server($end, 'ts').')';
|
||||
//error_log(__METHOD__."('$name', ...) syear=$syear, smonth=$smonth, sday=$sday, sweek=$sweek, eyear=$eyear, emonth=$emonth, eday=$eday, eweek=$eweek --> start=".$start->format().', end='.$end->format().", sql='$sql'");
|
||||
|
||||
// returned timestamps: $end is an inclusive date, eg. for today it's equal to start!
|
||||
$start = $start->format('ts');
|
||||
$end->add('-1day');
|
||||
$end = $end->format('ts');
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set user timezone, according to user prefs: converts current time to user time
|
||||
*
|
||||
* Does nothing if self::$user_timezone is current timezone!
|
||||
*/
|
||||
public function setUser()
|
||||
{
|
||||
$this->setTimezone(self::$user_timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set server timezone: converts current time to server time
|
||||
*
|
||||
* Does nothing if self::$server_timezone is current timezone!
|
||||
*/
|
||||
public function setServer()
|
||||
{
|
||||
$this->setTimezone(self::$server_timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format DateTime object as a specific type or string
|
||||
*
|
||||
* @param string $type='' 'integer'|'ts'=timestamp, 'server'=timestamp in servertime, 'string'='Y-m-d H:i:s', 'object'=DateTime,
|
||||
* 'array'=array with values for keys ('year','month','day','hour','minute','second','full','raw') or string with format
|
||||
* true = date only, false = time only as in user prefs, '' = date+time as in user prefs
|
||||
* @return int|string|array|datetime see $type
|
||||
*/
|
||||
public function format($type='')
|
||||
{
|
||||
switch((string)$type)
|
||||
{
|
||||
case '': // empty string: date and time as in user prefs
|
||||
//case '': // boolean false: time as in user prefs
|
||||
case '1': // boolean true: date as in user prefs
|
||||
if (is_bool($type))
|
||||
{
|
||||
$type = $type ? self::$user_dateformat : self::$user_timeformat;
|
||||
}
|
||||
else
|
||||
{
|
||||
$type = self::$user_dateformat.', '.self::$user_timeformat;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
$type = self::DATABASE;
|
||||
break;
|
||||
|
||||
case 'server': // timestamp in servertime
|
||||
$this->setServer();
|
||||
// fall through
|
||||
case 'integer':
|
||||
case 'ts':
|
||||
// ToDo: Check if PHP5.3 getTimestamp does the same, or always returns UTC timestamp
|
||||
return mktime(parent::format('H'),parent::format('i'),parent::format('s'),parent::format('m'),parent::format('d'),parent::format('Y'));
|
||||
|
||||
case 'object':
|
||||
case 'datetime':
|
||||
case 'egw_time':
|
||||
return clone($this);
|
||||
|
||||
case 'array':
|
||||
$arr = array(
|
||||
'year' => (int)parent::format('Y'),
|
||||
'month' => (int)parent::format('m'),
|
||||
'day' => (int)parent::format('d'),
|
||||
'hour' => (int)parent::format('H'),
|
||||
'minute' => (int)parent::format('i'),
|
||||
'second' => (int)parent::format('s'),
|
||||
'full' => parent::format('Ymd'),
|
||||
);
|
||||
$arr['raw'] = mktime($arr['hour'],$arr['minute'],$arr['second'],$arr['month'],$arr['day'],$arr['year']);
|
||||
return $arr;
|
||||
|
||||
case 'date_array': // array with short keys used by date: Y, m, d, H, i, s (used in eTemplate)
|
||||
return array(
|
||||
'Y' => (int)parent::format('Y'),
|
||||
'm' => (int)parent::format('m'),
|
||||
'd' => (int)parent::format('d'),
|
||||
'H' => (int)parent::format('H'),
|
||||
'i' => (int)parent::format('i'),
|
||||
's' => (int)parent::format('s'),
|
||||
);
|
||||
}
|
||||
// default $type contains string with format
|
||||
return parent::format($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast object to string
|
||||
*
|
||||
* @return string eg. "Wednesday, 2009-11-11 11:11:11 (Europe/Berlin)"
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->format('l, '.self::DATABASE).' ('.$this->getTimezone()->getName().')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a server time into a user time
|
||||
*
|
||||
* @param int|string|array|DateTime $time
|
||||
* @param string $type=null type or return-value, default (null) same as $time
|
||||
* @return int|string|array|datetime null if time could not be parsed
|
||||
*/
|
||||
public static function server2user($time,$type=null)
|
||||
{
|
||||
$typeof='egw_time';
|
||||
if (!($time instanceof egw_time))
|
||||
{
|
||||
try
|
||||
{
|
||||
$time = new egw_time($time,self::$server_timezone,$typeof);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
return null; // time could not be parsed
|
||||
}
|
||||
}
|
||||
$time->setUser();
|
||||
|
||||
if (is_null($type)) $type = $typeof;
|
||||
|
||||
//echo "<p>".__METHOD__."($time,$type) = ".print_r($format->format($type),true)."</p>\n";
|
||||
return $time->format($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a user time into a server time
|
||||
*
|
||||
* @param int|string|array|datetime $time
|
||||
* @param string $type=null type or return-value, default (null) same as $time
|
||||
* @return int|string|array|datetime null if time could not be parsed
|
||||
*/
|
||||
public static function user2server($time,$type=null)
|
||||
{
|
||||
$typeof='egw_time';
|
||||
if (!($time instanceof egw_time))
|
||||
{
|
||||
try
|
||||
{
|
||||
$time = new egw_time($time,self::$user_timezone,$typeof);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
return null; // time could not be parsed
|
||||
}
|
||||
}
|
||||
$time->setServer();
|
||||
|
||||
if (is_null($type)) $type = $typeof;
|
||||
|
||||
//echo "<p>".__METHOD__."($time,$type) = ".print_r($format->format($type),true)."</p>\n";
|
||||
return $time->format($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert time to a specific format or string, static version of egw_time::format()
|
||||
*
|
||||
* @param int|string|array|DateTime $time='now' see constructor
|
||||
* @param string $type='' 'integer'|'ts'=timestamp, 'server'=timestamp in servertime, 'string'='Y-m-d H:i:s', 'object'=DateTime,
|
||||
* 'array'=array with values for keys ('year','month','day','hour','minute','second','full','raw') or string with format
|
||||
* true = date only, false = time only as in user prefs, '' = date+time as in user prefs
|
||||
* @return int|string|array|datetime see $type, null if time could not be parsed
|
||||
*/
|
||||
public static function to($time='now',$type='')
|
||||
{
|
||||
if (!($time instanceof egw_time))
|
||||
{
|
||||
try
|
||||
{
|
||||
$time = new egw_time($time);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
return null; // time could not be parsed
|
||||
}
|
||||
}
|
||||
return $time->format($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for user timezone, should be called after reading user preferences
|
||||
*
|
||||
* @param string $tz timezone, eg. 'Europe/Berlin' or 'UTC'
|
||||
* @param string $dateformat='' eg. 'Y-m-d' or 'd.m.Y'
|
||||
* @param string|int $timeformat='' integer 12, 24, or format string eg. 'H:i'
|
||||
* @throws egw_exception_wrong_userinput if invalid $tz parameter
|
||||
* @return DateTimeZone
|
||||
*/
|
||||
public static function setUserPrefs($tz,$dateformat='',$timeformat='')
|
||||
{
|
||||
//echo "<p>".__METHOD__."('$tz','$dateformat','$timeformat') ".function_backtrace()."</p>\n";
|
||||
if (!empty($dateformat)) self::$user_dateformat = $dateformat;
|
||||
|
||||
switch($timeformat)
|
||||
{
|
||||
case '':
|
||||
break;
|
||||
case '24':
|
||||
self::$user_timeformat = 'H:i';
|
||||
break;
|
||||
case '12':
|
||||
self::$user_timeformat = 'h:i a';
|
||||
break;
|
||||
default:
|
||||
self::$user_timeformat = $timeformat;
|
||||
break;
|
||||
}
|
||||
try {
|
||||
self::$user_timezone = new DateTimeZone($tz);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
// silently use server timezone, as we have no means to report the wrong timezone to the user from this class
|
||||
self::$user_timezone = clone(self::$server_timezone);
|
||||
}
|
||||
return self::$user_timezone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get offset in seconds between user and server time at given time $time
|
||||
*
|
||||
* Compatibility method for old code. It is only valid for the given time, because of possible daylight saving changes!
|
||||
*
|
||||
* @param int|string|DateTime $time='now'
|
||||
* @return int difference in seconds between user and server time (for the given time!)
|
||||
*/
|
||||
public static function tz_offset_s($time='now')
|
||||
{
|
||||
if (!($time instanceof DateTime)) $time = new egw_time($time);
|
||||
|
||||
return egw_time::$user_timezone->getOffset($time) - egw_time::$server_timezone->getOffset($time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Init static variables, reading user prefs
|
||||
*/
|
||||
public static function init()
|
||||
{
|
||||
// if no server timezone set, use date_default_timezone_get() to determine it
|
||||
if (empty($GLOBALS['egw_info']['server']['server_timezone']))
|
||||
{
|
||||
$GLOBALS['egw_info']['server']['server_timezone'] = date_default_timezone_get();
|
||||
}
|
||||
// make sure we have a valid server timezone set
|
||||
try {
|
||||
self::$server_timezone = new DateTimeZone($GLOBALS['egw_info']['server']['server_timezone']);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
try {
|
||||
self::$server_timezone = new DateTimeZone(date_default_timezone_get());
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
self::$server_timezone = new DateTimeZone('Europe/Berlin');
|
||||
}
|
||||
error_log(__METHOD__."() invalid server_timezone='{$GLOBALS['egw_info']['server']['server_timezone']}' setting now '".self::$server_timezone->getName()."'!");
|
||||
config::save_value('server_timezone',$GLOBALS['egw_info']['server']['server_timezone'] = self::$server_timezone->getName(),'phpgwapi');
|
||||
}
|
||||
if (!isset($GLOBALS['egw_info']['user']['preferences']['common']['tz']))
|
||||
{
|
||||
$GLOBALS['egw_info']['user']['preferences']['common']['tz'] = $GLOBALS['egw_info']['server']['server_timezone'];
|
||||
}
|
||||
self::setUserPrefs($GLOBALS['egw_info']['user']['preferences']['common']['tz'],
|
||||
$GLOBALS['egw_info']['user']['preferences']['common']['dateformat'],
|
||||
$GLOBALS['egw_info']['user']['preferences']['common']['timeformat']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return "beautified" timezone list:
|
||||
* - no depricated timezones
|
||||
* - return UTC and oceans at the end
|
||||
* - if (user lang is a european language), move Europe to top
|
||||
*
|
||||
* @return array continent|ocean => array(tz-name => tz-label incl. current time)
|
||||
*/
|
||||
public static function getTimezones()
|
||||
{
|
||||
// prepare list of timezones from php, ignoring depricated ones and sort as follows
|
||||
$tzs = array(
|
||||
'Africa' => array(), // Contients
|
||||
'America' => array(),
|
||||
'Asia' => array(),
|
||||
'Australia' => array(),
|
||||
'Europe' => array(),
|
||||
'Atlantic' => array(), // Oceans
|
||||
'Pacific' => array(),
|
||||
'Indian' => array(),
|
||||
'Antarctica' => array(), // Poles
|
||||
'Arctic' => array(),
|
||||
'UTC' => array('UTC' => 'UTC'),
|
||||
);
|
||||
// no VTIMEZONE available in calendar_timezones --> do NOT return them
|
||||
static $no_vtimezone = array(
|
||||
'Europe/Tiraspol',
|
||||
'America/Atka',
|
||||
'America/Buenos_Aires',
|
||||
'America/Catamarca',
|
||||
'America/Coral_Harbour',
|
||||
'America/Cordoba',
|
||||
'America/Ensenada',
|
||||
'America/Fort_Wayne',
|
||||
'America/Indianapolis',
|
||||
'America/Jujuy',
|
||||
'America/Knox_IN',
|
||||
'America/Mendoza',
|
||||
'America/Porto_Acre',
|
||||
'America/Rosario',
|
||||
'America/Virgin',
|
||||
'Asia/Ashkhabad',
|
||||
'Asia/Beijing',
|
||||
'Asia/Chungking',
|
||||
'Asia/Dacca',
|
||||
'Asia/Macao',
|
||||
'Asia/Riyadh87',
|
||||
'Asia/Riyadh88',
|
||||
'Asia/Riyadh89',
|
||||
'Asia/Tel_Aviv',
|
||||
'Asia/Thimbu',
|
||||
'Asia/Ujung_Pandang',
|
||||
'Asia/Ulan_Bator',
|
||||
'Australia/ACT',
|
||||
'Australia/Canberra',
|
||||
'Australia/LHI',
|
||||
'Australia/North',
|
||||
'Australia/NSW',
|
||||
'Australia/Queensland',
|
||||
'Australia/South',
|
||||
'Australia/Tasmania',
|
||||
'Australia/Victoria',
|
||||
'Australia/West',
|
||||
'Australia/Yancowinna',
|
||||
'Pacific/Samoa',
|
||||
);
|
||||
foreach(DateTimeZone::listIdentifiers() as $name)
|
||||
{
|
||||
if (in_array($name,$no_vtimezone)) continue; // do NOT allow to set in EGroupware, as we have not VTIMEZONE component for it
|
||||
list($continent,$rest) = explode('/',$name,2);
|
||||
if (!isset($tzs[$continent])) continue; // old depricated timezones
|
||||
$datetime = new egw_time('now',new DateTimeZone($name));
|
||||
$tzs[$continent][$name] = str_replace(array('_','/'),array(' ',' / '),$name)." ".$datetime->format();
|
||||
unset($datetime);
|
||||
}
|
||||
foreach($tzs as $continent => &$data)
|
||||
{
|
||||
natcasesort($data); // sort cities
|
||||
}
|
||||
unset($data);
|
||||
|
||||
// if user lang or installed langs contain a european language --> move Europe to top of tz list
|
||||
$langs = class_exists('translation') ? translation::get_installed_langs() : array();
|
||||
if (array_intersect(array($GLOBALS['egw_info']['user']['preferences']['common']['lang'])+array_keys($langs),
|
||||
array('de','fr','it','nl','bg','ca','cs','da','el','es-es','et','eu','fi','hr','hu','lt','no','pl','pt','sk','sl','sv','tr','uk')))
|
||||
{
|
||||
$tzs = array_merge(array('Europe' => $tzs['Europe']),$tzs);
|
||||
}
|
||||
return $tzs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user timezones (the ones user selected in his prefs), plus evtl. an extra one
|
||||
*
|
||||
* @param string $extra extra timezone to add, if not already included in user timezones
|
||||
* @return array tzid => label
|
||||
*/
|
||||
public static function getUserTimezones($extra=null)
|
||||
{
|
||||
$tz = $GLOBALS['egw_info']['user']['preferences']['common']['tz'];
|
||||
$user_tzs = explode(',',$GLOBALS['egw_info']['user']['preferences']['common']['tz_selection']);
|
||||
if (count($user_tzs) <= 1)
|
||||
{
|
||||
$user_tzs = $tz ? array($tz) : array();
|
||||
}
|
||||
if ($tz && !in_array($tz,$user_tzs))
|
||||
{
|
||||
$user_tzs = array_merge(array($tz),$user_tzs);
|
||||
}
|
||||
if (!$user_tzs) // if we have no user timezones, eg. user set no pref --> use server default
|
||||
{
|
||||
$user_tzs = array($GLOBALS['egw_info']['server']['server_timezone']);
|
||||
}
|
||||
if ($extra && !in_array($extra,$user_tzs))
|
||||
{
|
||||
$user_tzs = array_merge(array($extra),$user_tzs);
|
||||
}
|
||||
$user_tzs = array_combine($user_tzs,$user_tzs);
|
||||
foreach($user_tzs as $name => &$label)
|
||||
{
|
||||
$label = str_replace(array('_','/'),array(' ',' / '),$label);
|
||||
}
|
||||
//_debug_array($user_tzs);
|
||||
return $user_tzs;
|
||||
}
|
||||
}
|
||||
egw_time::init();
|
||||
|
||||
/*
|
||||
if (isset($_SERVER['SCRIPT_FILENAME']) && $_SERVER['SCRIPT_FILENAME'] == __FILE__) // some tests
|
||||
{
|
||||
// test timestamps/dates before 1970
|
||||
foreach(array('19690811',-3600,'-119322000') as $ts)
|
||||
{
|
||||
try {
|
||||
echo "<p>egw_time::to($ts,'Y-m-d H:i:s')=".egw_time::to($ts,'Y-m-d H:i:s')."</p>\n";
|
||||
$et = new egw_time($ts);
|
||||
echo "<p>egw_time($ts)->format('Y-m-d H:i:s')=".$et->format('Y-m-d H:i:s')."</p>\n";
|
||||
$dt = new DateTime($ts);
|
||||
echo "<p>DateTime($ts)->format('Y-m-d H:i:s')=".$dt->format('Y-m-d H:i:s')."</p>\n";
|
||||
} catch(Exception $e) {
|
||||
echo "<p><b>Exception</b>: ".$e->getMessage()."</p>\n";
|
||||
}
|
||||
}
|
||||
// user time is UTC
|
||||
echo "<p>user timezone = ".($GLOBALS['egw_info']['user']['preferences']['common']['tz'] = 'UTC').", server timezone = ".date_default_timezone_get()."</p>\n";
|
||||
|
||||
$time = time();
|
||||
echo "<p>time=$time=".date('Y-m-d H:i:s',$time)."(server) =".egw_time::server2user($time,'Y-m-d H:i:s')."(user) =".egw_time::server2user($time,'ts')."(user)=".date('Y-m-d H:i:s',egw_time::server2user($time,'ts'))."</p>\n";
|
||||
|
||||
echo "egw_time::to(array('full' => '20091020', 'hour' => 12, 'minute' => 0))='".egw_time::to(array('full' => '20091020', 'hour' => 12, 'minute' => 0))."'</p>\n";
|
||||
|
||||
$ts = egw_time::to(array('full' => '20091027', 'hour' => 10, 'minute' => 0),'ts');
|
||||
echo "<p>2009-10-27 10h UTC timestamp=$ts --> server time = ".egw_time::user2server($ts,'')." --> user time = ".egw_time::server2user(egw_time::user2server($ts),'')."</p>\n";
|
||||
|
||||
$ts = egw_time::to(array('full' => '20090627', 'hour' => 10, 'minute' => 0),'ts');
|
||||
echo "<p>2009-06-27 10h UTC timestamp=$ts --> server time = ".egw_time::user2server($ts,'')." --> user time = ".egw_time::server2user(egw_time::user2server($ts),'')."</p>\n";
|
||||
}
|
||||
*/
|
||||
class egw_time extends Api\DateTime {}
|
||||
|
Loading…
Reference in New Issue
Block a user