forked from extern/egroupware
* eTemplate2/all apps: fixing various timezone related issues
backport of Nathan and mine commits r47919, r48102, r48133, r48142, r48163, r48166 using now ISO time strings instead of timestamps for communication between client and server
This commit is contained in:
parent
843b12b357
commit
ba254be4fc
@ -1244,7 +1244,6 @@ app.classes.calendar = AppJS.extend(
|
|||||||
var alarm_date = this.et2.getWidgetById('new_alarm[date]');
|
var alarm_date = this.et2.getWidgetById('new_alarm[date]');
|
||||||
var alarm_options = _widget || this.et2.getWidgetById('new_alarm[options]');
|
var alarm_options = _widget || this.et2.getWidgetById('new_alarm[options]');
|
||||||
var start = this.et2.getWidgetById('start');
|
var start = this.et2.getWidgetById('start');
|
||||||
var date = 0;
|
|
||||||
|
|
||||||
if (alarm_date && alarm_options
|
if (alarm_date && alarm_options
|
||||||
&& start)
|
&& start)
|
||||||
@ -1260,7 +1259,8 @@ app.classes.calendar = AppJS.extend(
|
|||||||
var startDate = start.get_value();
|
var startDate = start.get_value();
|
||||||
if (startDate)
|
if (startDate)
|
||||||
{
|
{
|
||||||
date = startDate - parseInt(alarm_options.get_value());
|
var date = new Date(startDate);
|
||||||
|
date.setTime(date.getTime() - 1000 * parseInt(alarm_options.get_value()));
|
||||||
alarm_date.set_value(date);
|
alarm_date.set_value(date);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,9 +30,10 @@
|
|||||||
*
|
*
|
||||||
* @todo validation of date-duration
|
* @todo validation of date-duration
|
||||||
*
|
*
|
||||||
* @info beforeSendToClient is no longer neccessary, in order to handle date/time conversion, for this widget
|
* @info Communication between client and server is always done as a string in ISO8601/W3C
|
||||||
* as we are handling both timestamp and string date/time formats on client side
|
* format ("Y-m-d\TH:i:sP"). If the application specifies a different format
|
||||||
*
|
* for the field, the conversion is done as needed understand what the application
|
||||||
|
* sends, and to give the application what it wants when the form is submitted.
|
||||||
*/
|
*/
|
||||||
class etemplate_widget_date extends etemplate_widget_transformer
|
class etemplate_widget_date extends etemplate_widget_transformer
|
||||||
{
|
{
|
||||||
@ -48,9 +49,48 @@ class etemplate_widget_date extends etemplate_widget_transformer
|
|||||||
protected $legacy_options = 'dataformat,mode';
|
protected $legacy_options = 'dataformat,mode';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the provided date into the format needed for unambiguous communication
|
||||||
|
* with browsers (Javascript). We use W3C format to avoid timestamp issues.
|
||||||
|
*/
|
||||||
|
public function beforeSendToClient($cname)
|
||||||
|
{
|
||||||
|
if($this->type == 'date-houronly')
|
||||||
|
{
|
||||||
|
return parent::beforeSendToClient($cname);
|
||||||
|
}
|
||||||
|
|
||||||
|
$form_name = self::form_name($cname, $this->id);
|
||||||
|
$value =& self::get_array(self::$request->content, $form_name, false, true);
|
||||||
|
|
||||||
|
if($this->type != 'date-duration' && $value)
|
||||||
|
{
|
||||||
|
// string with formatting letters like for php's date() method
|
||||||
|
if ($this->attrs['dataformat'] && !is_numeric($value))
|
||||||
|
{
|
||||||
|
$date = date_create_from_format($this->attrs['dataformat'], $value, new DateTimeZone('UTC'));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$date = new egw_time((int)$value, new DateTimeZone('UTC'));
|
||||||
|
}
|
||||||
|
if($date)
|
||||||
|
{
|
||||||
|
// Set timezone to UTC so javascript doesn't add/subtract anything
|
||||||
|
$date->setTimezone(new DateTimeZone('UTC'));
|
||||||
|
$value = $date->format(egw_time::W3C);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate input
|
* Validate input
|
||||||
*
|
*
|
||||||
|
* For dates (except duration), it is always a full timestamp in W3C format,
|
||||||
|
* which we then convert to the format the application is expecting. This can
|
||||||
|
* be either a unix timestamp, just a date, just time, or whatever is
|
||||||
|
* specified in the template.
|
||||||
|
*
|
||||||
* @param string $cname current namespace
|
* @param string $cname current namespace
|
||||||
* @param array $expand values for keys 'c', 'row', 'c_', 'row_', 'cont'
|
* @param array $expand values for keys 'c', 'row', 'c_', 'row_', 'cont'
|
||||||
* @param array $content
|
* @param array $content
|
||||||
@ -78,12 +118,21 @@ class etemplate_widget_date extends etemplate_widget_transformer
|
|||||||
{
|
{
|
||||||
$valid = (string)$value === '' ? '' : (int)$value;
|
$valid = (string)$value === '' ? '' : (int)$value;
|
||||||
}
|
}
|
||||||
|
if($value)
|
||||||
|
{
|
||||||
|
$date = new egw_time($value);
|
||||||
|
}
|
||||||
|
if(!$value)
|
||||||
|
{
|
||||||
|
// Not null, blank
|
||||||
|
$value = '';
|
||||||
|
}
|
||||||
elseif (empty($this->attrs['dataformat'])) // integer timestamp
|
elseif (empty($this->attrs['dataformat'])) // integer timestamp
|
||||||
{
|
{
|
||||||
$valid = (int)$value;
|
$valid = $date->format('ts');
|
||||||
}
|
}
|
||||||
// string with formatting letters like for php's date() method
|
// string with formatting letters like for php's date() method
|
||||||
elseif (($valid = date($this->attrs['dataformat'], $value)))
|
elseif (($valid = $date->format($this->attrs['dataformat'])))
|
||||||
{
|
{
|
||||||
// Nothing to do here
|
// Nothing to do here
|
||||||
}
|
}
|
||||||
@ -92,6 +141,7 @@ class etemplate_widget_date extends etemplate_widget_transformer
|
|||||||
// this is not really a user error, but one of the clientside engine
|
// this is not really a user error, but one of the clientside engine
|
||||||
self::set_validation_error($form_name,lang("'%1' is not a valid date !!!", $value).' '.$this->dataformat);
|
self::set_validation_error($form_name,lang("'%1' is not a valid date !!!", $value).' '.$this->dataformat);
|
||||||
}
|
}
|
||||||
|
//error_log("$this : ($valid)" . egw_time::to($valid));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,9 @@
|
|||||||
/**
|
/**
|
||||||
* Class which implements the "date" XET-Tag
|
* Class which implements the "date" XET-Tag
|
||||||
*
|
*
|
||||||
|
* Dates are passed to the server in ISO8601 format ("Y-m-d\TH:i:sP"), and data_format is
|
||||||
|
* handled server-side.
|
||||||
|
*
|
||||||
* @augments et2_inputWidget
|
* @augments et2_inputWidget
|
||||||
*/
|
*/
|
||||||
var et2_date = et2_inputWidget.extend(
|
var et2_date = et2_inputWidget.extend(
|
||||||
@ -35,7 +38,7 @@ var et2_date = et2_inputWidget.extend(
|
|||||||
"ignore": false
|
"ignore": false
|
||||||
},
|
},
|
||||||
"data_format": {
|
"data_format": {
|
||||||
"ignore": false,
|
"ignore": true,
|
||||||
"description": "Date/Time format. Can be set as an options to date widget",
|
"description": "Date/Time format. Can be set as an options to date widget",
|
||||||
"default": ''
|
"default": ''
|
||||||
}
|
}
|
||||||
@ -52,7 +55,7 @@ var et2_date = et2_inputWidget.extend(
|
|||||||
this._super.apply(this, arguments);
|
this._super.apply(this, arguments);
|
||||||
|
|
||||||
this.date = new Date();
|
this.date = new Date();
|
||||||
this.date.setHours(0);
|
this.date.setUTCHours(0);
|
||||||
this.date.setMinutes(0);
|
this.date.setMinutes(0);
|
||||||
this.date.setSeconds(0);
|
this.date.setSeconds(0);
|
||||||
this.input = null;
|
this.input = null;
|
||||||
@ -121,6 +124,11 @@ var et2_date = et2_inputWidget.extend(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for full timestamp
|
||||||
|
if(typeof _value == 'string' && _value.match(/(\d{4})-(\d{2})-(\d{2})T(\d{2})\:(\d{2})\:(\d{2})[+-](\d{2})\:(\d{2})/))
|
||||||
|
{
|
||||||
|
_value = new Date(_value);
|
||||||
|
}
|
||||||
// Handle just time as a string in the form H:i
|
// Handle just time as a string in the form H:i
|
||||||
if(typeof _value == 'string' && isNaN(_value))
|
if(typeof _value == 'string' && isNaN(_value))
|
||||||
{
|
{
|
||||||
@ -146,7 +154,8 @@ var et2_date = et2_inputWidget.extend(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.set_validation_error(false);
|
this.set_validation_error(false);
|
||||||
this.date.setHours(parsed.hour);
|
// Avoid javascript timezone offset, hour is in 'user time'
|
||||||
|
this.date.setUTCHours(parsed.hour);
|
||||||
this.date.setMinutes(parsed.minute);
|
this.date.setMinutes(parsed.minute);
|
||||||
this.input_date.val(_value);
|
this.input_date.val(_value);
|
||||||
if(old_value !== this.getValue())
|
if(old_value !== this.getValue())
|
||||||
@ -157,7 +166,7 @@ var et2_date = et2_inputWidget.extend(
|
|||||||
this.change(this.input_date);
|
this.change(this.input_date);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this._oldValue = _value;
|
this._oldValue = this.date.toJSON();
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
// Parse customfields's date with storage data_format to date object
|
// Parse customfields's date with storage data_format to date object
|
||||||
@ -173,7 +182,6 @@ var et2_date = et2_inputWidget.extend(
|
|||||||
var DTformat = this.options.data_format.split(' ');
|
var DTformat = this.options.data_format.split(' ');
|
||||||
var parsed = jQuery.datepicker.parseDateTime(this.egw().dateTimeFormat(DTformat[0]),this.egw().dateTimeFormat(DTformat[1]), _value);
|
var parsed = jQuery.datepicker.parseDateTime(this.egw().dateTimeFormat(DTformat[0]),this.egw().dateTimeFormat(DTformat[1]), _value);
|
||||||
}
|
}
|
||||||
this.date = new Date(parsed);
|
|
||||||
}
|
}
|
||||||
else // Parse other date widgets date with timepicker date/time format to date onject
|
else // Parse other date widgets date with timepicker date/time format to date onject
|
||||||
{
|
{
|
||||||
@ -184,9 +192,13 @@ var et2_date = et2_inputWidget.extend(
|
|||||||
this.set_validation_error(this.egw().lang("%1' han an invalid format !!!",_value));
|
this.set_validation_error(this.egw().lang("%1' han an invalid format !!!",_value));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.date = new Date(parsed);
|
|
||||||
}
|
}
|
||||||
|
// Update local variable, but remove the timezone offset that
|
||||||
|
// javascript adds when we parse
|
||||||
|
if(parsed)
|
||||||
|
{
|
||||||
|
this.date = new Date(parsed.valueOf() - parsed.getTimezoneOffset() * 60000);
|
||||||
|
}
|
||||||
|
|
||||||
this.set_validation_error(false);
|
this.set_validation_error(false);
|
||||||
}
|
}
|
||||||
@ -202,17 +214,21 @@ var et2_date = et2_inputWidget.extend(
|
|||||||
|
|
||||||
// Update input - popups do, but framework doesn't
|
// Update input - popups do, but framework doesn't
|
||||||
_value = '';
|
_value = '';
|
||||||
|
// Add timezone offset back in, or formatDate will lose those hours
|
||||||
|
var formatDate = new Date(this.date.valueOf() + this.date.getTimezoneOffset() * 60 * 1000);
|
||||||
if(this._type != 'date-timeonly')
|
if(this._type != 'date-timeonly')
|
||||||
{
|
{
|
||||||
_value = jQuery.datepicker.formatDate(this.input_date.datepicker("option","dateFormat"),this.date);
|
_value = jQuery.datepicker.formatDate(this.input_date.datepicker("option","dateFormat"),
|
||||||
|
formatDate
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if(this._type != 'date')
|
if(this._type != 'date')
|
||||||
{
|
{
|
||||||
if(this._type != 'date-timeonly') _value += ' ';
|
if(this._type != 'date-timeonly') _value += ' ';
|
||||||
|
|
||||||
_value += jQuery.datepicker.formatTime(this.input_date.datepicker("option","timeFormat"),{
|
_value += jQuery.datepicker.formatTime(this.input_date.datepicker("option","timeFormat"),{
|
||||||
hour: this.date.getHours(),
|
hour: formatDate.getHours(),
|
||||||
minute: this.date.getMinutes(),
|
minute: formatDate.getMinutes(),
|
||||||
seconds: 0,
|
seconds: 0,
|
||||||
timezone: 0
|
timezone: 0
|
||||||
});
|
});
|
||||||
@ -240,11 +256,13 @@ var et2_date = et2_inputWidget.extend(
|
|||||||
}
|
}
|
||||||
else if (this._type == 'date')
|
else if (this._type == 'date')
|
||||||
{
|
{
|
||||||
this.date.setHours(12);
|
this.date.setUTCHours(0);
|
||||||
|
this.date.setUTCMinutes(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to timestamp - no seconds
|
// Convert to timestamp - no seconds
|
||||||
this.date.setSeconds(0,0);
|
this.date.setSeconds(0,0);
|
||||||
return Math.round(this.date.valueOf() / 1000);
|
return this.date.toJSON();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
et2_register_widget(et2_date, ["date", "date-time", "date-timeonly"]);
|
et2_register_widget(et2_date, ["date", "date-time", "date-timeonly"]);
|
||||||
@ -643,6 +661,13 @@ var et2_date_ro = et2_valueWidget.extend([et2_IDetachedDOM],
|
|||||||
jQuery.datepicker.parseDateTime(this.egw().preference('dateformat'),this.egw().preference('timeformat') == '24' ? 'H:i' : 'g:i a', _value);
|
jQuery.datepicker.parseDateTime(this.egw().preference('dateformat'),this.egw().preference('timeformat') == '24' ? 'H:i' : 'g:i a', _value);
|
||||||
|
|
||||||
var text = new Date(parsed);
|
var text = new Date(parsed);
|
||||||
|
|
||||||
|
// Update local variable, but remove the timezone offset that javascript adds
|
||||||
|
if(parsed)
|
||||||
|
{
|
||||||
|
this.date = new Date(text.valueOf() - (text.getTimezoneOffset()*60*1000));
|
||||||
|
}
|
||||||
|
|
||||||
// JS dates use milliseconds
|
// JS dates use milliseconds
|
||||||
this.date.setTime(text.valueOf());
|
this.date.setTime(text.valueOf());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user