Use egw_time for InfoLog, tracking backend and Tracker

This commit is contained in:
Jörg Lehrke 2010-02-04 12:08:03 +00:00
parent ba2518a60e
commit 75746226a4
11 changed files with 185 additions and 98 deletions

View File

@ -121,12 +121,12 @@ class addressbook_tracking extends bo_tracking
if (!$data['modified'] || !$old)
{
return lang('New contact submitted by %1 at %2',
$GLOBALS['egw']->common->grab_owner_name($data['creator']),
$this->datetime($data['created']-$this->tracker->tz_offset_s));
common::grab_owner_name($data['creator']),
$this->datetime($data['created']));
}
return lang('Contact modified by %1 at %2',
$GLOBALS['egw']->common->grab_owner_name($data['modifier']),
$this->datetime($data['modified']-$this->tracker->tz_offset_s));
common::grab_owner_name($data['modifier']),
$this->datetime($data['modified']));
}
/**
@ -167,7 +167,7 @@ class addressbook_tracking extends bo_tracking
case 'created': case 'modified':
$details[$name] = array(
'label' => $label,
'value' => $this->datetime($data[$name]-$this->contacts->tz_offset_s),
'value' => $this->datetime($data[$name]),
);
break;
case 'bday':
@ -176,14 +176,14 @@ class addressbook_tracking extends bo_tracking
list($y,$m,$d) = explode('-',$data[$name]);
$details[$name] = array(
'label' => $label,
'value' => $GLOBALS['egw']->common->dateformatorder($y,$m,$d,true),
'value' => common::dateformatorder($y,$m,$d,true),
);
}
break;
case 'owner': case 'creator': case 'modifier':
$details[$name] = array(
'label' => $label,
'value' => $GLOBALS['egw']->common->grab_owner_name($data[$name]),
'value' => common::grab_owner_name($data[$name]),
);
break;
case 'cat_id':

View File

@ -1030,7 +1030,7 @@ class calendar_bo
* string (!) in form YYYYMMDD or iso8601 YYYY-MM-DDThh:mm:ss or YYYYMMDDThhmmss
* int already a timestamp
* array with keys 'second', 'minute', 'hour', 'day' or 'mday' (depricated !), 'month' and 'year'
* @param boolean $user2server_time conversation between user- and server-time default False == Off
* @param boolean $user2server=False conversion between user- and server-time; default False == Off
*/
static function date2ts($date,$user2server=False)
{

View File

@ -2029,7 +2029,7 @@ class calendar_boupdate extends calendar_bo
}
/*
* Translates all timestamps for a given event from servert-ime to user-time.
* Translates all timestamps for a given event from server-time to user-time.
* The update() and save() methods expect timestamps in user-time.
* @param &$event the event we are working on
*

View File

@ -157,12 +157,6 @@ abstract class bo_tracking
* @var string
*/
var $datetime_format;
/**
* Offset to server-time of the currently notified user (send_notificaton)
*
* @var int
*/
var $tz_offset_s;
/**
* Should the class allow html content (for notifications)
*
@ -530,22 +524,26 @@ abstract class bo_tracking
/**
* Return date+time formatted for the currently notified user (prefs in $GLOBALS['egw_info']['user']['preferences'])
*
* @param int $timestamp
* @param int|string|DateTime $timestamp in user-time
* @param boolean $do_time=true true=allways (default), false=never print the time, null=print time if != 00:00
* @todo implement timezone handling via 'tz' pref
*
* @return string
*/
public function datetime($timestamp,$do_time=true)
{
if (!is_a($timestamp,'DateTime'))
{
$timestamp = new egw_time($timestamp,egw_time::$user_timezone);
}
$timestamp->setTimezone(egw_time::$user_timezone);
if (is_null($do_time))
{
$do_time = date('H:i',$timestamp+$this->tz_offset_s) != '00:00';
$do_time = ($timestamp->format('Hi') != '0000');
}
$format = $GLOBALS['egw_info']['user']['preferences']['common']['dateformat'];
if ($do_time) $format .= ' '.($GLOBALS['egw_info']['user']['preferences']['common']['timeformat'] != 12 ? 'H:i' : 'h:i a');
//error_log("bo_tracking::datetime($timestamp,$do_time)=date('$format',$timestamp+$this->tz_offset_s)='".date($format,$timestamp+$this->tz_offset_s).'\')');
return date($format,$timestamp+3600 * $GLOBALS['egw_info']['user']['preferences']['common']['tz_offset']);
return $timestamp->format($format);
}
/**

View File

@ -227,8 +227,9 @@ class boinfolog extends infolog_bo
/**
* Convert an InfoLog entry into its xmlrpc representation, eg. convert timestamps to datetime.iso8601
*
* @param array $data infolog entry
* @param array xmlrpc infolog entry
* @param array $data infolog entry in db format
*
* @return array xmlrpc infolog entry
*/
function data2xmlrpc($data)
{
@ -272,8 +273,9 @@ class boinfolog extends infolog_bo
/**
* Convert an InfoLog xmlrpc representation into the internal one, eg. convert datetime.iso8601 to timestamps
*
* @param array $data infolog entry
* @param array xmlrpc infolog entry
* @param array $data infolog entry in xmlrpc representation
*
* @return array infolog entry in db format
*/
function xmlrpc2data($data)
{

View File

@ -31,15 +31,14 @@ class infolog_bo
var $link_pathes = array();
var $send_file_ips = array();
var $tz_offset = 0;
/**
* offset in secconds between user and server-time,
* it need to be add to a server-time to get the user-time or substracted from a user-time to get the server-time
* current time as timestamp in user-time and server-time
*
* @var int
* var int
*/
var $tz_offset_s = 0;
var $user_time_now;
var $now;
/**
* name of timestamps in an InfoLog entry
*
@ -233,9 +232,8 @@ class infolog_bo
$this->user = $GLOBALS['egw_info']['user']['account_id'];
$this->tz_offset = $GLOBALS['egw_info']['user']['preferences']['common']['tz_offset'];
$this->tz_offset_s = 60*60*$this->tz_offset;
$this->user_time_now = time() + $this->tz_offset_s;
$this->user_time_now = egw_time::to('now','ts');
$this->now = time();
$this->grants = $GLOBALS['egw']->acl->get_grants('infolog',$this->group_owners ? $this->group_owners : true);
$this->so = new infolog_so($this->grants);
@ -405,15 +403,32 @@ class infolog_bo
return substr($des,0,60).' ...';
}
/**
* convert a date from server to user-time
*
* @param int $ts timestamp in server-time
* @param string $date_format='ts' date-formats: 'ts'=timestamp, 'server'=timestamp in server-time, 'array'=array or string with date-format
* @return mixed depending of $date_format
*/
function date2usertime($ts,$date_format='ts')
{
if (empty($ts) || $date_format == 'server') return $ts;
return egw_time::server2user($ts,$date_format);
}
/**
* Read an infolog entry specified by $info_id
*
* @param int/array $info_id integer id or array with key 'info_id' of the entry to read
* @param boolean $run_link_id2from=true should link_id2from run, default yes,
* need to be set to false if called from link-title to prevent an infinit recursion
* @param string $date_format='ts' date-formats: 'ts'=timestamp, 'server'=timestamp in server-time,
* 'array'=array or string with date-format
*
* @return array/boolean infolog entry, null if not found or false if no permission to read it
*/
function &read($info_id,$run_link_id2from=true)
function &read($info_id,$run_link_id2from=true,$date_format='ts')
{
if (is_array($info_id))
{
@ -437,13 +452,30 @@ class infolog_bo
}
if ($run_link_id2from) $this->link_id2from($data);
if ($data['info_enddate'])
{
// Set due date to 00:00
$due = new egw_time($data['info_enddate'], egw_time::$server_timezone);
$due->setTime(0, 0, 0);
if ($date_format != 'server')
{
$arr = egw_time::to($due,'array');
$due = new egw_time($arr, egw_time::$user_timezone);
}
$data['info_enddate'] = egw_time::to($due,'server');
}
// convert system- to user-time
foreach($this->timestamps as $time)
{
if ($data[$time]) $data[$time] += $this->tz_offset_s;
if ($data[$time]) $data[$time] = $this->date2usertime($data[$time],$date_format);
}
if ($date_format == 'ts')
{
// pre-cache title and file access
self::set_link_cache($data);
}
return $data;
}
@ -492,7 +524,7 @@ class infolog_bo
$deleted = $info;
$deleted['info_status'] = 'deleted';
$deleted['info_datemodified'] = time();
$deleted['info_datemodified'] = $this->user_time_now;
$deleted['info_modifier'] = $this->user;
// if we have history switched on and not an already deleted item --> set only status deleted
@ -532,9 +564,11 @@ class infolog_bo
* @param array &$values values to write
* @param boolean $check_defaults=true check and set certain defaults
* @param boolean $touch_modified=true touch the modification data and sets the modiefier's user-id
* @param boolean $user2server=true conversion between user- and server-time necessary
*
* @return int/boolean info_id on a successfull write or false
*/
function write(&$values, $check_defaults=True, $touch_modified=True)
function write(&$values, $check_defaults=true, $touch_modified=true, $user2server=true)
{
//echo "boinfolog::write()values="; _debug_array($values);
if ($status_only = $values['info_id'] && !$this->check_access($values['info_id'],EGW_ACL_EDIT))
@ -578,7 +612,7 @@ class infolog_bo
}
if ($set_completed)
{
$values['info_datecompleted'] = $this->user_time_now;
$values['info_datecompleted'] = $user2server ? $this->user_time_now : $this->now;
$values['info_percent'] = 100;
$forcestatus = true;
$status = 'done';
@ -605,7 +639,7 @@ class infolog_bo
if (!$values['info_datecompleted'] &&
(in_array($values['info_status'],array('done','billed')) || (int)$values['info_percent'] == 100))
{
$values['info_datecompleted'] = $this->user_time_now; // set date completed to today if status == done
$values['info_datecompleted'] = $user2server ? $this->user_time_now : $this->now; // set date completed to today if status == done
}
if (in_array($values['info_status'],array('done','billed')))
{
@ -651,18 +685,58 @@ class infolog_bo
{
$values['info_owner'] = $this->so->user;
}
if ($info_from_set = ($values['info_link_id'] && isset($values['info_from']) && empty($values['info_from'])))
{
$values['info_from'] = $this->link_id2from($values);
}
if ($status_only && !$undelete) $values = array_merge($backup_values,$values);
$to_write = $values;
if ($user2server)
{
// convert user- to system-time
foreach($this->timestamps as $time)
{
if ($to_write[$time]) $to_write[$time] = egw_time::user2server($to_write[$time],'ts');
}
if ($values['info_enddate'])
{
// Set due date to 00:00
$due = new egw_time($values['info_enddate'], egw_time::$user_timezone);
$due->setTime(0, 0, 0);
$values['info_enddate'] = egw_time::to($due,'ts');
$arr = egw_time::to($due,'array');
$to_write['info_enddate'] = mktime(0, 0, 0, $arr['month'], $arr['day'], $arr['year']);
}
}
else
{
// convert server- to user-time
foreach($this->timestamps as $time)
{
if ($values[$time]) $values[$time] = egw_time::server2user($values[$time],'ts');
}
if ($to_write['info_enddate'])
{
$due = new egw_time($to_write['info_enddate'], egw_time::$server_timezone);
$due->setTime(0, 0, 0);
$to_write['info_enddate'] = egw_time::to($due,'server');
$arr = egw_time::to($due,'array');
$due = new egw_time($arr, egw_time::$user_timezone);
$values['info_enddate'] = egw_time::to($due,'ts');
}
}
if ($touch_modified || !$values['info_datemodified'])
{
// Should only an entry be updated which includes the original modification date?
// Used in the web-GUI to check against a modification by an other user while editing the entry.
// It's now disabled for xmlrpc, as otherwise the xmlrpc code need to be changed!
$xmlrpc = is_object($GLOBALS['server']) && $GLOBALS['server']->last_method;
$check_modified = $values['info_datemodified'] && !$xmlrpc ? $values['info_datemodified']-$this->tz_offset_s : false;
$values['info_datemodified'] = $this->user_time_now;
$check_modified = $values['info_datemodified'] && !$xmlrpc ? $to_write['info_datemodified'] : false;
$values['info_datemodified'] = $user2server ? $this->user_time_now : $this->now;
}
if ($touch_modified || !$values['info_modifier'])
{
@ -670,13 +744,7 @@ class infolog_bo
}
//_debug_array($values);
// error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n".array2string($values)."\n",3,'/tmp/infolog');
$to_write = $values;
if ($status_only && !$undelete) $values = array_merge($backup_values,$values);
// convert user- to system-time
foreach($this->timestamps as $time)
{
if ($to_write[$time]) $to_write[$time] -= $this->tz_offset_s;
}
// we need to get the old values to update the links in customfields and for the tracking
if ($values['info_id'])
{
@ -764,6 +832,10 @@ class infolog_bo
function &search(&$query)
{
//echo "<p>boinfolog::search(".print_r($query,True).")</p>\n";
if (!empty($query['start']))
{
$query['start'] = egw_time::user2server($query['start'],'ts');
}
$ret = $this->so->search($query);
// convert system- to user-time
@ -771,13 +843,20 @@ class infolog_bo
{
foreach($ret as $id => &$data)
{
if($this->tz_offset_s)
if ($data['info_enddate'])
{
// Set due date to 00:00 in user-time
$due = new egw_time($data['info_enddate'], egw_time::$server_timezone);
$due->setTime(0, 0, 0);
$arr = egw_time::to($due,'array');
$due = new egw_time($arr, egw_time::$user_timezone);
$data['info_enddate'] = egw_time::to($due,'server');
}
foreach($this->timestamps as $time)
{
if ($data[$time]) $data[$time] += $this->tz_offset_s;
}
if ($data[$time]) $data[$time] = $this->date2usertime($data[$time]);
}
// pre-cache title and file access
self::set_link_cache($data);
}
@ -883,7 +962,7 @@ class infolog_bo
* @param int/array $info int info_id or array with infolog entry
* @return string/boolean string with the title, null if $info not found, false if no perms to view
*/
function link_title( $info )
function link_title($info)
{
if (!is_array($info))
{
@ -902,7 +981,7 @@ class infolog_bo
*
* @param array $ids
*/
function link_titles( array $ids )
function link_titles(array $ids)
{
$titles = array();
foreach($this->search($params=array(
@ -927,7 +1006,7 @@ class infolog_bo
* @param array $options Array of options for the search
* @return array with info_id - title pairs of the matching entries
*/
function link_query( $pattern, Array &$options = array() )
function link_query($pattern, Array &$options = array())
{
$query = array(
'search' => $pattern,
@ -1012,8 +1091,9 @@ class infolog_bo
{
foreach($infos as $info)
{
$time = (int) adodb_date('Hi',$info['info_startdate']);
$date = adodb_date('Y/m/d',$info['info_startdate']);
$start = new egw_time($info['info_startdate'],egw_time::$user_timezone);
$time = (int) $start->format('Hi');
$date = $start->format('Y/m/d');
/* As event-like infologs are not showen in current calendar,
we need to present all open infologs to the user! (2006-06-27 nelius)
if ($do_events && !$time ||
@ -1021,7 +1101,7 @@ class infolog_bo
{
continue;
}*/
$title = ($do_events?$GLOBALS['egw']->common->formattime(adodb_date('H',$info['info_startdate']),adodb_date('i',$info['info_startdate'])).' ':'').
$title = ($do_events?common::formattime($start->format('H'),$start->format('i')).' ':'').
$info['info_subject'];
$view = egw_link::view('infolog',$info['info_id']);
$content=array();
@ -1363,6 +1443,8 @@ class infolog_bo
/**
* Try to find a matching db entry
* This method is working completely in server-time and
* expects all time entriey to be 00:00 normalized.
*
* @param array $egwData the vTODO data we try to find
* @param boolean $relax=false if asked to relax, we only match against some key fields
@ -1373,7 +1455,7 @@ class infolog_bo
if (!empty($egwData['info_uid']))
{
$filter = array('col_filter' => array('info_uid' => $egwData['info_uid']));
if (($found = $this->search($filter))
if (($found = $this->so->search($filter))
&& ($uidmatch = array_shift($found)))
{
return $uidmatch['info_id'];
@ -1411,7 +1493,7 @@ class infolog_bo
$filter['col_filter'] = $egwData;
if($foundItems = $this->search($filter)) {
if($foundItems = $this->so->search($filter)) {
if(count($foundItems) > 0) {
$itemIDs = array_keys($foundItems);
return $itemIDs[0];
@ -1433,20 +1515,23 @@ class infolog_bo
// try tasks without category
unset($filter['col_filter']['info_cat']);
#Horde::logMessage("findVTODO Filter\n"
# . print_r($filter, true),
# __FILE__, __LINE__, PEAR_LOG_DEBUG);
foreach ($this->search($filter) as $itemID => $taskData) {
# Horde::logMessage("findVTODO Trying\n"
# . print_r($taskData, true),
# __FILE__, __LINE__, PEAR_LOG_DEBUG);
// Horde::logMessage("findVTODO Filter\n"
// . print_r($filter, true),
// __FILE__, __LINE__, PEAR_LOG_DEBUG);
foreach ($this->so->search($filter) as $itemID => $taskData)
{
// Horde::logMessage("findVTODO Trying\n"
// . print_r($taskData, true),
// __FILE__, __LINE__, PEAR_LOG_DEBUG);
if (isset($egwData['info_cat'])
&& isset($taskData['info_cat']) && $taskData['info_cat']
&& $egwData['info_cat'] != $taskData['info_cat']) continue;
if (isset($egwData['info_startdate'])
&& isset($taskData['info_startdate']) && $taskData['info_startdate']) {
$parts = @getdate($taskData['info_startdate']);
$startdate = @mktime(0, 0, 0, $parts['mon'], $parts['mday'], $parts['year']);
&& isset($taskData['info_startdate']) && $taskData['info_startdate'])
{
$time = new egw_time($taskData['info_startdate'],egw_time::$server_timezone);
$time->setTime(0, 0, 0);
$startdate = egw_time::to($time,'server');
if ($egwData['info_startdate'] != $startdate) continue;
}
// some clients don't support DTSTART
@ -1454,9 +1539,11 @@ class infolog_bo
&& (!isset($taskData['info_startdate']) || !$taskData['info_startdate'])
&& !$relax) continue;
if (isset($egwData['info_datecompleted'])
&& isset($taskData['info_datecompleted']) && $taskData['info_datecompleted']) {
$parts = @getdate($taskData['info_datecompleted']);
$enddate = @mktime(0, 0, 0, $parts['mon'], $parts['mday'], $parts['year']);
&& isset($taskData['info_datecompleted']) && $taskData['info_datecompleted'])
{
$time = new egw_time($taskData['info_datecompleted'],egw_time::$server_timezone);
$time->setTime(0, 0, 0);
$enddate = egw_time::to($time,'server');
if ($egwData['info_datecompleted'] != $enddate) continue;
}
if ((isset($egwData['info_datecompleted'])

View File

@ -181,7 +181,7 @@ class infolog_groupdav extends groupdav_handler
*/
function read($id)
{
return $this->bo->read($id,false);
return $this->bo->read($id,false,'server');
}
/**
@ -206,7 +206,7 @@ class infolog_groupdav extends groupdav_handler
{
if (!is_array($info))
{
$info = $this->bo->read($info);
$info = $this->bo->read($info,true,'server');
}
if (!is_array($info) || !isset($info['info_id']) || !isset($info['info_datemodified']))
{

View File

@ -111,7 +111,7 @@ class infolog_ical extends infolog_bo
*/
function exportVTODO($_taskID, $_version='2.0',$_method='PUBLISH')
{
$taskData = $this->read($_taskID);
$taskData = $this->read($_taskID, true, 'server');
if ($taskData['info_id_parent'])
{
@ -350,7 +350,7 @@ class infolog_ical extends infolog_bo
array2string($taskData)."\n",3,$this->logfile);
}
return $this->write($taskData);
return $this->write($taskData, true, true, false);
}
/**
@ -571,7 +571,7 @@ class infolog_ical extends infolog_bo
*/
function exportVNOTE($_noteID, $_type)
{
$note = $this->read($_noteID);
$note = $this->read($_noteID, true, 'server');
$note = $GLOBALS['egw']->translation->convert($note,
$GLOBALS['egw']->translation->charset(), 'UTF-8');
@ -676,7 +676,7 @@ class infolog_ical extends infolog_bo
array2string($note)."\n",3,$this->logfile);
}
return $this->write($note);
return $this->write($note, true, true, false);
}
/**

View File

@ -382,7 +382,7 @@ class infolog_sif extends infolog_bo
$taskData['info_datecompleted'] = 0;
}
$egwID = $this->write($egwData, false);
$egwID = $this->write($egwData, false, true, false);
return $egwID;
}
@ -402,7 +402,7 @@ class infolog_sif extends infolog_bo
switch($_sifType)
{
case 'task':
if (($taskData = $this->read($_id)))
if (($taskData = $this->read($_id, true, 'server')))
{
$vcal = new Horde_iCalendar('1.0');
@ -534,7 +534,7 @@ class infolog_sif extends infolog_bo
break;
case 'note':
if (($taskData = $this->read($_id)))
if (($taskData = $this->read($_id, true, 'server')))
{
$vcal = new Horde_iCalendar('1.0');

View File

@ -163,17 +163,17 @@ class infolog_tracking extends bo_tracking
if (!$old || $old['info_status'] == 'deleted')
{
return lang('New %1 created by %2 at %3',lang($this->infolog->enums['type'][$data['info_type']]),
$GLOBALS['egw']->common->grab_owner_name($this->infolog->user),$this->datetime(time()));
common::grab_owner_name($this->infolog->user),$this->datetime('now'));
}
elseif($data['info_status'] == 'deleted')
{
return lang('%1 deleted by %2 at %3',lang($this->infolog->enums['type'][$data['info_type']]),
$GLOBALS['egw']->common->grab_owner_name($data['info_modifier']),
$this->datetime($data['info_datemodified']-$this->infolog->tz_offset_s));
common::grab_owner_name($data['info_modifier']),
$this->datetime($data['info_datemodified']));
}
return lang('%1 modified by %2 at %3',lang($this->infolog->enums['type'][$data['info_type']]),
$GLOBALS['egw']->common->grab_owner_name($data['info_modifier']),
$this->datetime($data['info_datemodified']-$this->infolog->tz_offset_s));
common::grab_owner_name($data['info_modifier']),
$this->datetime($data['info_datemodified']));
}
/**
@ -192,7 +192,7 @@ class infolog_tracking extends bo_tracking
{
foreach($data['info_responsible'] as $uid)
{
$responsible[] = $GLOBALS['egw']->common->grab_owner_name($uid);
$responsible[] = common::grab_owner_name($uid);
}
}
if ($GLOBALS['egw_info']['user']['preferences']['infolog']['show_id'])
@ -205,13 +205,13 @@ class infolog_tracking extends bo_tracking
'info_addr' => $data['info_addr'],
'info_cat' => $data['info_cat'] ? $GLOBALS['egw']->categories->id2name($data['info_cat']) : '',
'info_priority' => lang($this->infolog->enums['priority'][$data['info_priority']]),
'info_owner' => $GLOBALS['egw']->common->grab_owner_name($data['info_owner']),
'info_owner' => common::grab_owner_name($data['info_owner']),
'info_status' => lang($data['info_status']=='deleted'?'deleted':$this->infolog->status[$data['info_type']][$data['info_status']]),
'info_percent' => (int)$data['info_percent'].'%',
'info_datecompleted' => $data['info_datecompleted'] ? $this->datetime($data['info_datecompleted']-$this->infolog->tz_offset_s) : '',
'info_datecompleted' => $data['info_datecompleted'] ? $this->datetime($data['info_datecompleted']) : '',
'info_location' => $data['info_location'],
'info_startdate' => $data['info_startdate'] ? $this->datetime($data['info_startdate']-$this->infolog->tz_offset_s,null) : '',
'info_enddate' => $data['info_enddate'] ? $this->datetime($data['info_enddate']-$this->infolog->tz_offset_s,false) : '',
'info_startdate' => $data['info_startdate'] ? $this->datetime($data['info_startdate'],null) : '',
'info_enddate' => $data['info_enddate'] ? $this->datetime($data['info_enddate'],false) : '',
'info_responsible' => implode(', ',$responsible),
'info_subject' => $data['info_subject'],
) as $name => $value)

View File

@ -121,11 +121,11 @@ class timesheet_tracking extends bo_tracking
if (!$data['ts_modified'] || !$old)
{
return lang('New timesheet submitted by %1 at %2',
$GLOBALS['egw']->common->grab_owner_name($data['ts_creator']),
$this->datetime($data['ts_created']-$this->tracker->tz_offset_s));
common::grab_owner_name($data['ts_creator']),
$this->datetime($data['ts_created']));
}
return lang('Timesheet modified by %1 at %2',
$data['ts_modifier'] ? $GLOBALS['egw']->common->grab_owner_name($data['ts_modifier']) : lang('Timesheet'),
$this->datetime($data['ts_modified']-$this->timesheet->tz_offset_s));
$data['ts_modifier'] ? common::grab_owner_name($data['ts_modifier']) : lang('Timesheet'),
$this->datetime($data['ts_modified']));
}
}