[Time] Time implementation changed
authorPiotr Kosko <p.kosko@samsung.com>
Mon, 28 Sep 2015 11:34:18 +0000 (13:34 +0200)
committerPiotr Kosko <p.kosko@samsung.com>
Fri, 2 Oct 2015 05:33:28 +0000 (07:33 +0200)
[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 <p.kosko@samsung.com>
src/time/time.gyp
src/time/time_api.js
src/time/time_instance.cc
src/time/time_instance.h
src/time/time_manager.cc [new file with mode: 0644]
src/time/time_manager.h [new file with mode: 0644]
src/time/time_utils.cc [new file with mode: 0644]
src/time/time_utils.h [new file with mode: 0644]
src/utils/utils_api.js

index a7a2d263f385d777a6c876094c3bc35b824780e9..cade13cffed9fa75d0bf225510537f4ace9cb0f5 100644 (file)
         'time_extension.h',
         'time_instance.cc',
         'time_instance.h',
+        'time_manager.cc',
+        'time_manager.h',
+        'time_utils.cc',
+        'time_utils.h',
       ],
       'conditions': [
         [ 'tizen == 1', {
index dc4f5e61073c92e55ae1845b5751297d2ef8779a..6fc9c791a09a120caada46d678ee84a7be67b400 100644 (file)
-// 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
index 7e78cba4d23fdfa5071227cc310a636d2b2f739a..2f0ce9372d147500176243507807e09f6ce06cfa 100644 (file)
 // found in the LICENSE file.
 
 #include "time/time_instance.h"
-#include "common/platform_exception.h"
 #include "common/logger.h"
-
-#if defined(TIZEN)
-#include <vconf.h>
-#endif
-
-#include <sstream>
-#include <memory>
-#include <cerrno>
-#include <unistd.h>
-
 #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<StringEnumeration> 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<UnicodeString> 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(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<picojson::object>();
+
+  auto array = result_obj.insert(std::make_pair("availableTimezones",
+                                                picojson::value(picojson::array())));
+  PlatformResult res = TimeUtilTools::GetAvailableTimezones(
+      &array.first->second.get<picojson::array>());
+  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<UnicodeString> 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(TimeZone::createTimeZone(*id));
-  std::unique_ptr<Calendar> cal(Calendar::createInstance(*timezone, ec));
-  if (U_FAILURE(ec)) {
-    LoggerE("Failed to create Calendar instance");
-    ReportError(out);
+  bool shortformat = args.get("shortformat").get<bool>();
+  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<DateFormat> 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<picojson::object>();
+  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<UnicodeString> 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(TimeZone::createTimeZone(*id));
+  picojson::value result = picojson::value(picojson::object());
+  picojson::object& result_obj = result.get<picojson::object>();
+  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<bool>(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<UnicodeString> 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(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<UnicodeString> 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(TimeZone::createTimeZone(*id));
-  std::unique_ptr<Calendar> 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<DateFormat> 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<picojson::object>();
+  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<std::string>();
+  LoggerD("Getting timezone details for id: %s ", timezone_id.c_str());
+
+  const std::string& timestamp_str = args.get("timestamp").get<std::string>();
+
+  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<picojson::object>();
+    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<DateTimePatternGenerator> 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::string>();
+  std::shared_ptr<UnicodeString> 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<std::string>();
+  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<picojson::object>();
+  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<void*>(&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<JsonObject>();
-  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<TimeInstance*>(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::string>();
+  std::shared_ptr<UnicodeString> unicode_id (new UnicodeString(timezone_id.c_str()));
 
-  std::string defaultTimezone = GetDefaultTimezone();
+  const std::string& timestamp_str = args.get("timestamp").get<std::string>();
+  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<picojson::object>();
+  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::string>();
+  std::shared_ptr<UnicodeString> 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<std::string>();
+  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<picojson::object>();
+  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::string>();
+  std::shared_ptr<UnicodeString> 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<std::string>();
+  UDate date = std::stod(timestamp_str);
 
-  std::unique_ptr<UnicodeString> 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<picojson::object>();
+  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(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::string>();
+  std::shared_ptr<UnicodeString> unicode_id (new UnicodeString(timezone_id.c_str()));
+
+  const std::string& timestamp_str = args.get("timestamp").get<std::string>();
+  UDate date = std::stod(timestamp_str);
 
-  dateInMs -= (rawOffset + dstOffset);
+  picojson::value result = picojson::value(picojson::object());
+  picojson::object& result_obj = result.get<picojson::object>();
+  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<double>(dateInMs)}, out);
+  ReportSuccess(result, out);
 }
 
 }  // namespace time
index 3c5ffa9b2f3c485f60f07b9027b6f07c3de21d91..6666a211cd1e7cb10de35cebb3b8873d5ac1764e 100644 (file)
@@ -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 <string>
 
 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 (file)
index 0000000..898954a
--- /dev/null
@@ -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 <unicode/timezone.h>
+#include <unicode/calendar.h>
+#include <unistd.h>
+
+#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<UnicodeString> unicode_id (new UnicodeString(timezone_id.c_str()));
+  std::unique_ptr<TimeZone> 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<TimeManager*>(event_ptr);
+  TimeInstance* instance = manager->GetTimeInstance();
+  std::string defaultTimezone = GetDefaultTimezone();
+
+  if (manager->GetCurrentTimezone() != defaultTimezone) {
+    manager->SetCurrentTimezone(defaultTimezone);
+    //call timezone callback
+
+    const std::shared_ptr<picojson::value>& response =
+        std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+    response->get<picojson::object>()["listenerId"] = picojson::value("TimezoneChangeListener");
+    //    ReportSuccess(result,response->get<picojson::object>());
+    Instance::PostMessage(instance, response->serialize().c_str());
+  }
+  //call date time callback
+  const std::shared_ptr<picojson::value>& response =
+      std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+  response->get<picojson::object>()["listenerId"] = picojson::value("DateTimeChangeListener");
+  //  ReportSuccess(result,response->get<picojson::object>());
+  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 (file)
index 0000000..02f95e9
--- /dev/null
@@ -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 <memory>
+#include <vconf.h>
+#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 (file)
index 0000000..0afbc86
--- /dev/null
@@ -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 <unicode/dtptngen.h>
+#include <unicode/smpdtfmt.h>
+#include <unicode/timezone.h>
+#include <unicode/vtzone.h>
+
+#include <vconf.h>
+
+#include "common/logger.h"
+
+using common::PlatformResult;
+using common::ErrorCode;
+
+namespace extension {
+namespace time {
+
+UDate TimeUtilTools::GetDSTTransition(UDate timestamp,
+                                      const std::shared_ptr<UnicodeString>& timezone_id,
+                                      DSTTransition tr_type) {
+  LoggerD("Entered");
+  UBool result = false;
+  UDate dst_transition_date = timestamp;
+  std::unique_ptr<VTimeZone> 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<UnicodeString>& timezone_id,
+                                    bool* result_bool) {
+  LoggerD("Entered");
+  UErrorCode ec = U_ZERO_ERROR;
+  std::unique_ptr<TimeZone> tz (TimeZone::createTimeZone(*timezone_id));
+  std::unique_ptr<icu::Calendar> 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<bool>(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<UnicodeString>& timezone_id,
+                                                      std::string* result_string) {
+  LoggerD("Entered");
+  UErrorCode ec = U_ZERO_ERROR;
+  UnicodeString str;
+
+  std::unique_ptr<DateFormat> fmt(new SimpleDateFormat(UnicodeString("z"),
+                                                       Locale::getEnglish(), ec));
+  if (U_SUCCESS(ec)) {
+    std::unique_ptr<TimeZone> 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<DateFormat> 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<UnicodeString>& 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<Locale> default_locale(TimeUtilTools::GetDefaultLocale());
+  std::unique_ptr<DateFormat> 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<TimeZone> 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<int>(uni_str.length()) + 1;
+
+  std::unique_ptr<char, void(*)(void*)> result_buffer(static_cast<char*>(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<TimeZone> 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<DateTimePatternGenerator> 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<UnicodeString> 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<StringEnumeration> 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 (file)
index 0000000..93e8e84
--- /dev/null
@@ -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 <memory>
+#include <unicode/unistr.h>
+#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<UnicodeString>& timezone_id,
+                                DSTTransition tr_type);
+  static common::PlatformResult IsDST(UDate dstTransitionDate,
+                                      const std::shared_ptr<UnicodeString>& timezone_id, bool* result_bool);
+  static common::PlatformResult GetTimezoneAbbreviation(UDate date,
+                                                        const std::shared_ptr<UnicodeString>& timezone_id,
+                                                        std::string* result_string);
+  static common::PlatformResult ToStringHelper(
+      UDate date, std::shared_ptr<UnicodeString>& 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_
index dcee69ca6ce0ac49016eff6b456552afba37c0be..2e9b6fb8ee6effbb3629fb1f783636bccf041c68 100755 (executable)
@@ -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
   };
 
 };