From: Piotr Kosko Date: Mon, 28 Sep 2015 11:34:18 +0000 (+0200) Subject: [Time] Time implementation changed X-Git-Tag: submit/tizen/20151026.073646^2^2~60^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a5e4e2439a76a7934c84180f9176de69525c0a0e;p=platform%2Fcore%2Fapi%2Fwebapi-plugins.git [Time] Time implementation changed [Feature] Implementation changed to be more clear and easier to maintain. [Verification] Code compiles without errors. TCT passrate: Time, Calendar, Alarm and Exif is 100%. Change-Id: Id222df420a0296b2763c1d828c02dc4f7f3e07ea Signed-off-by: Piotr Kosko --- diff --git a/src/time/time.gyp b/src/time/time.gyp index a7a2d263..cade13cf 100644 --- a/src/time/time.gyp +++ b/src/time/time.gyp @@ -20,6 +20,10 @@ 'time_extension.h', 'time_instance.cc', 'time_instance.h', + 'time_manager.cc', + 'time_manager.h', + 'time_utils.cc', + 'time_utils.h', ], 'conditions': [ [ 'tizen == 1', { diff --git a/src/time/time_api.js b/src/time/time_api.js index dc4f5e61..6fc9c791 100644 --- a/src/time/time_api.js +++ b/src/time/time_api.js @@ -1,821 +1,912 @@ -// Copyright (c) 2013 Intel Corporation. All rights reserved. -// Copyright (c) 2015 Samsung Electronics Co, Ltd. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -var _minuteInMilliseconds = 60 * 1000; -var _hourInMilliseconds = _minuteInMilliseconds * 60; +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ var utils_ = xwalk.utils; var validator_ = utils_.validator; var types_ = validator_.Types; var native_ = new utils_.NativeManager(extension); +var converter_ = utils_.converter; +var T = utils_.type; -exports.getCurrentDateTime = function() { - return new tizen.TZDate(); -}; - -exports.getLocalTimezone = function() { - var result = native_.callSync('Time_getLocalTimeZone'); - if (native_.isFailure(result)) { - throw native_.getErrorObject(result); - } - - return native_.getResultObject(result); -}; - -var _availableTimezonesCache = []; - -exports.getAvailableTimezones = function() { - if (_availableTimezonesCache.length) - return _availableTimezonesCache; - - var result = native_.callSync('Time_getAvailableTimeZones'); - if (native_.isFailure(result)) { - throw native_.getErrorObject(result); - } - - _availableTimezonesCache = native_.getResultObject(result); - return _availableTimezonesCache; -}; - -exports.getDateFormat = function() { - var args = validator_.validateArgs(arguments, [{ - name: 'shortformat', - type: types_.BOOLEAN, - optional: true, - nullable: true - }]); - - if (!args.has.shortformat) { - args.shortformat = false; - } - - var result = native_.callSync('Time_getDateFormat', {shortformat: args.shortformat}); - if (native_.isFailure(result)) { - throw native_.getErrorObject(result); - } - return native_.getResultObject(result); -}; - -exports.getTimeFormat = function() { - var result = native_.callSync('Time_getTimeFormat'); - if (native_.isFailure(result)) { - throw native_.getErrorObject(result); - } - - return native_.getResultObject(result); -}; - -exports.isLeapYear = function(year) { - if (year === undefined) - throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR); - - return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0); -}; - -var _timeUtilDateTimeChangeListener; +var _GMT_ID = 'GMT'; +var _LOCAL_ID = '__local__'; -function _timeUtilDateTimeChangeListenerCallback() { - native_.callIfPossible(_timeUtilDateTimeChangeListener); +function _createShiftedDate(tzDate) { + return new Date(tzDate._shiftedTimestamp); } -exports.setDateTimeChangeListener = function() { - var args = validator_.validateArgs(arguments, [ - { - name: 'changeCallback', - type: types_.FUNCTION - } - ]); - _timeUtilDateTimeChangeListener = args.changeCallback; - native_.addListener('DateTimeChangeListener', - _timeUtilDateTimeChangeListenerCallback); - var result = native_.callSync('Time_setDateTimeChangeListener', {}); - if (native_.isFailure(result)) { - throw native_.getErrorObject(result); - } -}; - -exports.unsetDateTimeChangeListener = function() { - native_.removeListener('DateTimeChangeListener', - _timeUtilDateTimeChangeListenerCallback); - var result = native_.callSync('Time_unsetDateTimeChangeListener', {}); - _timeUtilDateTimeChangeListener = undefined; - if (native_.isFailure(result)) { - throw native_.getErrorObject(result); - } -}; - -var _timeUtilTimezoneChangeListener; - -function _timeUtilTimezoneChangeListenerCallback() { - native_.callIfPossible(_timeUtilTimezoneChangeListener); +function _createUTCDate(tzDate) { + return new Date(tzDate._utcTimestamp); } -exports.setTimezoneChangeListener = function() { - var args = validator_.validateArgs(arguments, [ - { - name: 'changeCallback', - type: types_.FUNCTION - } - ]); - - _timeUtilTimezoneChangeListener = args.changeCallback; - native_.addListener('TimezoneChangeListener', - _timeUtilTimezoneChangeListenerCallback); - var result = native_.callSync('Time_setTimezoneChangeListener', {}); - if (native_.isFailure(result)) { - throw native_.getErrorObject(result); - } -}; - -exports.unsetTimezoneChangeListener = function() { - native_.removeListener('TimezoneChangeListener', - _timeUtilTimezoneChangeListenerCallback); - var result = native_.callSync('Time_unsetTimezoneChangeListener', {}); - _timeUtilTimezoneChangeListener = undefined; - if (native_.isFailure(result)) { - throw native_.getErrorObject(result); - } -}; - -function _throwProperTizenException(e) { - if (e instanceof TypeError) - throw new WebAPIException(WebAPIException.TYPE_MISMATCH_ERR); - else if (e instanceof RangeError) - throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR); - else - throw new WebAPIException(WebAPIException.UNKNOWN_ERR); +function _fill(date, tzDate) { + tzDate._shiftedTimestamp = date.getTime(); + tzDate._utcTimestamp = Number(tzDate._shiftedTimestamp) - Number(tzDate._timezoneOffset); } -var TimeDurationUnit = { - MSECS: 'MSECS', - SECS: 'SECS', - MINS: 'MINS', - HOURS: 'HOURS', - DAYS: 'DAYS' -}; - -tizen.TimeDuration = function(length, unit) { - validator_.isConstructorCall(this, tizen.TimeDuration); - - var length_ = length !== null ? Math.floor(length) : 0; - var unit_ = Object.keys(TimeDurationUnit).indexOf(unit) >= 0 ? unit : TimeDurationUnit.MSECS; +function _fillWithUTC(date, tzDate) { + tzDate._utcTimestamp = date.getTime(); + tzDate._shiftedTimestamp = Number(tzDate._utcTimestamp) + Number(tzDate._timezoneOffset); +} +function PrivateTZDate(timestamp, timezone, offset) { Object.defineProperties(this, { - length: { - get: function() { - return length_; - }, - set: function(v) { - if (v !== null) { - length_ = Math.floor(v); - } - }, - enumerable: true - }, - unit: { - get: function() { - return unit_; - }, - set: function(v) { - if (Object.keys(TimeDurationUnit).indexOf(v) >= 0) { - unit_ = v; - } - }, - enumerable: true - } + ts : {value: timestamp, writable: false, enumerable: false}, + tzId : {value: timezone, writable: false, enumerable: false}, + o : {value: offset, writable: false, enumerable: false} }); -}; - -function makeMillisecondsDurationObject(length) { - var dayInMsecs = _hourInMilliseconds * 24; - length = Math.floor(length); - - if ((length % dayInMsecs) === 0) - return new tizen.TimeDuration(length / dayInMsecs, TimeDurationUnit.DAYS); - - return new tizen.TimeDuration(length, TimeDurationUnit.MSECS); } -tizen.TimeDuration.prototype.getMilliseconds = function() { - var m; - switch (this.unit) { - case TimeDurationUnit.MSECS: - m = 1; - break; - case TimeDurationUnit.SECS: - m = 1000; - break; - case TimeDurationUnit.MINS: - m = 60 * 1000; - break; - case TimeDurationUnit.HOURS: - m = 3600 * 1000; - break; - case TimeDurationUnit.DAYS: - m = 86400 * 1000; - break; - } - return m * this.length; -}; - -tizen.TimeDuration.prototype.difference = function() { - var args = validator_.validateArgs(arguments, [{ - name: 'other', - type: types_.PLATFORM_OBJECT, - values: tizen.TimeDuration - }]); - - try { - return makeMillisecondsDurationObject(this.getMilliseconds() - - args.other.getMilliseconds()); - } catch (e) { - _throwProperTizenException(e); - } -}; - -tizen.TimeDuration.prototype.equalsTo = function() { - var args = validator_.validateArgs(arguments, [{ - name: 'other', - type: types_.PLATFORM_OBJECT, - values: tizen.TimeDuration - }]); - - try { - return this.getMilliseconds() === args.other.getMilliseconds(); - } catch (e) { - _throwProperTizenException(e); +function _getTimezoneOffset(timestamp, tzName) { + var callArgs = { + timezone : converter_.toString(tzName), + timestamp : converter_.toString(timestamp) + }; + var result = native_.callSync('TZDate_getTimezoneOffset', callArgs); + if (native_.isFailure(result)) { + throw native_.getErrorObject(result); } -}; - -tizen.TimeDuration.prototype.lessThan = function() { - var args = validator_.validateArgs(arguments, [{ - name: 'other', - type: types_.PLATFORM_OBJECT, - values: tizen.TimeDuration - }]); + var res = { + offset : converter_.toLong(native_.getResultObject(result).offset), + modifier : converter_.toLong(native_.getResultObject(result).modifier) + }; + return res; +} - try { - return this.getMilliseconds() < args.other.getMilliseconds(); - } catch (e) { - _throwProperTizenException(e); - } -}; +function _getLocalTimezoneOffset() { + return -1 * (new Date().getTimezoneOffset()) * 60 * 1000; // cast to milliseconds +} -tizen.TimeDuration.prototype.greaterThan = function() { - var args = validator_.validateArgs(arguments, [{ - name: 'other', - type: types_.PLATFORM_OBJECT, - values: tizen.TimeDuration - }]); +function _constructTZDate(obj, privateTZDate) { + var utcTimestamp = privateTZDate.ts; + var tzName = privateTZDate.tzId; + var offset = privateTZDate.o; - try { - return this.getMilliseconds() > args.other.getMilliseconds(); - } catch (e) { - _throwProperTizenException(e); - } -}; + switch (tzName) { + case _LOCAL_ID: + console.log('Entered _constructTZDate for local timezone'); -tizen.TimeDuration.prototype.toString = function() { - return this.length + ' ' + this.unit; -}; + tzName = tizen.time.getLocalTimezone(); -function getTimezoneOffset(_timezone, _timeInMs) { - var result = native_.callSync('Time_getTimeZoneOffset', { - timezone: _timezone, - value: _timeInMs - }); - if (native_.isFailure(result)) { - throw native_.getErrorObject(result); - } + if (T.isNullOrUndefined(offset)) { + offset = _getLocalTimezoneOffset(); + } + break; - return native_.getResultObject(result); -} + case _GMT_ID: + console.log('Entered _constructTZDate for GMT'); -function getMsUTC(date, timezone) { - var ms_utc = Date.UTC(date.getUTCFullYear(), - date.getUTCMonth(), - date.getUTCDate(), - date.getUTCHours(), - date.getUTCMinutes(), - date.getUTCSeconds(), - date.getUTCMilliseconds()); - if (arguments.length === 2) { - var result = native_.callSync('Time_getMsUTC', { - timezone: timezone, - value: ms_utc - }); - if (native_.isFailure(result)) { - throw native_.getErrorObject(result); + if (T.isNullOrUndefined(offset)) { + offset = 0; } + break; - ms_utc = native_.getResultObject(result); + default: + console.log('Entered _constructTZDate for: ' + tzName); + if (T.isNullOrUndefined(offset)) { + // throws if tzName is invalid + offset = _getTimezoneOffset(utcTimestamp, tzName).offset; + } + break; } - return ms_utc; + Object.defineProperties(obj, { + _utcTimestamp : {value: utcTimestamp, writable: true, enumerable: false}, + _shiftedTimestamp : {value: utcTimestamp + offset, writable: true, enumerable: false}, + _timezoneName : {value: tzName, writable: true, enumerable: false}, + _timezoneOffset : {value: offset, writable: true, enumerable: false} + }); } -tizen.TZDate = function(year, month, day, hours, minutes, seconds, milliseconds, timezone) { - validator_.isConstructorCall(this, tizen.TZDate); +//class TZDate //////////////////////////////////////////////////// +tizen.TZDate = function(p1, p2, day, hours, minutes, seconds, milliseconds, timezone) { + console.log("Entered tizen.TZDate"); + validator_.validateConstructorCall(this, tizen.TZDate); - if (timezone) { - if (tizen.time.getAvailableTimezones().indexOf(timezone) < 0) { - throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR); - } - - this.timezone_ = timezone; + var priv; + //copy constructor section (should be only for private usage) + if (p1 instanceof PrivateTZDate) { + priv = p1; } else { - this.timezone_ = tizen.time.getLocalTimezone(); - } + //Public constructor section + console.log('Entered TZDate constructor with: ' + arguments.length + ' attributes'); - var hours = hours || 0; - var minutes = minutes || 0; - var seconds = seconds || 0; - var milliseconds = milliseconds || 0; + var date; - if (!arguments.length) { - this.date_ = new Date(); - } else if (arguments.length === 1 || arguments.length === 2) { - if (arguments[0] instanceof Date) { - this.date_ = arguments[0]; + if (arguments.length < 3) { + if (T.isDate(p1)) { + date = p1; + } else { + date = new Date(); + } + timezone = p2; } else { - this.date_ = new Date(); + p1 = p1 ? p1 : 0; + p2 = p2 ? p2 : 0; + day = day ? day : 0; + hours = hours ? hours : 0; + minutes = minutes ? minutes : 0; + seconds = seconds ? seconds : 0; + milliseconds = milliseconds ? milliseconds : 0; + + date = new Date(p1, p2, day, hours, minutes, seconds, milliseconds); } - if (arguments[1]) { - if (tizen.time.getAvailableTimezones().indexOf(arguments[1]) < 0) { - throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR); + + var offset = _getLocalTimezoneOffset(); + var utcTimestamp = date.getTime(); + var tzName = _LOCAL_ID; + + if (!T.isNullOrUndefined(timezone)) { + timezone = converter_.toString(timezone); + var timezoneTimestamp = new Date(Date.UTC(date.getFullYear(), + date.getMonth(), + date.getDate(), + date.getHours(), + date.getMinutes(), + date.getSeconds(), + date.getMilliseconds())).getTime(); + try { + var offsetObject = _getTimezoneOffset(timezoneTimestamp, timezone); + offset = offsetObject.offset; + utcTimestamp = timezoneTimestamp - offset; + //correction of missing/extra hour on DST change + var modifier = offsetObject.modifier; + if (modifier > 0) { + //this is for case when 2AM becomes 3AM (but offset must be corrected - + //missing one hour) + offset += modifier; + } else { + //this is for case when extra hour appers - prevents error of + //unnecessary shift of hour when timezone changes + offset -= modifier; + utcTimestamp += modifier; + } + tzName = timezone; + } catch(e) { + // in case of exception we fall back to local time zone } - this.timezone_ = arguments[1]; - } - } else { - this.date_ = {}; - if (timezone) { - var d = new Date(); - d.setUTCFullYear(year); - d.setUTCMonth(month); - d.setUTCDate(day); - d.setUTCHours(hours); - d.setUTCMinutes(minutes); - d.setUTCSeconds(seconds); - d.setUTCMilliseconds(milliseconds); - this.date_ = new Date(getMsUTC(d, timezone)); - } else { - this.date_ = new Date(year, month, day, hours, minutes, seconds, milliseconds); } + + priv = new PrivateTZDate(utcTimestamp, tzName, offset); } + + _constructTZDate(this, priv); }; tizen.TZDate.prototype.getDate = function() { - var d = this.addDuration(new tizen.TimeDuration(getTimezoneOffset(this.timezone_, - getMsUTC(this.date_)))); - return d.date_.getUTCDate(); -}; + console.log('Entered TZDate.getDate'); + //getters realized with pattern + //---> use _shiftedTimestamp (_utcTimestamp (UTC) with added _timezoneOffset) + //---> create Date instance + //---> return d.getUTCDate() --- to avoid locale timezone impact of JS Date object + return _createShiftedDate(this).getUTCDate(); +}; + +function _updateTZDate(tzdate, args, param, func) { + var a = validator_.validateMethod(args, [ + { + name : param, + type : validator_.Types.LONG + } + ]); + + //setters realized with pattern + //---> use _shiftedTimestamp (_utcTimestamp (UTC) with added _timezoneOffset) + //---> create Date instance + //---> setUTCDate of JS Date object + //---> getTime of object to set _shiftedTimestmp (avoiding timezone of JS Date) + //---> fix _utcTimestamp with subtraction of _timezoneOffset + var date = _createShiftedDate(tzdate); + date[func](a[param]); + _fill(date, tzdate); +} -tizen.TZDate.prototype.setDate = function() { - var args = validator_.validateArgs(arguments, [{ - name: 'date', - type: types_.LONG - }]); +function _updateTZDateUTC(tzdate, args, param, func) { + var a = validator_.validateMethod(args, [ + { + name : param, + type : validator_.Types.LONG + } + ]); + var date = _createUTCDate(tzdate); + date[func](a[param]); + _fillWithUTC(date, tzdate); +} - this.date_.setDate(args.date); +tizen.TZDate.prototype.setDate = function() { + console.log('Entered TZDate.setDate'); + _updateTZDate(this, arguments, 'date', 'setUTCDate'); }; tizen.TZDate.prototype.getDay = function() { - return this.date_.getDay(); + console.log('Entered TZDate.getDay'); + return _createShiftedDate(this).getUTCDay(); }; tizen.TZDate.prototype.getFullYear = function() { - return this.date_.getFullYear(); + console.log('Entered TZDate.getFullYear'); + return _createShiftedDate(this).getUTCFullYear(); }; tizen.TZDate.prototype.setFullYear = function() { - var args = validator_.validateArgs(arguments, [{ - name: 'year', - type: types_.LONG - }]); - - this.date_.setFullYear(args.year); + console.log('Entered TZDate.setFullYear'); + _updateTZDate(this, arguments, 'year', 'setUTCFullYear'); }; tizen.TZDate.prototype.getHours = function() { - var d = this.addDuration(new tizen.TimeDuration(getTimezoneOffset(this.timezone_, - getMsUTC(this.date_)))); - return d.date_.getUTCHours(); + console.log('Entered TZDate.getHours'); + return _createShiftedDate(this).getUTCHours(); }; tizen.TZDate.prototype.setHours = function() { - var args = validator_.validateArgs(arguments, [{ - name: 'hours', - type: types_.LONG - }]); - - this.date_.setHours(args.hours); + console.log('Entered TZDate.setHours'); + _updateTZDate(this, arguments, 'hours', 'setUTCHours'); }; tizen.TZDate.prototype.getMilliseconds = function() { - return this.date_.getMilliseconds(); + console.log('Entered TZDate.getMilliseconds'); + return _createShiftedDate(this).getUTCMilliseconds(); }; tizen.TZDate.prototype.setMilliseconds = function() { - var args = validator_.validateArgs(arguments, [{ - name: 'ms', - type: types_.LONG - }]); - - this.date_.setMilliseconds(args.ms); + console.log('Entered TZDate.setMilliseconds'); + _updateTZDate(this, arguments, 'ms', 'setUTCMilliseconds'); }; -tizen.TZDate.prototype.getMonth = function() { - return this.date_.getMonth(); +tizen.TZDate.prototype.getMinutes = function() { + console.log('Entered TZDate.getMinutes'); + return _createShiftedDate(this).getUTCMinutes(); }; -tizen.TZDate.prototype.setMonth = function() { - var args = validator_.validateArgs(arguments, [{ - name: 'month', - type: types_.LONG - }]); - - this.date_.setMonth(args.month); +tizen.TZDate.prototype.setMinutes = function() { + console.log('Entered TZDate.setMinutes'); + _updateTZDate(this, arguments, 'minutes', 'setUTCMinutes'); }; -tizen.TZDate.prototype.getMinutes = function() { - return this.date_.getMinutes(); +tizen.TZDate.prototype.getMonth = function() { + console.log('Entered TZDate.getMonth'); + return _createShiftedDate(this).getUTCMonth(); }; -tizen.TZDate.prototype.setMinutes = function() { - var args = validator_.validateArgs(arguments, [{ - name: 'minutes', - type: types_.LONG - }]); - - this.date_.setMinutes(args.minutes); +tizen.TZDate.prototype.setMonth = function() { + console.log('Entered TZDate.setMonth'); + _updateTZDate(this, arguments, 'month', 'setUTCMonth'); }; tizen.TZDate.prototype.getSeconds = function() { - return this.date_.getSeconds(); + console.log('Entered TZDate.getSeconds'); + return _createShiftedDate(this).getUTCSeconds(); }; tizen.TZDate.prototype.setSeconds = function() { - var args = validator_.validateArgs(arguments, [{ - name: 'seconds', - type: types_.LONG - }]); - - this.date_.setSeconds(args.seconds); + console.log('Entered TZDate.setSeconds'); + _updateTZDate(this, arguments, 'seconds', 'setUTCSeconds'); }; tizen.TZDate.prototype.getUTCDate = function() { - return this.date_.getUTCDate(); + console.log('Entered TZDate.getUTCDate'); + return _createUTCDate(this).getUTCDate(); }; tizen.TZDate.prototype.setUTCDate = function() { - var args = validator_.validateArgs(arguments, [{ - name: 'date', - type: types_.LONG - }]); - - this.date_.setUTCDate(args.date); + console.log('Entered TZDate.setUTCDate'); + _updateTZDateUTC(this, arguments, 'date', 'setUTCDate'); }; tizen.TZDate.prototype.getUTCDay = function() { - var d = this.addDuration(new tizen.TimeDuration(getTimezoneOffset(this.timezone_, - getMsUTC(this.date_)) * -1)); - return d.getDay(); + console.log('Entered TZDate.getUTCDay'); + return _createUTCDate(this).getUTCDay(); }; tizen.TZDate.prototype.getUTCFullYear = function() { - var d = this.addDuration(new tizen.TimeDuration(getTimezoneOffset(this.timezone_, - getMsUTC(this.date_)) * -1)); - return d.getFullYear(); + console.log('Entered TZDate.getUTCFullYear'); + return _createUTCDate(this).getUTCFullYear(); }; tizen.TZDate.prototype.setUTCFullYear = function() { - var args = validator_.validateArgs(arguments, [{ - name: 'year', - type: types_.LONG - }]); - - this.date_.setUTCFullYear(args.year); + console.log('Entered TZDate.setUTCFullYear'); + _updateTZDateUTC(this, arguments, 'year', 'setUTCFullYear'); }; tizen.TZDate.prototype.getUTCHours = function() { - return this.date_.getUTCHours(); + console.log('Entered TZDate.getUTCHours'); + return _createUTCDate(this).getUTCHours(); }; tizen.TZDate.prototype.setUTCHours = function() { - var args = validator_.validateArgs(arguments, [{ - name: 'hours', - type: types_.LONG - }]); - - var offset_hours = getTimezoneOffset(this.timezone_, getMsUTC(this.date_)) / - _hourInMilliseconds; - this.date_.setHours(args.hours + offset_hours); + console.log('Entered TZDate.setUTCHours'); + _updateTZDateUTC(this, arguments, 'hours', 'setUTCHours'); }; tizen.TZDate.prototype.getUTCMilliseconds = function() { - var d = this.addDuration(new tizen.TimeDuration(getTimezoneOffset(this.timezone_, - getMsUTC(this.date_)) * -1)); - return d.getMilliseconds(); + console.log('Entered TZDate.getUTCMilliseconds'); + return _createUTCDate(this).getUTCMilliseconds(); }; tizen.TZDate.prototype.setUTCMilliseconds = function() { - var args = validator_.validateArgs(arguments, [{ - name: 'ms', - type: types_.LONG - }]); - - this.date_.setUTCMilliseconds(args.ms); + console.log('Entered TZDate.setUTCMilliseconds'); + _updateTZDateUTC(this, arguments, 'ms', 'setUTCMilliseconds'); }; tizen.TZDate.prototype.getUTCMinutes = function() { - var d = this.addDuration(new tizen.TimeDuration(getTimezoneOffset(this.timezone_, - getMsUTC(this.date_)) * -1)); - return d.getMinutes(); + console.log('Entered TZDate.getUTCMinutes'); + return _createUTCDate(this).getUTCMinutes(); }; tizen.TZDate.prototype.setUTCMinutes = function() { - var args = validator_.validateArgs(arguments, [{ - name: 'minutes', - type: types_.LONG - }]); - - this.date_.setUTCMinutes(args.minutes); + console.log('Entered TZDate.setUTCMinutes'); + _updateTZDateUTC(this, arguments, 'minutes', 'setUTCMinutes'); }; tizen.TZDate.prototype.getUTCMonth = function() { - var d = this.addDuration(new tizen.TimeDuration(getTimezoneOffset(this.timezone_, - getMsUTC(this.date_)) * -1)); - return d.getMonth(); + console.log('Entered TZDate.getUTCMonth'); + return _createUTCDate(this).getUTCMonth(); }; tizen.TZDate.prototype.setUTCMonth = function() { - var args = validator_.validateArgs(arguments, [{ - name: 'month', - type: types_.LONG - }]); - - this.date_.setUTCMonth(args.month); + console.log('Entered TZDate.setUTCMonth'); + _updateTZDateUTC(this, arguments, 'month', 'setUTCMonth'); }; tizen.TZDate.prototype.getUTCSeconds = function() { - var d = this.addDuration(new tizen.TimeDuration(getTimezoneOffset(this.timezone_, - getMsUTC(this.date_)) * -1)); - return d.getSeconds(); + console.log('Entered TZDate.getUTCSeconds'); + return _createUTCDate(this).getUTCSeconds(); }; tizen.TZDate.prototype.setUTCSeconds = function() { - var args = validator_.validateArgs(arguments, [{ - name: 'secs', - type: types_.LONG - }]); - - this.date_.setUTCSeconds(args.secs); -}; - -tizen.TZDate.prototype.getTime = function() { - return this.date_.getTime(); + console.log('Entered TZDate.setUTCSeconds'); + _updateTZDateUTC(this, arguments, 'seconds', 'setUTCSeconds'); }; tizen.TZDate.prototype.getTimezone = function() { - return this.timezone_; + console.log('Entered TZDate.getTimezone'); + return this._timezoneName; }; tizen.TZDate.prototype.toTimezone = function() { - var args = validator_.validateArgs(arguments, [{ - name: 'timezone', - type: types_.STRING - }]); - - if (!args.timezone) - throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR); - - return new tizen.TZDate(new Date(this.date_.getTime()), args.timezone); + console.log('Entered TZDate.toTimezone'); + var args = validator_.validateMethod(arguments, [ + { + name : 'timezone', + type : validator_.Types.STRING + } + ]); + return new tizen.TZDate(new PrivateTZDate(this._utcTimestamp, args.timezone)); }; tizen.TZDate.prototype.toLocalTimezone = function() { - return this.toTimezone(tizen.time.getLocalTimezone()); + console.log('Entered TZDate.toLocalTimezone'); + return new tizen.TZDate(new PrivateTZDate(this._utcTimestamp, _LOCAL_ID)); }; tizen.TZDate.prototype.toUTC = function() { - return this.toTimezone('GMT'); + console.log('Entered TZDate.toUTC'); + return new tizen.TZDate(new PrivateTZDate(this._utcTimestamp, _GMT_ID)); }; tizen.TZDate.prototype.difference = function() { - var args = validator_.validateArgs(arguments, [{ - name: 'other', - type: types_.PLATFORM_OBJECT, - values: tizen.TZDate - }]); - - try { - return makeMillisecondsDurationObject(this.getTime() - args.other.getTime()); - } catch (e) { - _throwProperTizenException(e); - } + console.log('Entered TZDate.difference'); + var args = validator_.validateMethod(arguments, [ + { + name : 'other', + type : validator_.Types.PLATFORM_OBJECT, + values : tizen.TZDate + } + ]); + var length = this._utcTimestamp - args.other._utcTimestamp; + var type = _timeDurationUnit.MSECS; + if (length % _timeDurationUnitValue.DAYS === 0) { + length /= _timeDurationUnitValue.DAYS; + type = _timeDurationUnit.DAYS; + } + return new tizen.TimeDuration(length, type); }; tizen.TZDate.prototype.equalsTo = function() { - var args = validator_.validateArgs(arguments, [{ - name: 'other', - type: types_.PLATFORM_OBJECT, - values: tizen.TZDate - }]); - - try { - return this.getTime() === args.other.getTime(); - } catch (e) { - _throwProperTizenException(e); - } + console.log('Entered TZDate.equalsTo'); + var args = validator_.validateMethod(arguments, [ + { + name : 'other', + type : validator_.Types.PLATFORM_OBJECT, + values : tizen.TZDate + } + ]); + return this._utcTimestamp === args.other._utcTimestamp; }; tizen.TZDate.prototype.earlierThan = function() { - var args = validator_.validateArgs(arguments, [{ - name: 'other', - type: types_.PLATFORM_OBJECT, - values: tizen.TZDate - }]); + console.log('Entered TZDate.earlierThan'); + var args = validator_.validateMethod(arguments, [ + { + name : 'other', + type : validator_.Types.PLATFORM_OBJECT, + values : tizen.TZDate + } + ]); + return this._utcTimestamp < args.other._utcTimestamp; +}; + +tizen.TZDate.prototype.laterThan = function() { + console.log('Entered TZDate.laterThan'); + var args = validator_.validateMethod(arguments, [ + { + name : 'other', + type : validator_.Types.PLATFORM_OBJECT, + values : tizen.TZDate + } + ]); + return this._utcTimestamp > args.other._utcTimestamp; +}; - try { - return this.getTime() < args.other.getTime(); - } catch (e) { - _throwProperTizenException(e); - } +tizen.TZDate.prototype.addDuration = function() { + console.log('Entered TZDate.addDuration'); + var args = validator_.validateMethod(arguments, [ + { + name : 'duration', + type : validator_.Types.PLATFORM_OBJECT, + values : tizen.TimeDuration + } + ]); + return new tizen.TZDate(new PrivateTZDate(this._utcTimestamp + + _getLengthInMsecsUnit(args.duration.length, args.duration.unit), + this._timezoneName)); }; -tizen.TZDate.prototype.laterThan = function(other) { - var args = validator_.validateArgs(arguments, [{ - name: 'other', - type: types_.PLATFORM_OBJECT, - values: tizen.TZDate - }]); +tizen.TZDate.prototype.toLocaleDateString = function() { + console.log('Entered TZDate.toLocaleDateString'); + var result = native_.callSync('TZDate_toLocaleDateString', + {timezone: String(this._timezoneName), + timestamp: String(this._utcTimestamp)}); + if (native_.isFailure(result)) { + throw native_.getErrorObject(result); + } + return native_.getResultObject(result).string; +}; - try { - return this.getTime() > args.other.getTime(); - } catch (e) { - _throwProperTizenException(e); +tizen.TZDate.prototype.toLocaleTimeString = function() { + console.log('Entered TZDate.toLocaleTimeString'); + var result = native_.callSync('TZDate_toLocaleTimeString', + {timezone: String(this._timezoneName), + timestamp: String(this._utcTimestamp)}); + if (native_.isFailure(result)) { + throw native_.getErrorObject(result); } + return native_.getResultObject(result).string; }; -tizen.TZDate.prototype.addDuration = function() { - var args = validator_.validateArgs(arguments, [{ - name: 'duration', - type: types_.PLATFORM_OBJECT, - values: tizen.TimeDuration - }]); +tizen.TZDate.prototype.toLocaleString = function() { + console.log('Entered TZDate.toLocaleString'); + var result = native_.callSync('TZDate_toLocaleString', + {timezone: String(this._timezoneName), + timestamp: String(this._utcTimestamp)}); + if (native_.isFailure(result)) { + throw native_.getErrorObject(result); + } + return native_.getResultObject(result).string; +}; - try { - var date = new tizen.TZDate(new Date(this.date_.getTime()), this.timezone_); - date.setMilliseconds(args.duration.getMilliseconds() + date.getMilliseconds()); - return date; - } catch (e) { - _throwProperTizenException(e); +tizen.TZDate.prototype.toDateString = function() { + console.log('Entered TZDate.toDateString'); + var result = native_.callSync('TZDate_toDateString', + {timezone: String(this._timezoneName), + timestamp: String(this._utcTimestamp)}); + if (native_.isFailure(result)) { + throw native_.getErrorObject(result); } + return native_.getResultObject(result).string; }; -tizen.TZDate.prototype.toLocaleDateString = function() { - var result = native_.callSync('Time_toDateString', { - timezone: this.timezone_, - value: this.date_.getTime(), - trans: '', - locale: true - }); +tizen.TZDate.prototype.toTimeString = function() { + console.log('Entered TZDate.toTimeString'); + var result = native_.callSync('TZDate_toTimeString', + {timezone: String(this._timezoneName), + timestamp: String(this._utcTimestamp)}); if (native_.isFailure(result)) { - return ''; + throw native_.getErrorObject(result); } + return native_.getResultObject(result).string; +}; - return native_.getResultObject(result); +tizen.TZDate.prototype.toString = function() { + console.log('Entered TZDate.toString'); + var result = native_.callSync('TZDate_toString', + {timezone: String(this._timezoneName), + timestamp: String(this._utcTimestamp)}); + if (native_.isFailure(result)) { + throw native_.getErrorObject(result); + } + return native_.getResultObject(result).string; }; -tizen.TZDate.prototype.toLocaleTimeString = function() { - var result = native_.callSync('Time_toTimeString', { - timezone: this.timezone_, - value: this.date_.getTime(), - trans: '', - locale: true - }); +tizen.TZDate.prototype.getTimezoneAbbreviation = function() { + console.log('Entered TZDate.getTimezoneAbbreviation'); + var result = native_.callSync('TZDate_getTimezoneAbbreviation', + {timezone: String(this._timezoneName), + timestamp: String(this._utcTimestamp)}); if (native_.isFailure(result)) { - return ''; + throw native_.getErrorObject(result); } + return native_.getResultObject(result).abbreviation; +}; - return native_.getResultObject(result); +tizen.TZDate.prototype.secondsFromUTC = function() { + console.log('Entered TZDate.secondsFromUTC'); + return -this._timezoneOffset/1000; }; -tizen.TZDate.prototype.toLocaleString = function() { - var result = native_.callSync('Time_toString', { - timezone: this.timezone_, - value: this.date_.getTime(), - trans: '', - locale: true - }); +tizen.TZDate.prototype.isDST = function() { + console.log('Entered TZDate.isDST'); + var result = native_.callSync('TZDate_isDST', + {timezone: String(this._timezoneName), + timestamp: String(this._utcTimestamp)}); if (native_.isFailure(result)) { - return ''; + throw native_.getErrorObject(result); } - - return native_.getResultObject(result); + return native_.getResultObject(result).isDST; }; -tizen.TZDate.prototype.toDateString = function() { - var result = native_.callSync('Time_toDateString', { - timezone: this.timezone_, - value: this.date_.getTime(), - trans: '', - locale: false - }); +tizen.TZDate.prototype.getPreviousDSTTransition = function() { + console.log('Entered TZDate.getPreviousDSTTransition'); + var result = native_.callSync('TZDate_getPreviousDSTTransition', + {timezone: String(this._timezoneName), + timestamp: String(this._utcTimestamp)}); if (native_.isFailure(result)) { - return ''; + throw native_.getErrorObject(result); } - return native_.getResultObject(result); + return new tizen.TZDate(new PrivateTZDate(native_.getResultObject(result).prevDSTDate, + this._timezoneName)); }; -tizen.TZDate.prototype.toTimeString = function() { - var result = native_.callSync('Time_toTimeString', { - timezone: this.timezone_, - value: this.date_.getTime(), - trans: '', - locale: false - }); +tizen.TZDate.prototype.getNextDSTTransition = function() { + console.log('Entered TZDate.getNextDSTTransition'); + var result = native_.callSync('TZDate_getNextDSTTransition', + {timezone: String(this._timezoneName), + timestamp: String(this._utcTimestamp)}); if (native_.isFailure(result)) { - return ''; + throw native_.getErrorObject(result); } - return native_.getResultObject(result); + return new tizen.TZDate(new PrivateTZDate(native_.getResultObject(result).nextDSTDate, + this._timezoneName)); }; -tizen.TZDate.prototype.toString = function() { - var result = native_.callSync('Time_toString', { - timezone: this.timezone_, - value: this.date_.getTime(), - trans: '', - locale: false +//TimeUtil helpers /////////////////////////////////////////////////// +var _timeDurationUnit = { + MSECS: 'MSECS', + SECS : 'SECS', + MINS : 'MINS', + HOURS: 'HOURS', + DAYS : 'DAYS' +}; + +var _timeDurationUnitValue = { + MSECS: Number(1), + SECS : Number(1000), + MINS : Number(60*1000), + HOURS: Number(60*60*1000), + DAYS : Number(24*60*60*1000) +}; + +function _getLengthInMsecsUnit(length, unit) { + if (unit === _timeDurationUnit.MSECS) { + return length; + } else if (unit === _timeDurationUnit.SECS) { + return length * _timeDurationUnitValue.SECS; + } else if (unit === _timeDurationUnit.MINS) { + return length * _timeDurationUnitValue.MINS; + } else if (unit === _timeDurationUnit.HOURS) { + return length * _timeDurationUnitValue.HOURS; + } else if (unit === _timeDurationUnit.DAYS) { + return length * _timeDurationUnitValue.DAYS; + } else { + native_.throwTypeMismatch(); + } +} + +function _convertMsecsToBiggestPossibleUnit(len) { + var length; + var unit; + if (len % _timeDurationUnitValue.DAYS === 0) { + length = len / _timeDurationUnitValue.DAYS; + unit = _timeDurationUnit.DAYS; + } else if (len % _timeDurationUnitValue.HOURS === 0) { + length = len / _timeDurationUnitValue.HOURS; + unit = _timeDurationUnit.HOURS; + } else if (len % _timeDurationUnitValue.MINS === 0) { + length = len / _timeDurationUnitValue.MINS; + unit = _timeDurationUnit.MINS; + } else if (len % _timeDurationUnitValue.SECS === 0) { + length = len / _timeDurationUnitValue.SECS; + unit = _timeDurationUnit.SECS; + } else { + length = len; + unit = _timeDurationUnit.MSECS; + } + return new tizen.TimeDuration(length, unit); +} + +//class tizen.TimeDuration //////////////////////////////////////////////////// +tizen.TimeDuration = function(length, unit) { + console.log('Entered TimeDuration constructor'); + validator_.validateConstructorCall(this, tizen.TimeDuration); + var l, u; + if (arguments.length >= 2) { + l = converter_.toLongLong(length); + unit = converter_.toString(unit); + if (T.hasProperty(_timeDurationUnit, unit)) { + u = unit; + } else { + u = _timeDurationUnit.MSECS; + } + } else if (arguments.length === 1) { + l = converter_.toLongLong(length); + u = _timeDurationUnit.MSECS; + } else { + l = undefined; + u = undefined; + } + function lengthSetter(val) { + if (!T.isNullOrUndefined(val)) { + l = val; + } + } + function unitSetter(val) { + if (!T.isNullOrUndefined(val)) { + u = val; + } + } + Object.defineProperties(this, { + length : { + enumerable : true, + set : lengthSetter, + get : function() { + return l; + } + }, + unit : { + enumerable : true, + set : unitSetter, + get : function() { + return u; + } + } }); - if (native_.isFailure(result)) { - return ''; +} + +tizen.TimeDuration.prototype.difference = function() { + console.log('Entered TimeDuration.difference'); + + var args = validator_.validateMethod(arguments, [ + { + name : 'other', + type : validator_.Types.PLATFORM_OBJECT, + values : tizen.TimeDuration + } + ]); + + if (this.unit === args.other.unit) { + return new tizen.TimeDuration(this.length - args.other.length, this.unit); + } else { + var l1 = _getLengthInMsecsUnit(this.length, this.unit); + var l2 = _getLengthInMsecsUnit(args.other.length, args.other.unit); + return _convertMsecsToBiggestPossibleUnit(l1 - l2); } +}; - return native_.getResultObject(result); +tizen.TimeDuration.prototype.equalsTo = function() { + console.log('Entered TimeDuration.equalsTo'); + + var args = validator_.validateMethod(arguments, [ + { + name : 'other', + type : validator_.Types.PLATFORM_OBJECT, + values : tizen.TimeDuration + } + ]); + + if (this.unit === args.other.unit) { + return (this.length === args.other.length) ? true : false; + } else { + var l1 = _getLengthInMsecsUnit(this.length, this.unit); + var l2 = _getLengthInMsecsUnit(args.other.length, args.other.unit); + return (l1 === l2) ? true : false; + } }; -tizen.TZDate.prototype.getTimezoneAbbreviation = function() { - var result = native_.callSync('Time_getTimeZoneAbbreviation', { - timezone: this.timezone_, - value: this.date_.getTime() - }); +tizen.TimeDuration.prototype.lessThan = function() { + console.log('Entered TimeDuration.lessThan'); + + var args = validator_.validateMethod(arguments, [ + { + name : 'other', + type : validator_.Types.PLATFORM_OBJECT, + values : tizen.TimeDuration + } + ]); + + if (this.unit === args.other.unit) { + return (this.length < args.other.length) ? true : false; + } else { + var l1 = _getLengthInMsecsUnit(this.length, this.unit); + var l2 = _getLengthInMsecsUnit(args.other.length, args.other.unit); + return (l1 < l2) ? true : false; + } +}; + +tizen.TimeDuration.prototype.greaterThan = function() { + console.log('Entered TimeDuration.greaterThan'); + + var args = validator_.validateMethod(arguments, [ + { + name : 'other', + type : validator_.Types.PLATFORM_OBJECT, + values : tizen.TimeDuration + } + ]); + + if (this.unit === args.other.unit) { + return (this.length > args.other.length) ? true : false; + } else { + var l1 = _getLengthInMsecsUnit(this.length, this.unit); + var l2 = _getLengthInMsecsUnit(args.other.length, args.other.unit); + return (l1 > l2) ? true : false; + } +}; + + +//class TimeUtil //////////////////////////////////////////////////// +exports.getCurrentDateTime = function() { + console.log('Entered TimeUtil.getCurrentDateTime'); + return new tizen.TZDate(); +}; + +exports.getLocalTimezone = function() { + console.log('Entered TimeUtil.getLocalTimezone'); + var result = native_.callSync('TZDate_getTimezone', {}); if (native_.isFailure(result)) { - return ''; + throw native_.getErrorObject(result); + } + return native_.getResultObject(result).timezoneId; +}; + +var _availableTimezones = []; //an array for holding available timezones + +exports.getAvailableTimezones = function() { + console.log('Entered TimeUtil.getAvailableTimezones'); + if (_availableTimezones.length === 0) { + var result = native_.callSync('TimeUtil_getAvailableTimezones', {}); + if (native_.isFailure(result)) { + throw native_.getErrorObject(result); + } + _availableTimezones = native_.getResultObject(result).availableTimezones; } - return native_.getResultObject(result); + return _availableTimezones.slice(0); }; -tizen.TZDate.prototype.secondsFromUTC = function() { - return this.date_.getTimezoneOffset() * 60; +exports.getDateFormat = function() { + console.log('Entered TimeUtil.getDateFormat'); + + var args = validator_.validateMethod(arguments, [ + { + name : 'shortformat', + type : validator_.Types.BOOLEAN, + optional : true, + nullable : true + } + ]); + + if (!args.has.shortformat || T.isNull(args.shortformat)) { + args.shortformat = false; + } + + var result = native_.callSync('TimeUtil_getDateFormat', {shortformat: args.shortformat}); + if (native_.isFailure(result)) { + throw native_.getErrorObject(result); + } + return native_.getResultObject(result).format; }; -tizen.TZDate.prototype.isDST = function() { - var result = native_.callSync('Time_isDST', { - timezone: this.timezone_, - value: getMsUTC(this.date_) - }); +exports.getTimeFormat = function() { + console.log('Entered TimeUtil.getTimeFormat'); + var result = native_.callSync('TimeUtil_getTimeFormat', {}); if (native_.isFailure(result)) { - return false; + throw native_.getErrorObject(result); } + return native_.getResultObject(result).format; +}; + +exports.isLeapYear = function() { + console.log('Entered TimeUtil.isLeapYear'); + + var args = validator_.validateMethod(arguments, [ + { + name : 'year', + type : validator_.Types.LONG + } + ]); - return native_.getResultObject(result); + // new Date(year, 1, 29).getMonth() === 1 <-- does not work for years 0-99 + return ((args.year % 4 === 0) && (args.year % 100 !== 0)) || (args.year % 400 === 0); }; -tizen.TZDate.prototype.getPreviousDSTTransition = function() { - var result = native_.callSync('Time_getDSTTransition', { - 'timezone': this.timezone_, - 'value': getMsUTC(this.date_), - 'trans': 'NEXT_TRANSITION' - }); + +var _timeUtilDateTimeChangeListener; +function _timeChangedListenerCallback(eventObj) { + console.log("_timeChangedListenerCallback"); + native_.callIfPossible(_timeUtilDateTimeChangeListener); +} + +exports.setDateTimeChangeListener = function() { + console.log('Entered TimeUtil.setDateTimeChangeListener'); + var args = validator_.validateMethod(arguments, [ + { + name : 'changeCallback', + type : validator_.Types.FUNCTION + } + ]); + var result = native_.callSync('TimeUtil_setDateTimeChangeListener', {}); if (native_.isFailure(result)) { - return null; + throw native_.getErrorObject(result); } - var _result = native_.getResultObject(result); - if (result.error || _result === 0) - return null; + _timeUtilDateTimeChangeListener = args.changeCallback; + native_.addListener("DateTimeChangeListener", _timeChangedListenerCallback); +}; - var utc_time = getMsUTC(new Date(_result), this.timezone_); - return new tizen.TZDate(new Date(utc_time)).toTimezone(this.timezone_); +exports.unsetDateTimeChangeListener = function() { + console.log('Entered TimeUtil.unsetDateTimeChangeListener'); + var result = native_.callSync('TimeUtil_unsetDateTimeChangeListener', {}); + if (native_.isFailure(result)) { + throw native_.getErrorObject(result); + } + native_.removeListener('DateTimeChangeListener'); + _timeUtilDateTimeChangeListener = undefined; }; -tizen.TZDate.prototype.getNextDSTTransition = function() { - var result = native_.callSync('Time_getDSTTransition', { - timezone: this.timezone_, - value: getMsUTC(this.date_), - trans: 'PREV_TRANSITION' - }); +var _timeUtilTimezoneChangeListener; +function _timezoneListenerCallback(eventObj) { + console.log("_timezoneListenerCallback"); + native_.callIfPossible(_timeUtilTimezoneChangeListener); +} + +exports.setTimezoneChangeListener = function() { + console.log('Entered TimeUtil.setTimezoneChangeListener'); + var args = validator_.validateMethod(arguments, [ + { + name : 'changeCallback', + type : validator_.Types.FUNCTION + } + ]); + var result = native_.callSync('TimeUtil_setTimezoneChangeListener', {}); if (native_.isFailure(result)) { - return null; + throw native_.getErrorObject(result); } - var _result = native_.getResultObject(result); - if (result.error || _result === 0) - return null; + _timeUtilTimezoneChangeListener = args.changeCallback; + native_.addListener('TimezoneChangeListener', + _timezoneListenerCallback); - var utc_time = getMsUTC(new Date(_result), this.timezone_); - return new tizen.TZDate(new Date(utc_time)).toTimezone(this.timezone_); }; + +exports.unsetTimezoneChangeListener = function() { + console.log('Entered TimeUtil.unsetTimezoneChangeListener'); + native_.removeListener('TimezoneChangeListener'); + var result = native_.callSync('TimeUtil_unsetTimezoneChangeListener', {}); + _timeUtilTimezoneChangeListener = undefined; + if (native_.isFailure(result)) { + throw native_.getErrorObject(result); + } +}; \ No newline at end of file diff --git a/src/time/time_instance.cc b/src/time/time_instance.cc index 7e78cba4..2f0ce937 100644 --- a/src/time/time_instance.cc +++ b/src/time/time_instance.cc @@ -4,746 +4,352 @@ // found in the LICENSE file. #include "time/time_instance.h" -#include "common/platform_exception.h" #include "common/logger.h" - -#if defined(TIZEN) -#include -#endif - -#include -#include -#include -#include - #include "common/picojson.h" #include "common/platform_result.h" -#include "unicode/timezone.h" -#include "unicode/calendar.h" -#include "unicode/vtzone.h" -#include "unicode/tztrans.h" -#include "unicode/smpdtfmt.h" -#include "unicode/dtptngen.h" - namespace extension { namespace time { using namespace common; -enum ListenerType { - kTimeChange, - kTimezoneChange -}; - -namespace { - -const int _hourInMilliseconds = 3600000; -const char kTimezoneListenerId[] = "TimezoneChangeListener"; -const char kDateTimeListenerId[] = "DateTimeChangeListener"; - -} // namespace - -TimeInstance::TimeInstance() { +TimeInstance::TimeInstance() : manager_(this) { using std::placeholders::_1; using std::placeholders::_2; LoggerD("Entered"); #define REGISTER_SYNC(c, x) \ - RegisterSyncHandler(c, std::bind(&TimeInstance::x, this, _1, _2)); + RegisterSyncHandler(c, std::bind(&TimeInstance::x, this, _1, _2)); #define REGISTER_ASYNC(c, x) \ - RegisterSyncHandler(c, std::bind(&TimeInstance::x, this, _1, _2)); - - REGISTER_SYNC("Time_getAvailableTimeZones", TimeGetAvailableTimeZones); - REGISTER_SYNC("Time_getDSTTransition", TimeGetDSTTransition); - REGISTER_SYNC("Time_getLocalTimeZone", TimeGetLocalTimeZone); - REGISTER_SYNC("Time_getTimeFormat", TimeGetTimeFormat); - REGISTER_SYNC("Time_getDateFormat", TimeGetDateFormat); - REGISTER_SYNC("Time_getTimeZoneOffset", TimeGetTimeZoneOffset); - REGISTER_SYNC("Time_getTimeZoneAbbreviation", TimeGetTimeZoneAbbreviation); - REGISTER_SYNC("Time_isDST", TimeIsDST); - REGISTER_SYNC("Time_toString", TimeToString); - REGISTER_SYNC("Time_toDateString", TimeToDateString); - REGISTER_SYNC("Time_toTimeString", TimeToTimeString); - REGISTER_SYNC("Time_setDateTimeChangeListener", - TimeSetDateTimeChangeListener); - REGISTER_SYNC("Time_unsetDateTimeChangeListener", - TimeUnsetDateTimeChangeListener); - REGISTER_SYNC("Time_setTimezoneChangeListener", - TimeSetTimezoneChangeListener); - REGISTER_SYNC("Time_unsetTimezoneChangeListener", - TimeUnsetTimezoneChangeListener); - REGISTER_SYNC("Time_getMsUTC", TimeGetMsUTC); + RegisterSyncHandler(c, std::bind(&TimeInstance::x, this, _1, _2)); + + REGISTER_SYNC("TimeUtil_getAvailableTimezones", TimeUtil_getAvailableTimezones); + REGISTER_SYNC("TimeUtil_getDateFormat", TimeUtil_getDateFormat); + REGISTER_SYNC("TimeUtil_getTimeFormat", TimeUtil_getTimeFormat); + REGISTER_SYNC("TimeUtil_setDateTimeChangeListener", TimeUtil_setDateTimeChangeListener); + REGISTER_SYNC("TimeUtil_unsetDateTimeChangeListener", TimeUtil_unsetDateTimeChangeListener); + REGISTER_SYNC("TimeUtil_setTimezoneChangeListener", TimeUtil_setTimezoneChangeListener); + REGISTER_SYNC("TimeUtil_unsetTimezoneChangeListener", TimeUtil_unsetTimezoneChangeListener); + REGISTER_SYNC("TZDate_getTimezone", TZDate_getTimezone); + REGISTER_SYNC("TZDate_getTimezoneOffset", TZDate_GetTimezoneOffset); + REGISTER_SYNC("TZDate_toLocaleDateString", TZDate_toLocaleDateString); + REGISTER_SYNC("TZDate_toLocaleTimeString", TZDate_toLocaleTimeString); + REGISTER_SYNC("TZDate_toLocaleString", TZDate_toLocaleString); + REGISTER_SYNC("TZDate_toDateString", TZDate_toDateString); + REGISTER_SYNC("TZDate_toTimeString", TZDate_toTimeString); + REGISTER_SYNC("TZDate_toString", TZDate_toString); + REGISTER_SYNC("TZDate_getTimezoneAbbreviation", TZDate_getTimezoneAbbreviation); + REGISTER_SYNC("TZDate_isDST", TZDate_isDST); + REGISTER_SYNC("TZDate_getPreviousDSTTransition", TZDate_getPreviousDSTTransition); + REGISTER_SYNC("TZDate_getNextDSTTransition", TZDate_getNextDSTTransition); #undef REGISTER_SYNC #undef REGISTER_ASYNC } -static void OnTimeChangedCallback(keynode_t* /*node*/, void* user_data); -static std::string GetDefaultTimezone(); - TimeInstance::~TimeInstance() { - LoggerD("Entered"); -} - -void TimeInstance::TimeGetLocalTimeZone(const JsonValue& /*args*/, - JsonObject& out) { - LoggerD("Entered"); - - UnicodeString local_timezone; - TimeZone* timezone = TimeZone::createDefault(); - if (nullptr != timezone) { - timezone->getID(local_timezone); - delete timezone; - - std::string localtz; - local_timezone.toUTF8String(localtz); - - ReportSuccess(JsonValue(localtz), out); - } else { - ReportError(out); - } -} - -void TimeInstance::TimeGetAvailableTimeZones(const JsonValue& /*args*/, - JsonObject& out) { LoggerD("Entered"); - - UErrorCode ec = U_ZERO_ERROR; - std::unique_ptr timezones(TimeZone::createEnumeration()); - int32_t count = timezones->count(ec); - if (U_FAILURE(ec)) { - LoggerE("Failed to get timezones."); - ReportError(out); - return; - } - - JsonArray a; - const char* timezone = NULL; - int i = 0; - do { - int32_t resultLen = 0; - timezone = timezones->next(&resultLen, ec); - if (U_SUCCESS(ec)) { - a.push_back(JsonValue(timezone)); - i++; - } - } while (timezone && i < count); - - ReportSuccess(JsonValue(a), out); } -void TimeInstance::TimeGetTimeZoneOffset(const JsonValue& args, - JsonObject& out) { +void TimeInstance::TimeUtil_getAvailableTimezones(const picojson::value& /*args*/, + picojson::object& out) { LoggerD("Entered"); - - std::unique_ptr id( - new UnicodeString(args.get("timezone").to_str().c_str())); - UDate dateInMs = strtod(args.get("value").to_str().c_str(), NULL); - - if (errno == ERANGE) { - LoggerE("Value out of range"); - ReportError(out); - return; - } - - UErrorCode ec = U_ZERO_ERROR; - std::unique_ptr timezone(TimeZone::createTimeZone(*id)); - - int32_t rawOffset = 0; - int32_t dstOffset = 0; - timezone->getOffset(dateInMs, false, rawOffset, dstOffset, ec); - if (U_FAILURE(ec)) { - LoggerE("Failed to get timezone offset"); - ReportError(out); + picojson::value result = picojson::value(picojson::object()); + picojson::object& result_obj = result.get(); + + auto array = result_obj.insert(std::make_pair("availableTimezones", + picojson::value(picojson::array()))); + PlatformResult res = TimeUtilTools::GetAvailableTimezones( + &array.first->second.get()); + if (res.IsError()) { + ReportError(res, &out); return; } - std::stringstream offsetStr; - offsetStr << (rawOffset + dstOffset); - ReportSuccess(JsonValue(offsetStr.str()), out); + ReportSuccess(result, out); } -void TimeInstance::TimeGetTimeZoneAbbreviation(const JsonValue& args, - JsonObject& out) { +void TimeInstance::TimeUtil_getDateFormat(const picojson::value& args, picojson::object& out) { LoggerD("Entered"); - - std::unique_ptr id( - new UnicodeString(args.get("timezone").to_str().c_str())); - UDate dateInMs = strtod(args.get("value").to_str().c_str(), NULL); - - if (errno == ERANGE) { - LoggerE("Value out of range"); - ReportError(out); + if (!args.contains("shortformat")) { + LoggerE("Invalid parameter passed."); + ReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."), &out); return; } - UErrorCode ec = U_ZERO_ERROR; - std::unique_ptr timezone(TimeZone::createTimeZone(*id)); - std::unique_ptr cal(Calendar::createInstance(*timezone, ec)); - if (U_FAILURE(ec)) { - LoggerE("Failed to create Calendar instance"); - ReportError(out); + bool shortformat = args.get("shortformat").get(); + std::string format; + PlatformResult res = TimeUtilTools::GetDateFormat(shortformat, &format); + if (res.IsError()) { + ReportError(res, &out); return; } - cal->setTime(dateInMs, ec); - if (U_FAILURE(ec)) { - LoggerE("Failed to set date"); - ReportError(out); - return; - } - - std::unique_ptr fmt( - new SimpleDateFormat(UnicodeString("z"), Locale::getEnglish(), ec)); - if (U_FAILURE(ec)) { - LoggerE("Failed to create format object"); - ReportError(out); - return; - } + picojson::value result = picojson::value(picojson::object()); + picojson::object& result_obj = result.get(); + result_obj.insert(std::make_pair("format", picojson::value(format))); - UnicodeString uAbbreviation; - fmt->setCalendar(*cal); - fmt->format(cal->getTime(ec), uAbbreviation); - if (U_FAILURE(ec)) { - LoggerE("Failed to format object"); - ReportError(out); - return; - } - - std::string abbreviation = ""; - uAbbreviation.toUTF8String(abbreviation); - - ReportSuccess(JsonValue(abbreviation), out); + ReportSuccess(result, out); } -void TimeInstance::TimeIsDST(const JsonValue& args, JsonObject& out) { +void TimeInstance::TimeUtil_getTimeFormat(const picojson::value& /* args */, + picojson::object& out) { LoggerD("Entered"); - - std::unique_ptr id( - new UnicodeString(args.get("timezone").to_str().c_str())); - UDate dateInMs = strtod(args.get("value").to_str().c_str(), NULL); - - if (errno == ERANGE) { - LoggerE("Value out of range"); - ReportError(out); + std::string format; + PlatformResult res = TimeUtilTools::GetTimeFormat(&format); + if (res.IsError()) { + ReportError(res, &out); return; } - UErrorCode ec = U_ZERO_ERROR; - std::unique_ptr timezone(TimeZone::createTimeZone(*id)); + picojson::value result = picojson::value(picojson::object()); + picojson::object& result_obj = result.get(); + result_obj.insert(std::make_pair("format", picojson::value(format))); - int32_t rawOffset = 0; - int32_t dstOffset = 0; - timezone->getOffset(dateInMs, false, rawOffset, dstOffset, ec); - if (U_FAILURE(ec)) { - LoggerE("Failed to get timezone offset"); - ReportError(out); - return; - } - ReportSuccess(JsonValue{static_cast(dstOffset)}, out); + ReportSuccess(result, out); } -void TimeInstance::TimeGetDSTTransition(const JsonValue& args, - JsonObject& out) { +void TimeInstance::TimeUtil_setDateTimeChangeListener(const picojson::value& /*args*/, + picojson::object& out) { LoggerD("Entered"); - - std::unique_ptr id( - new UnicodeString(args.get("timezone").to_str().c_str())); - std::string trans = args.get("trans").to_str(); - UDate dateInMs = strtod(args.get("value").to_str().c_str(), NULL); - - if (errno == ERANGE) { - LoggerE("Value out of range"); - ReportError(out); - return; - } - - std::unique_ptr vtimezone(VTimeZone::createVTimeZoneByID(*id)); - - if (!vtimezone->useDaylightTime()) { - LoggerE("Failed to set DST"); - ReportError(out); - return; - } - - TimeZoneTransition tzTransition; - if (trans.compare("NEXT_TRANSITION") && - vtimezone->getNextTransition(dateInMs, FALSE, tzTransition)) { - ReportSuccess(JsonValue{tzTransition.getTime()}, out); - } else if (vtimezone->getPreviousTransition(dateInMs, FALSE, tzTransition)) { - ReportSuccess(JsonValue{tzTransition.getTime()}, out); - } else { - LoggerE("Error while getting transition"); - ReportError(out); + PlatformResult res = manager_.RegisterVconfCallback(kTimeChange); + if (res.IsError()) { + ReportError(res, &out); } + ReportSuccess(out); } -void TimeInstance::TimeToString(const JsonValue& args, JsonObject& out) { - JsonValue val; +void TimeInstance::TimeUtil_unsetDateTimeChangeListener(const picojson::value& /*args*/, + picojson::object& out) { LoggerD("Entered"); - - if (!this->toStringByFormat(args, val, TimeInstance::DATETIME_FORMAT)) { - LoggerE("Failed to convert to string"); - ReportError(out); - return; + PlatformResult res = manager_.UnregisterVconfCallback(kTimeChange); + if (res.IsError()) { + ReportError(res, &out); } - - ReportSuccess(val, out); + ReportSuccess(out); } -void TimeInstance::TimeToDateString(const JsonValue& args, JsonObject& out) { - JsonValue val; +void TimeInstance::TimeUtil_setTimezoneChangeListener(const picojson::value& /*args*/, + picojson::object& out) { LoggerD("Entered"); - - if (!this->toStringByFormat(args, val, TimeInstance::DATE_FORMAT)) { - LoggerE("Failed to convert to string"); - ReportError(out); - return; + PlatformResult res = manager_.RegisterVconfCallback(kTimezoneChange); + if (res.IsError()) { + ReportError(res, &out); } - - ReportSuccess(val, out); + ReportSuccess(out); } -void TimeInstance::TimeToTimeString(const JsonValue& args, JsonObject& out) { - JsonValue val; +void TimeInstance::TimeUtil_unsetTimezoneChangeListener(const picojson::value& /*args*/, + picojson::object& out) { LoggerD("Entered"); - - if (!this->toStringByFormat(args, val, TimeInstance::TIME_FORMAT)) { - LoggerE("Failed to convert to string"); - ReportError(out); - return; + PlatformResult res = manager_.UnregisterVconfCallback(kTimezoneChange); + if (res.IsError()) { + ReportError(res, &out); } - - ReportSuccess(val, out); + ReportSuccess(out); } -bool TimeInstance::toStringByFormat(const JsonValue& args, JsonValue& out, - DateTimeFormatType format) { +void TimeInstance::TZDate_getTimezone(const picojson::value& /*args*/, picojson::object& out) { LoggerD("Entered"); - std::unique_ptr id( - new UnicodeString(args.get("timezone").to_str().c_str())); - bool bLocale = args.get("locale").evaluate_as_boolean(); + std::string local_timezone = TimeManager::GetDefaultTimezone(); - UDate dateInMs = strtod(args.get("value").to_str().c_str(), NULL); - if (errno == ERANGE) { - LoggerE("Value out of range"); - return false; - } - - UErrorCode ec = U_ZERO_ERROR; - std::unique_ptr timezone(TimeZone::createTimeZone(*id)); - std::unique_ptr cal(Calendar::createInstance(*timezone, ec)); - if (U_FAILURE(ec)) { - LoggerE("Failed to create Calendar instance"); - return false; - } - - cal->setTime(dateInMs, ec); - if (U_FAILURE(ec)) { - LoggerE("Failed to set time"); - return false; - } - - std::unique_ptr fmt(new SimpleDateFormat( - getDateTimeFormat(format, bLocale), - (bLocale ? Locale::getDefault() : Locale::getEnglish()), ec)); - if (U_FAILURE(ec)) { - LoggerE("Failed to create format object"); - return false; - } + picojson::value result = picojson::value(picojson::object()); + picojson::object& result_obj = result.get(); + result_obj.insert(std::make_pair("timezoneId", picojson::value(local_timezone))); - UnicodeString uResult; - fmt->setCalendar(*cal); - fmt->format(cal->getTime(ec), uResult); - if (U_FAILURE(ec)) { - LoggerE("Failed to format object"); - return false; - } - - std::string result = ""; - uResult.toUTF8String(result); - - out = JsonValue(result); - return true; -} - -void TimeInstance::TimeGetTimeFormat(const JsonValue& /*args*/, - JsonObject& out) { - LoggerD("Entered"); - - UnicodeString timeFormat = getDateTimeFormat(TimeInstance::TIME_FORMAT, true); - - timeFormat = timeFormat.findAndReplace("H", "h"); - timeFormat = timeFormat.findAndReplace("a", "ap"); - - timeFormat = timeFormat.findAndReplace("hh", "h"); - timeFormat = timeFormat.findAndReplace("mm", "m"); - timeFormat = timeFormat.findAndReplace("ss", "s"); - - std::string result = ""; - timeFormat.toUTF8String(result); - - ReportSuccess(JsonValue(result), out); + ReportSuccess(result, out); } -void TimeInstance::TimeGetDateFormat(const JsonValue& args, JsonObject& out) { +void TimeInstance::TZDate_GetTimezoneOffset(const picojson::value& args, + picojson::object& out) { LoggerD("Entered"); - - bool shortformat = args.get("shortformat").evaluate_as_boolean(); - UnicodeString time_format = - getDateTimeFormat((shortformat ? DateTimeFormatType::DATE_SHORT_FORMAT - : DateTimeFormatType::DATE_FORMAT), - true); - - time_format = time_format.findAndReplace("E", "D"); - - if (time_format.indexOf("MMM") > 0) { - if (time_format.indexOf("MMMM") > 0) { - time_format = time_format.findAndReplace("MMMM", "M"); - } else { - time_format = time_format.findAndReplace("MMM", "M"); - } - } else { - time_format = time_format.findAndReplace("M", "m"); + if (!args.contains("timezone") || !args.contains("timestamp")) { + LoggerE("Invalid parameter passed."); + ReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."), &out); + return; } - - int i = 0; - while (i < time_format.length() - 1) { - if (time_format[i] == time_format[i + 1]) { - time_format.remove(i, 1); - } else { - ++i; - } + const std::string& timezone_id = args.get("timezone").get(); + LoggerD("Getting timezone details for id: %s ", timezone_id.c_str()); + + const std::string& timestamp_str = args.get("timestamp").get(); + + std::string offset; + std::string modifier; + PlatformResult res = manager_.GetTimezoneOffset(timezone_id, timestamp_str, + &offset, &modifier); + if (res.IsSuccess()) { + picojson::value result = picojson::value(picojson::object()); + picojson::object& result_obj = result.get(); + result_obj.insert(std::make_pair("offset", picojson::value(offset))); + //this value is to correct 'missing' hour also in JS + result_obj.insert(std::make_pair("modifier", picojson::value(modifier))); + ReportSuccess(result, out); + } else { + ReportError(res, &out); } - - std::string result = ""; - time_format.toUTF8String(result); - ReportSuccess(JsonValue(result), out); } -Locale* TimeInstance::getDefaultLocale() { - char *tempstr = vconf_get_str(VCONFKEY_REGIONFORMAT); - if (NULL == tempstr){ - return NULL; - } - - Locale *defaultLocale = NULL; - - char *str_region = NULL; - char* p = strchr(tempstr, '.'); - int len = strlen(tempstr) - (p != nullptr ? strlen(p) : 0); - if (len > 0) { - str_region = strndup(tempstr, len); //.UTF8 => 5 - defaultLocale = new Locale(str_region); - } - - free(tempstr); - free(str_region); - - if (defaultLocale) { - if (defaultLocale->isBogus()) { - delete defaultLocale; - defaultLocale = NULL; - } - } - - return defaultLocale; -} - -UnicodeString TimeInstance::getDateTimeFormat(DateTimeFormatType type, - bool bLocale) { +void TimeInstance::ToStringTemplate(const picojson::value& args, + bool use_locale_fmt, + TimeUtilTools::DateTimeFormatType type, + picojson::object* out) { LoggerD("Entered"); - LoggerD("bLocale %d", bLocale); - - UErrorCode ec = U_ZERO_ERROR; - Locale *defaultLocale = getDefaultLocale(); - std::unique_ptr dateTimepattern( - DateTimePatternGenerator::createInstance( - ((bLocale && defaultLocale) ? *defaultLocale : Locale::getEnglish()), ec)); + if (!args.contains("timezone") || !args.contains("timestamp")) { + LoggerE("Invalid parameter passed."); + ReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."), out); + return; + } + const std::string& timezone_id = args.get("timezone").get(); + std::shared_ptr unicode_id (new UnicodeString(timezone_id.c_str())); + LoggerD("Getting timezone details for id: %s ", timezone_id.c_str()); - delete defaultLocale; + const std::string& timestamp_str = args.get("timestamp").get(); + UDate date = std::stod(timestamp_str); - if (U_FAILURE(ec)) { - LoggerE("Failed to create Calendar instance"); - return ""; + std::string result_string; + PlatformResult res = TimeUtilTools::ToStringHelper(date, unicode_id, use_locale_fmt, + type, &result_string); + if (res.IsError()) { + ReportError(res, out); + return; } - UnicodeString pattern; - if (type == DATE_FORMAT) { - pattern = dateTimepattern->getBestPattern(UDAT_YEAR_MONTH_WEEKDAY_DAY, ec); - } else if (type == DATE_SHORT_FORMAT) { - pattern = dateTimepattern->getBestPattern(UDAT_YEAR_NUM_MONTH_DAY, ec); - } else { - std::string skeleton; - if (type != TIME_FORMAT) skeleton = UDAT_YEAR_MONTH_WEEKDAY_DAY; - -#if defined(TIZEN) - int ret = 0; - int value = 0; - ret = vconf_get_int(VCONFKEY_REGIONFORMAT_TIME1224, &value); - // if failed, set default time format - if (-1 == ret) { - value = VCONFKEY_TIME_FORMAT_12; - } - if (VCONFKEY_TIME_FORMAT_12 == value) { - skeleton += "hhmmss"; - } else { - skeleton += "HHmmss"; - } -#else - skeleton += "hhmmss"; -#endif - - pattern = dateTimepattern->getBestPattern( - UnicodeString(skeleton.c_str()), ec); - if (U_FAILURE(ec)) { - LoggerE("Failed to get time pattern"); - return ""; - } - - if (!bLocale) pattern += " 'GMT'Z v'"; - } + picojson::value result = picojson::value(picojson::object()); + picojson::object& result_obj = result.get(); + result_obj.insert( + std::make_pair("string", picojson::value(result_string))); - return pattern; + ReportSuccess(result, *out); } -/////////////////////////// TimeUtilListeners //////////////////////////////// - -class TimeUtilListeners { - public: - TimeUtilListeners(); - ~TimeUtilListeners(); - - PlatformResult RegisterVconfCallback(ListenerType type, TimeInstance& instance); - PlatformResult UnregisterVconfCallback(ListenerType type); - - std::string GetCurrentTimezone(); - void SetCurrentTimezone(std::string& newTimezone); - - private: - std::string current_timezone_; - bool is_time_listener_registered_; - bool is_timezone_listener_registered_; -}; - -TimeUtilListeners::TimeUtilListeners() - : current_timezone_(GetDefaultTimezone()), - is_time_listener_registered_(false), - is_timezone_listener_registered_(false) { +void TimeInstance::TZDate_toLocaleDateString(const picojson::value& args, picojson::object& out) { LoggerD("Entered"); + ToStringTemplate(args, true, TimeUtilTools::DateTimeFormatType::kDateFormat, &out); } -TimeUtilListeners::~TimeUtilListeners() { +void TimeInstance::TZDate_toLocaleTimeString(const picojson::value& args, picojson::object& out) { LoggerD("Entered"); - if (is_time_listener_registered_ || is_timezone_listener_registered_) { - if (0 != vconf_ignore_key_changed(VCONFKEY_SYSTEM_TIME_CHANGED, - OnTimeChangedCallback)) { - LoggerE("Failed to unregister vconf callback"); - } - } + ToStringTemplate(args, true, TimeUtilTools::DateTimeFormatType::kTimeFormat, &out); } -PlatformResult TimeUtilListeners::RegisterVconfCallback(ListenerType type, TimeInstance& instance) { +void TimeInstance::TZDate_toLocaleString(const picojson::value& args, picojson::object& out) { LoggerD("Entered"); - - if (!is_time_listener_registered_ && !is_timezone_listener_registered_) { - LoggerD("registering listener on platform"); - if (0 != vconf_notify_key_changed(VCONFKEY_SYSTEM_TIME_CHANGED, - OnTimeChangedCallback, static_cast(&instance))) { - LoggerE("Failed to register vconf callback"); - return PlatformResult(ErrorCode::UNKNOWN_ERR, - "Failed to register vconf callback"); - } - } else { - LoggerD("not registering listener on platform - already registered"); - } - switch (type) { - case kTimeChange: - is_time_listener_registered_ = true; - LoggerD("time change listener registered"); - break; - case kTimezoneChange: - is_timezone_listener_registered_ = true; - LoggerD("time zone change listener registered"); - break; - default: - LoggerE("Unknown type of listener"); - return PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown type of listener"); - } - return PlatformResult(ErrorCode::NO_ERROR); + ToStringTemplate(args, true, TimeUtilTools::DateTimeFormatType::kDateTimeFormat, &out); } -PlatformResult TimeUtilListeners::UnregisterVconfCallback(ListenerType type) { +void TimeInstance::TZDate_toDateString(const picojson::value& args, picojson::object& out) { LoggerD("Entered"); - - switch (type) { - case kTimeChange: - is_time_listener_registered_ = false; - LoggerD("time change listener unregistered"); - break; - case kTimezoneChange: - is_timezone_listener_registered_ = false; - LoggerD("time zone change listener unregistered"); - break; - default: - return PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown type of listener"); - } - if (!is_time_listener_registered_ && !is_timezone_listener_registered_) { - LoggerD("unregistering listener on platform"); - if (0 != vconf_ignore_key_changed(VCONFKEY_SYSTEM_TIME_CHANGED, - OnTimeChangedCallback)) { - LoggerE("Failed to unregister vconf callback"); - } - } - return PlatformResult(ErrorCode::NO_ERROR); + ToStringTemplate(args, false, TimeUtilTools::DateTimeFormatType::kDateFormat, &out); } -std::string TimeUtilListeners::GetCurrentTimezone() { - return current_timezone_; -} - -void TimeUtilListeners::SetCurrentTimezone(std::string& newTimezone) { - current_timezone_ = newTimezone; -} - -static std::string GetDefaultTimezone() { +void TimeInstance::TZDate_toTimeString(const picojson::value& args, picojson::object& out) { LoggerD("Entered"); - - char buf[1024]; - std::string result; - ssize_t len = readlink("/opt/etc/localtime", buf, sizeof(buf) - 1); - if (len != -1) { - buf[len] = '\0'; - } else { - /* handle error condition */ - LoggerE("Error while reading link - incorrect length"); - return result; - } - result = std::string(buf + strlen("/usr/share/zoneinfo/")); - - LoggerD("tzpath = %s", result.c_str()); - return result; + ToStringTemplate(args, false, TimeUtilTools::DateTimeFormatType::kTimeFormat, &out); } -/////////////////////////// TimeUtilListeners object //////////////////////// -static TimeUtilListeners g_time_util_listeners_obj; - -static void PostMessage(const char* message, TimeInstance& instance) { +void TimeInstance::TZDate_toString(const picojson::value& args, picojson::object& out) { LoggerD("Entered"); - - JsonValue result{JsonObject{}}; - JsonObject& result_obj = result.get(); - result_obj.insert(std::make_pair("listenerId", picojson::value(message))); - Instance::PostMessage(&instance, result.serialize().c_str()); + ToStringTemplate(args, false, TimeUtilTools::DateTimeFormatType::kDateTimeFormat, &out); } -static void OnTimeChangedCallback(keynode_t* /*node*/, void* user_data) { +void TimeInstance::TZDate_getTimezoneAbbreviation(const picojson::value& args, + picojson::object& out) { LoggerD("Entered"); - - TimeInstance *that = static_cast(user_data); - if (!that) { - LoggerE("instance is NULL"); + if (!args.contains("timezone") || !args.contains("timestamp")) { + LoggerE("Invalid parameter passed."); + ReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."), &out); return; } + const std::string& timezone_id = args.get("timezone").get(); + std::shared_ptr unicode_id (new UnicodeString(timezone_id.c_str())); - std::string defaultTimezone = GetDefaultTimezone(); + const std::string& timestamp_str = args.get("timestamp").get(); + UDate date = std::stod(timestamp_str); - if (g_time_util_listeners_obj.GetCurrentTimezone() != defaultTimezone) { - g_time_util_listeners_obj.SetCurrentTimezone(defaultTimezone); - PostMessage(kTimezoneListenerId, *that); + std::string result_string; + PlatformResult res = TimeUtilTools::GetTimezoneAbbreviation(date, unicode_id, &result_string); + if (res.IsError()) { + ReportError(res, &out); + return; } - PostMessage(kDateTimeListenerId, *that); -} -void TimeInstance::TimeSetDateTimeChangeListener(const JsonValue& /*args*/, - JsonObject& out) { - LoggerD("Entered"); + picojson::value result = picojson::value(picojson::object()); + picojson::object& result_obj = result.get(); + result_obj.insert(std::make_pair("abbreviation", picojson::value(result_string))); - PlatformResult result = - g_time_util_listeners_obj.RegisterVconfCallback(kTimeChange, *this); - if (result.IsError()) { - LoggerE("Error while registering vconf callback"); - ReportError(result, &out); - } - else - ReportSuccess(out); + ReportSuccess(result, out); } -void TimeInstance::TimeUnsetDateTimeChangeListener(const JsonValue& /*args*/, - JsonObject& out) { +void TimeInstance::TZDate_isDST(const picojson::value& args, picojson::object& out) { LoggerD("Entered"); - - PlatformResult result = - g_time_util_listeners_obj.UnregisterVconfCallback(kTimeChange); - if (result.IsError()) { - LoggerE("Failed to unregister vconf callback"); - ReportError(result, &out); + if (!args.contains("timezone") || !args.contains("timestamp")) { + LoggerE("Invalid parameter passed."); + ReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."), &out); + return; } - else - ReportSuccess(out); -} + const std::string& timezone_id = args.get("timezone").get(); + std::shared_ptr unicode_id (new UnicodeString(timezone_id.c_str())); -void TimeInstance::TimeSetTimezoneChangeListener(const JsonValue& /*args*/, - JsonObject& out) { - LoggerD("Entered"); + const std::string& timestamp_str = args.get("timestamp").get(); + UDate date = std::stod(timestamp_str); - PlatformResult result = - g_time_util_listeners_obj.RegisterVconfCallback(kTimezoneChange, *this); - if (result.IsError()) { - LoggerE("Failed to register vconf callback"); - ReportError(result, &out); + bool is_dst = false; + PlatformResult res = TimeUtilTools::IsDST(date, unicode_id, &is_dst); + if (res.IsError()) { + ReportError(res, &out); + return; } - else - ReportSuccess(out); + picojson::value result = picojson::value(picojson::object()); + picojson::object& result_obj = result.get(); + result_obj.insert( + std::make_pair("isDST", picojson::value(is_dst))); + ReportSuccess(result, out); } -void TimeInstance::TimeUnsetTimezoneChangeListener(const JsonValue& /*args*/, - JsonObject& out) { +void TimeInstance::TZDate_getPreviousDSTTransition(const picojson::value& args, + picojson::object& out) { LoggerD("Entered"); - - PlatformResult result = - g_time_util_listeners_obj.UnregisterVconfCallback(kTimezoneChange); - if (result.IsError()) { - LoggerE("Failed to unregister vconf callback"); - ReportError(result, &out); + if (!args.contains("timezone") || !args.contains("timestamp")) { + LoggerE("Invalid parameter passed."); + ReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."), &out); + return; } - else - ReportSuccess(out); -} + const std::string& timezone_id = args.get("timezone").get(); + std::shared_ptr unicode_id (new UnicodeString(timezone_id.c_str())); -void TimeInstance::TimeGetMsUTC(const JsonValue& args, JsonObject& out) { - LoggerD("Entered"); + const std::string& timestamp_str = args.get("timestamp").get(); + UDate date = std::stod(timestamp_str); - std::unique_ptr id(new UnicodeString(args.get("timezone").to_str().c_str())); - if (id == NULL) { - LoggerE("Allocation error"); - ReportError(out); - return; - } - UDate dateInMs = strtod(args.get("value").to_str().c_str(), NULL); - if (errno == ERANGE) { - LoggerE("Value out of range"); - ReportError(out); - return; - } + picojson::value result = picojson::value(picojson::object()); + picojson::object& result_obj = result.get(); + UDate prev_dst = TimeUtilTools::GetDSTTransition(date, unicode_id, + TimeUtilTools::DSTTransition::kPreviousDST); + result_obj.insert(std::make_pair("prevDSTDate", picojson::value(prev_dst))); - UErrorCode ec = U_ZERO_ERROR; - std::unique_ptr timezone(TimeZone::createTimeZone(*id)); + ReportSuccess(result, out); +} - int32_t rawOffset = 0; - int32_t dstOffset = 0; - timezone->getOffset(dateInMs, true, rawOffset, dstOffset, ec); - if (U_FAILURE(ec)) { - LoggerE("Failed to get timezone offset"); - ReportError(out); +void TimeInstance::TZDate_getNextDSTTransition(const picojson::value& args, picojson::object& out) { + LoggerD("Entered"); + if (!args.contains("timezone") || !args.contains("timestamp")) { + LoggerE("Invalid parameter passed."); + ReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."), &out); return; } + const std::string& timezone_id = args.get("timezone").get(); + std::shared_ptr unicode_id (new UnicodeString(timezone_id.c_str())); + + const std::string& timestamp_str = args.get("timestamp").get(); + UDate date = std::stod(timestamp_str); - dateInMs -= (rawOffset + dstOffset); + picojson::value result = picojson::value(picojson::object()); + picojson::object& result_obj = result.get(); + UDate next_dst = TimeUtilTools::GetDSTTransition(date, unicode_id, + TimeUtilTools::DSTTransition::kNextDST); + result_obj.insert(std::make_pair("nextDSTDate", picojson::value(next_dst))); - ReportSuccess(JsonValue{static_cast(dateInMs)}, out); + ReportSuccess(result, out); } } // namespace time diff --git a/src/time/time_instance.h b/src/time/time_instance.h index 3c5ffa9b..6666a211 100644 --- a/src/time/time_instance.h +++ b/src/time/time_instance.h @@ -9,51 +9,43 @@ #include "common/extension.h" #include "common/picojson.h" #include "unicode/unistr.h" +#include "time/time_manager.h" +#include "time/time_utils.h" #include namespace extension { namespace time { -typedef picojson::value JsonValue; -typedef picojson::object JsonObject; -typedef picojson::array JsonArray; -typedef std::string JsonString; - class TimeInstance : public common::ParsedInstance { public: TimeInstance(); virtual ~TimeInstance(); private: - enum DateTimeFormatType { - TIME_FORMAT, - DATE_FORMAT, - DATE_SHORT_FORMAT, - DATETIME_FORMAT - }; - - void TimeGetAvailableTimeZones(const JsonValue& args, JsonObject& out); - void TimeGetDSTTransition(const JsonValue& args, JsonObject& out); - void TimeGetLocalTimeZone(const JsonValue& args, JsonObject& out); - void TimeGetTimeFormat(const JsonValue& args, JsonObject& out); - void TimeGetDateFormat(const JsonValue& args, JsonObject& out); - void TimeGetTimeZoneOffset(const JsonValue& args, JsonObject& out); - void TimeGetTimeZoneAbbreviation(const JsonValue& args, JsonObject& out); - void TimeIsDST(const JsonValue& args, JsonObject& out); - void TimeToString(const JsonValue& args, JsonObject& out); - void TimeToDateString(const JsonValue& args, JsonObject& out); - void TimeToTimeString(const JsonValue& args, JsonObject& out); - void TimeSetDateTimeChangeListener(const JsonValue& args, JsonObject& out); - void TimeUnsetDateTimeChangeListener(const JsonValue& args, JsonObject& out); - void TimeSetTimezoneChangeListener(const JsonValue& args, JsonObject& out); - void TimeUnsetTimezoneChangeListener(const JsonValue& args, JsonObject& out); - void TimeGetMsUTC(const JsonValue& args, JsonObject& out); - - Locale* getDefaultLocale(); - UnicodeString getDateTimeFormat(DateTimeFormatType type, bool bLocale); - bool toStringByFormat(const JsonValue& args, JsonValue& out, - DateTimeFormatType format); + void TimeUtil_getAvailableTimezones(const picojson::value& args, picojson::object& out); + void TimeUtil_getDateFormat(const picojson::value& args, picojson::object& out); + void TimeUtil_getTimeFormat(const picojson::value& args, picojson::object& out); + void TimeUtil_setDateTimeChangeListener(const picojson::value& args, picojson::object& out); + void TimeUtil_unsetDateTimeChangeListener(const picojson::value& args, picojson::object& out); + void TimeUtil_setTimezoneChangeListener(const picojson::value& args, picojson::object& out); + void TimeUtil_unsetTimezoneChangeListener(const picojson::value& args, picojson::object& out); + void TZDate_getTimezone(const picojson::value& args, picojson::object& out); + void TZDate_GetTimezoneOffset(const picojson::value& args, picojson::object& out); + void ToStringTemplate(const picojson::value& args, bool use_locale_fmt, + TimeUtilTools::DateTimeFormatType type, picojson::object* out); + void TZDate_toLocaleDateString(const picojson::value& args, picojson::object& out); + void TZDate_toLocaleTimeString(const picojson::value& args, picojson::object& out); + void TZDate_toLocaleString(const picojson::value& args, picojson::object& out); + void TZDate_toDateString(const picojson::value& args, picojson::object& out); + void TZDate_toTimeString(const picojson::value& args, picojson::object& out); + void TZDate_toString(const picojson::value& args, picojson::object& out); + void TZDate_getTimezoneAbbreviation(const picojson::value& args, picojson::object& out); + void TZDate_isDST(const picojson::value& args, picojson::object& out); + void TZDate_getPreviousDSTTransition(const picojson::value& args, picojson::object& out); + void TZDate_getNextDSTTransition(const picojson::value& args, picojson::object& out); + + TimeManager manager_; }; } // namespace time } // namespace extension diff --git a/src/time/time_manager.cc b/src/time/time_manager.cc new file mode 100644 index 00000000..898954a5 --- /dev/null +++ b/src/time/time_manager.cc @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "time/time_manager.h" + +#include +#include +#include + +#include "common/logger.h" +#include "time/time_instance.h" + +using common::PlatformResult; +using common::ErrorCode; +using common::Instance; + +namespace extension { +namespace time { + +TimeManager::TimeManager(TimeInstance* instance) + : instance_(instance), + current_timezone_(GetDefaultTimezone()), + is_time_listener_registered_(false), + is_timezone_listener_registered_(false) { + LoggerD("Entered"); +} + +TimeManager::~TimeManager() { + LoggerD("Entered"); + if (is_time_listener_registered_) { + UnregisterVconfCallback(kTimeChange); + } + if (is_timezone_listener_registered_) { + UnregisterVconfCallback(kTimezoneChange); + } +} + +PlatformResult TimeManager::GetTimezoneOffset(const std::string& timezone_id, + const std::string& timestamp_str, + std::string* offset, + std::string* modifier) { + LoggerD("Entered"); + std::unique_ptr unicode_id (new UnicodeString(timezone_id.c_str())); + std::unique_ptr tz (TimeZone::createTimeZone(*unicode_id)); + + if (TimeZone::getUnknown() == *tz) { + return PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."); + } + + const int32_t oneHour = 3600000; + UDate date = std::stod(timestamp_str); + int32_t stdOffset = 0; + int32_t dstOffset = 0; + UErrorCode ec = U_ZERO_ERROR; + //offset is get for target LOCAL date timestamp, but it should be UTC timestamp, + //so it has to be checked below against DST edge condition + tz->getOffset(date, false, stdOffset, dstOffset, ec); + LOGD("stdOffset: %d, dstOffset: %d", stdOffset, dstOffset); + + //this section checks if date is not in DST transition point + //check if date shifted to UTC timestamp is still with the same offset + int32_t dstOffsetBefore = 0; + tz->getOffset(date - stdOffset - dstOffset, false, stdOffset, dstOffsetBefore, ec); + LOGD("stdOffset: %d, dstOffsetBefore: %d", stdOffset, dstOffsetBefore); + + //it has to be checked if it is 'missing' hour case + int32_t dstOffsetAfterBefore = 0; + tz->getOffset(date - stdOffset - dstOffset + oneHour, + false, stdOffset, dstOffsetAfterBefore, ec); + LOGD("stdOffset: %d, dstOffsetAfterBefore: %d", stdOffset, dstOffsetAfterBefore); + + //offset would be minimum of local and utc timestamp offsets + //(to work correctly even if DST transtion is 'now') + dstOffset = std::min(dstOffset, dstOffsetBefore); + + *offset = std::to_string(stdOffset + dstOffset); + *modifier = std::to_string(dstOffsetAfterBefore - dstOffsetBefore); + return PlatformResult(ErrorCode::NO_ERROR); +} + +PlatformResult TimeManager::RegisterVconfCallback(ListenerType type) { + LoggerD("Entered"); + if (!is_time_listener_registered_ && !is_timezone_listener_registered_){ + LOGD("registering listener on platform"); + if (0 != vconf_notify_key_changed( + VCONFKEY_SYSTEM_TIME_CHANGED, OnTimeChangedCallback, this)) { + LOGE("Failed to register vconf callback"); + return PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to register vconf callback"); + } + } else { + LOGD("not registering listener on platform - already registered"); + } + switch (type) { + case kTimeChange : + is_time_listener_registered_ = true; + LOGD("time change listener registered"); + break; + case kTimezoneChange : + is_timezone_listener_registered_ = true; + LOGD("time zone change listener registered"); + break; + default : + LOGE("Unknown type of listener"); + return PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown type of listener"); + } + return PlatformResult(ErrorCode::NO_ERROR); +} + +PlatformResult TimeManager::UnregisterVconfCallback(ListenerType type) { + LoggerD("Entered"); + switch (type) { + case kTimeChange : + is_time_listener_registered_ = false; + LOGD("time change listener unregistered"); + break; + case kTimezoneChange : + is_timezone_listener_registered_ = false; + LOGD("time zone change listener unregistered"); + break; + default : + return PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown type of listener"); + } + if (!is_time_listener_registered_ && !is_timezone_listener_registered_) { + LOGD("unregistering listener on platform"); + if (0 != vconf_ignore_key_changed(VCONFKEY_SYSTEM_TIME_CHANGED, OnTimeChangedCallback)) { + LOGE("Failed to unregister vconf callback"); + // silent fail + //return PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to unregister vconf callback"); + } + } + return PlatformResult(ErrorCode::NO_ERROR); +} + +void TimeManager::OnTimeChangedCallback(keynode_t* /*node*/, void* event_ptr) { + LoggerD("Entered"); + TimeManager* manager = static_cast(event_ptr); + TimeInstance* instance = manager->GetTimeInstance(); + std::string defaultTimezone = GetDefaultTimezone(); + + if (manager->GetCurrentTimezone() != defaultTimezone) { + manager->SetCurrentTimezone(defaultTimezone); + //call timezone callback + + const std::shared_ptr& response = + std::shared_ptr(new picojson::value(picojson::object())); + response->get()["listenerId"] = picojson::value("TimezoneChangeListener"); + // ReportSuccess(result,response->get()); + Instance::PostMessage(instance, response->serialize().c_str()); + } + //call date time callback + const std::shared_ptr& response = + std::shared_ptr(new picojson::value(picojson::object())); + response->get()["listenerId"] = picojson::value("DateTimeChangeListener"); + // ReportSuccess(result,response->get()); + Instance::PostMessage(instance, response->serialize().c_str()); +} + +std::string TimeManager::GetDefaultTimezone() { + LoggerD("Entered"); + char buf[1024]; + std::string result; + ssize_t len = readlink("/opt/etc/localtime", buf, sizeof(buf)-1); + if (len != -1) { + buf[len] = '\0'; + } else { + /* handle error condition */ + return result; + } + result = std::string(buf+strlen("/usr/share/zoneinfo/")); + + LoggerD("tzpath = %s", result.c_str()); + return result; +} + +std::string TimeManager::GetCurrentTimezone(){ + LoggerD("Entered"); + return current_timezone_; +} + +void TimeManager::SetCurrentTimezone(const std::string& new_timezone){ + LoggerD("Entered"); + current_timezone_ = new_timezone; +} + +TimeInstance* TimeManager::GetTimeInstance() { + LoggerD("Entered"); + return instance_; +} + +} // time +} // extension diff --git a/src/time/time_manager.h b/src/time/time_manager.h new file mode 100644 index 00000000..02f95e9e --- /dev/null +++ b/src/time/time_manager.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TIME_TIME_MANAGER_H_ +#define TIME_TIME_MANAGER_H_ + +#include +#include +#include "common/picojson.h" +#include "common/platform_result.h" + +namespace extension { +namespace time { + +enum ListenerType { + kTimeChange, + kTimezoneChange +}; + +class TimeInstance; + +class TimeManager +{ + public: + TimeManager(TimeInstance* instance); + ~TimeManager(); + + common::PlatformResult GetTimezoneOffset(const std::string& timezone_id, + const std::string& timestamp_str, + std::string* offset, + std::string* modifier); + common::PlatformResult RegisterVconfCallback(ListenerType type); + common::PlatformResult UnregisterVconfCallback(ListenerType type); + static void OnTimeChangedCallback(keynode_t* node, void* event_ptr); + std::string GetCurrentTimezone(); + void SetCurrentTimezone(const std::string& new_timezone); + TimeInstance* GetTimeInstance(); + static std::string GetDefaultTimezone(); + private: + TimeInstance* instance_; + std::string current_timezone_; + bool is_time_listener_registered_; + bool is_timezone_listener_registered_; +}; + +} +} + +#endif // TIME_TIME_MANAGER_H_ diff --git a/src/time/time_utils.cc b/src/time/time_utils.cc new file mode 100644 index 00000000..0afbc86e --- /dev/null +++ b/src/time/time_utils.cc @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "time_utils.h" + +#include +#include +#include +#include + +#include + +#include "common/logger.h" + +using common::PlatformResult; +using common::ErrorCode; + +namespace extension { +namespace time { + +UDate TimeUtilTools::GetDSTTransition(UDate timestamp, + const std::shared_ptr& timezone_id, + DSTTransition tr_type) { + LoggerD("Entered"); + UBool result = false; + UDate dst_transition_date = timestamp; + std::unique_ptr vtz(VTimeZone::createVTimeZoneByID(*timezone_id)); + + TimeZoneTransition tz_trans; + if (vtz->useDaylightTime()) { + switch (tr_type) { + case DSTTransition::kNextDST: + result = vtz->getNextTransition(dst_transition_date, FALSE, tz_trans); + break; + + case DSTTransition::kPreviousDST: + result = vtz->getPreviousTransition(dst_transition_date, FALSE, tz_trans); + break; + } + + if (result) { + dst_transition_date = tz_trans.getTime(); + } + } + return dst_transition_date; +} + +PlatformResult TimeUtilTools::IsDST(UDate timestamp, + const std::shared_ptr& timezone_id, + bool* result_bool) { + LoggerD("Entered"); + UErrorCode ec = U_ZERO_ERROR; + std::unique_ptr tz (TimeZone::createTimeZone(*timezone_id)); + std::unique_ptr calendar (Calendar::createInstance(*tz, ec)); + + if (U_FAILURE(ec)){ + LoggerE("Failed to create calendar instance: %d", ec); + return PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to create calendar instance"); + } + calendar->setTime(timestamp, ec); + if (U_FAILURE(ec)){ + LoggerE("Failed to set calendar date: %d", ec); + return PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to set calendar date"); + } + bool result = static_cast(calendar->inDaylightTime(ec)); + if (U_FAILURE(ec)){ + LoggerE("Failed to get day light boolean: %d", ec); + return PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to get day light boolean"); + } + *result_bool = result; + return PlatformResult(ErrorCode::NO_ERROR); +} + +PlatformResult TimeUtilTools::GetTimezoneAbbreviation(UDate date, + const std::shared_ptr& timezone_id, + std::string* result_string) { + LoggerD("Entered"); + UErrorCode ec = U_ZERO_ERROR; + UnicodeString str; + + std::unique_ptr fmt(new SimpleDateFormat(UnicodeString("z"), + Locale::getEnglish(), ec)); + if (U_SUCCESS(ec)) { + std::unique_ptr tz(TimeZone::createTimeZone(*timezone_id)); + fmt->setTimeZone(*tz); + fmt->format(date, str); + + if ((str.length() > 3) && (str.compare(0, 3, "GMT") == 0)) { + str.remove(); + std::unique_ptr gmt(new SimpleDateFormat(UnicodeString("OOOO"), + Locale::getEnglish(), ec)); + gmt->setTimeZone(*tz); + gmt->format(date, str); + } + + return TimeUtilTools::ToUTF8String(str, result_string); + } + LOGE("can't make SimpleDateFormat or can't get time"); + return PlatformResult(ErrorCode::UNKNOWN_ERR, + "can't make SimpleDateFormat or can't get time"); +} + +PlatformResult TimeUtilTools::ToStringHelper(UDate date, + std::shared_ptr& timezone_id, + bool use_locale_fmt, + TimeUtilTools::DateTimeFormatType type, + std::string* result_string) { + LoggerD("Entered"); + UErrorCode ec = U_ZERO_ERROR; + UnicodeString str; + + std::unique_ptr default_locale(TimeUtilTools::GetDefaultLocale()); + std::unique_ptr fmt( + new SimpleDateFormat( + TimeUtilTools::GetDateTimeFormat(type, use_locale_fmt), + ((use_locale_fmt && default_locale != nullptr) ? *default_locale : Locale::getEnglish()), + ec)); + + if (U_SUCCESS(ec)) { + std::unique_ptr tz(TimeZone::createTimeZone(*timezone_id)); + + fmt->setTimeZone(*tz); + fmt->format(date, str); + + return TimeUtilTools::ToUTF8String(str, result_string); + } + + LOGE("can't make SimpleDateFormat or can't get time"); + return PlatformResult(ErrorCode::UNKNOWN_ERR, "can't make SimpleDateFormat or can't get time"); +} + +PlatformResult TimeUtilTools::ToUTF8String(const UnicodeString& uni_str, + std::string* result_string) { + LoggerD("Entered"); + int buffer_len = sizeof(UChar) * static_cast(uni_str.length()) + 1; + + std::unique_ptr result_buffer(static_cast(malloc(buffer_len)), + &std::free); + + if (!result_buffer) { + LOGE("memory allocation error"); + return PlatformResult(ErrorCode::UNKNOWN_ERR, "memory allocation error"); + } + + memset(result_buffer.get(), 0, buffer_len); + CheckedArrayByteSink sink(result_buffer.get(), buffer_len); + uni_str.toUTF8(sink); + + if (sink.Overflowed()) { + LOGE("Converting error"); + return PlatformResult(ErrorCode::UNKNOWN_ERR, "Converting error"); + } + + *result_string = result_buffer.get(); + return PlatformResult(ErrorCode::NO_ERROR); +} + +UnicodeString* TimeUtilTools::ToUnicodeString(const std::string& str) { + LoggerD("Entered"); + return new UnicodeString(str.c_str()); +} + +PlatformResult TimeUtilTools::GetLocalTimeZone(std::string* result_string) { + LoggerD("Entered"); + UnicodeString id; + std::unique_ptr zone(TimeZone::createDefault()); + zone->getID(id); + + PlatformResult res = ToUTF8String(id, result_string); + if(res.IsError()) { + return res; + } + LoggerD("local timezone: %s", result_string->c_str()); + return PlatformResult(ErrorCode::NO_ERROR); +} + +Locale* TimeUtilTools::GetDefaultLocale() { + LoggerD("Entered"); + char* tempstr = vconf_get_str(VCONFKEY_REGIONFORMAT); + + if (nullptr == tempstr){ + return nullptr; + } + + Locale* default_locale = nullptr; + + char* p = strchr(tempstr, '.'); + int len = strlen(tempstr) - (p != nullptr ? strlen(p) : 0); + + if (len > 0) { + char* str_region = strndup(tempstr, len); //.UTF8 => 5 + default_locale = new Locale(str_region); + free(str_region); + } + + free(tempstr); + + if (default_locale && default_locale->isBogus()) { + delete default_locale; + default_locale = nullptr; + } + + return default_locale; +} + +UnicodeString TimeUtilTools::GetDateTimeFormat(DateTimeFormatType type, bool use_locale_fmt) { + LoggerD("Entered"); + UErrorCode ec = U_ZERO_ERROR; + Locale* default_locale = GetDefaultLocale(); + + std::unique_ptr date_time_pattern( + DateTimePatternGenerator::createInstance( + ((use_locale_fmt && default_locale) ? *default_locale : Locale::getEnglish()), + ec)); + + delete default_locale; + if (U_SUCCESS(ec)) { + UnicodeString pattern; + + switch (type) { + case DateTimeFormatType::kDateFormat: + pattern = date_time_pattern->getBestPattern(UDAT_YEAR_MONTH_WEEKDAY_DAY, ec); + break; + + case DateTimeFormatType::kDateShortFormat: + pattern = date_time_pattern->getBestPattern(UDAT_YEAR_NUM_MONTH_DAY, ec); + break; + + default: + { + int ret = 0; + int value = 0; + ret = vconf_get_int(VCONFKEY_REGIONFORMAT_TIME1224, &value); + // if failed, set default time format + if (-1 == ret) { + value = VCONFKEY_TIME_FORMAT_12; + } + + std::string skeletone; + if (DateTimeFormatType::kTimeFormat != type) { + skeletone = UDAT_YEAR_MONTH_WEEKDAY_DAY; + } + + if (VCONFKEY_TIME_FORMAT_12 == value) { + skeletone += "hhmmss"; + } else { + skeletone += "HHmmss"; + } + + std::unique_ptr skeletone_str(ToUnicodeString(skeletone)); + pattern = date_time_pattern->getBestPattern(*skeletone_str, ec); + + if (!use_locale_fmt) { + pattern += " 'GMT'Z v'"; + } + } + break; + } + + return pattern; + } + + return ""; +} + +PlatformResult TimeUtilTools::GetDateFormat(bool shortformat, std::string* result_string) { + LoggerD("Entered"); + UnicodeString time_format = + TimeUtilTools::GetDateTimeFormat( + (shortformat ? + DateTimeFormatType::kDateShortFormat: + DateTimeFormatType::kDateFormat), + true); + time_format = time_format.findAndReplace("E", "D"); + + if (time_format.indexOf("MMM") > 0) { + if (time_format.indexOf("MMMM") > 0){ + time_format = time_format.findAndReplace("MMMM", "M"); + } else { + time_format = time_format.findAndReplace("MMM", "M"); + } + } else { + time_format = time_format.findAndReplace("M", "m"); + } + + int32_t i = 0; + + while (i < time_format.length() - 1) { + if (time_format[i] == time_format[i + 1]) { + time_format.remove(i, 1); + } else { + ++i; + } + } + + PlatformResult res = ToUTF8String(time_format, result_string); + if(res.IsError()) { + return res; + } + return PlatformResult(ErrorCode::NO_ERROR); +} + +PlatformResult TimeUtilTools::GetTimeFormat(std::string* result_string) { + LoggerD("Entered"); + UnicodeString time_format = TimeUtilTools::GetDateTimeFormat( + DateTimeFormatType::kTimeFormat, true); + time_format = time_format.findAndReplace("H", "h"); + time_format = time_format.findAndReplace("K", "h"); + time_format = time_format.findAndReplace("k", "h"); + time_format = time_format.findAndReplace("a", "ap"); + + int32_t i = 0; + + while (i < time_format.length() - 1) { + if (time_format[i] == time_format[i + 1]) { + time_format.remove(i, 1); + } else { + ++i; + } + } + PlatformResult res = ToUTF8String(time_format, result_string); + if(res.IsError()) { + return res; + } + return PlatformResult(ErrorCode::NO_ERROR); +} + +PlatformResult TimeUtilTools::GetAvailableTimezones(picojson::array* available_timezones) { + LoggerD("Entered"); + UErrorCode ec = U_ZERO_ERROR; + std::unique_ptr tz_enum(TimeZone::createEnumeration()); + const char* str = nullptr; + int32_t count = tz_enum->count(ec); + + if (U_SUCCESS(ec)) { + int i = 0; + do { + int32_t resultLen = 0; + str = tz_enum->next(&resultLen, ec); + if (U_SUCCESS(ec)) { + available_timezones->push_back(picojson::value(str)); + ++i; + } else { + LOGE("An error occurred"); + return PlatformResult(ErrorCode::UNKNOWN_ERR, "An error occurred"); + } + } while ((str != nullptr) && (i < count)); + } + else { + LOGE("Can't get timezones list"); + return PlatformResult(ErrorCode::UNKNOWN_ERR, "Can't get timezones list"); + } + return PlatformResult(ErrorCode::NO_ERROR); +} + +} // time +} diff --git a/src/time/time_utils.h b/src/time/time_utils.h new file mode 100644 index 00000000..93e8e84e --- /dev/null +++ b/src/time/time_utils.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TIME_TIME_UTILS_H_ +#define TIME_TIME_UTILS_H_ + +#include +#include +#include "common/picojson.h" +#include "common/platform_result.h" + +namespace extension { +namespace time { + +class TimeUtilTools +{ + public: + enum class DateTimeFormatType { + kTimeFormat, + kDateFormat, + kDateShortFormat, + kDateTimeFormat + }; + enum class DSTTransition { + kPreviousDST, + kNextDST + }; + static UDate GetDSTTransition(UDate dstTransitionDate, + const std::shared_ptr& timezone_id, + DSTTransition tr_type); + static common::PlatformResult IsDST(UDate dstTransitionDate, + const std::shared_ptr& timezone_id, bool* result_bool); + static common::PlatformResult GetTimezoneAbbreviation(UDate date, + const std::shared_ptr& timezone_id, + std::string* result_string); + static common::PlatformResult ToStringHelper( + UDate date, std::shared_ptr& timezone_id, bool use_locale_fmt, + TimeUtilTools::DateTimeFormatType type, + std::string* result_string); + static common::PlatformResult ToUTF8String(const UnicodeString& uniStr, + std::string* result_string); + static UnicodeString* ToUnicodeString(const std::string& str); + static common::PlatformResult GetLocalTimeZone(std::string* result_string); + static UnicodeString GetDateTimeFormat(DateTimeFormatType type, bool bLocale); + static Locale* GetDefaultLocale(); + static common::PlatformResult GetDateFormat(bool shortformat, std::string* result_string); + static common::PlatformResult GetTimeFormat(std::string* result_string); + static common::PlatformResult GetAvailableTimezones(picojson::array* available_timezones); +}; + +} +} + +#endif // TIME_TIME_UTILS_H_ diff --git a/src/utils/utils_api.js b/src/utils/utils_api.js index dcee69ca..2e9b6fb8 100755 --- a/src/utils/utils_api.js +++ b/src/utils/utils_api.js @@ -27,8 +27,8 @@ var DateConverter = function() {}; DateConverter.prototype.toTZDate = function(v, isAllDay) { if (typeof v === 'number') { v = { - UTCTimestamp: v - }; + UTCTimestamp: v + }; isAllDay = false; } @@ -40,7 +40,7 @@ DateConverter.prototype.toTZDate = function(v, isAllDay) { return new tizen.TZDate(v.year, v.month - 1, v.day, null, null, null, null, v.timezone || null); } else { - return new tizen.TZDate(new Date(v.UTCTimestamp * 1000), 'UTC').toLocalTimezone(); + return new tizen.TZDate(new Date(v.UTCTimestamp * 1000)); } }; @@ -49,20 +49,12 @@ DateConverter.prototype.fromTZDate = function(v) { return v; } - var timestamp = Date.UTC(v.date_.getUTCFullYear(), - v.date_.getUTCMonth(), - v.date_.getUTCDate(), - v.date_.getUTCHours(), - v.date_.getUTCMinutes(), - v.date_.getUTCSeconds(), - v.date_.getUTCMilliseconds()) / 1000; - return { year: v.getFullYear(), month: v.getMonth(), day: v.getDate(), timezone: v.getTimezone(), - UTCTimestamp: timestamp + UTCTimestamp: v._utcTimestamp / 1000 }; };