Skip to content

Commit

Permalink
Change jerry_port interface to allow for a correct implementation of …
Browse files Browse the repository at this point in the history
…timezones.

The previous jerry_port interface did not allow timezones to be handled correctly,
even if the host system was up to the task. This PR changes the jerry_port interface
to allow a completely correct implementation to exist, and provides one (for Linux/BSD
systems) in default-date.c.

Fixes jerryscript-project#1661

JerryScript-DCO-1.0-Signed-off-by: crazy2be [email protected]
  • Loading branch information
crazy2be committed Oct 3, 2018
1 parent 35fbcd1 commit b81a97f
Show file tree
Hide file tree
Showing 11 changed files with 103 additions and 174 deletions.
54 changes: 23 additions & 31 deletions docs/05.PORT-API.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,27 +76,25 @@ void jerry_port_log (jerry_log_level_t level, const char *fmt, ...);
```c
/**
* Jerry time zone structure
*/
typedef struct
{
int offset; /**< minutes from west */
int daylight_saving_time; /**< daylight saving time (1 - DST applies, 0 - not on DST) */
} jerry_time_zone_t;
/**
* Get timezone and daylight saving data
* Get local timezone adjustment, in milliseconds, for the given timestamp.
* The timestamp can be specified in either UTC or local time, depending on
* the value of is_utc. Adding the value returned from this function to
* a timestamp in UTC time should result in local time for the current timezone.
*
* Note:
* This port function is called by jerry-core when
* CONFIG_DISABLE_DATE_BUILTIN is _not_ defined. Otherwise this function is
* not used.
*
* @param[out] tz_p time zone structure to fill.
* @return true - if success
* false - otherwise
* @param js_time_ms The timestamp we want an offset for (could be now, in
* the future, or in the past)
* @param is_utc Is the given timestamp in UTC time? If false, it is in local
time.
*
* @return offset in milliseconds, if available
*. 0 if not available / we are in UTC.
*/
bool jerry_port_get_time_zone (jerry_time_zone_t *tz_p);
bool jerry_port_get_local_tza (double js_time_ms, bool is_utc);
/**
* Get system time
Expand Down Expand Up @@ -198,27 +196,21 @@ jerry_port_log (jerry_log_level_t level, /**< log level */
#include "jerryscript-port.h"

/**
* Default implementation of jerry_port_get_time_zone.
* Default implementation of jerry_port_get_local_tza.
*/
bool jerry_port_get_time_zone (jerry_time_zone_t *tz_p)
double jerry_port_get_local_tza (double js_time_ms, /**< ms since unix epoch */
bool is_utc) /**< is the time above in utc? */
{
struct timeval tv;
struct timezone tz;

/* gettimeofday may not fill tz, so zero-initializing */
tz.tz_minuteswest = 0;
tz.tz_dsttime = 0;

if (gettimeofday (&tv, &tz) != 0)
struct tm tm;
time_t now = (time_t) (js_time_ms / 1000);
localtime_r (&now, &tm);
if (!is_utc)
{
return false;
now -= tm.tm_gmtoff;
localtime_r (&now, &tm);
}

tz_p->offset = tz.tz_minuteswest;
tz_p->daylight_saving_time = tz.tz_dsttime > 0 ? 1 : 0;

return true;
} /* jerry_port_get_time_zone */
return ((double) tm.tm_gmtoff) * 1000;
} /* jerry_port_get_local_tza */

/**
* Default implementation of jerry_port_get_current_time.
Expand Down
56 changes: 2 additions & 54 deletions jerry-core/ecma/builtin-objects/ecma-builtin-helpers-date.c
Original file line number Diff line number Diff line change
Expand Up @@ -301,41 +301,6 @@ ecma_date_week_day (ecma_number_t time) /**< time value */
return (week_day < 0) ? (7 + week_day) : week_day;
} /* ecma_date_week_day */

/**
* Helper function to get local time zone adjustment.
*
* See also:
* ECMA-262 v5, 15.9.1.7
*
* @return local time zone adjustment
*/
static inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
ecma_date_local_tza (jerry_time_zone_t *tz) /**< time zone information */
{
return tz->offset * -ECMA_DATE_MS_PER_MINUTE;
} /* ecma_date_local_tza */

/**
* Helper function to get the daylight saving time adjustment.
*
* See also:
* ECMA-262 v5, 15.9.1.8
*
* @return daylight saving time adjustment
*/
static inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
ecma_date_daylight_saving_ta (jerry_time_zone_t *tz, /**< time zone information */
ecma_number_t time) /**< time value */
{
JERRY_ASSERT (!ecma_number_is_nan (time));

/*
* TODO: Fix daylight saving calculation.
* https://github.com/jerryscript-project/jerryscript/issues/1661
*/
return tz->daylight_saving_time * ECMA_DATE_MS_PER_HOUR;
} /* ecma_date_daylight_saving_ta */

/**
* Helper function to get local time from UTC.
*
Expand All @@ -347,15 +312,7 @@ ecma_date_daylight_saving_ta (jerry_time_zone_t *tz, /**< time zone information
inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
ecma_date_local_time_zone (ecma_number_t time) /**< time value */
{
jerry_time_zone_t tz;

if (ecma_number_is_nan (time)
|| !jerry_port_get_time_zone (&tz))
{
return ecma_number_make_nan ();
}

return ecma_date_local_tza (&tz) + ecma_date_daylight_saving_ta (&tz, time);
return jerry_port_get_local_tza (time, true);
} /* ecma_date_local_time_zone */

/**
Expand All @@ -369,16 +326,7 @@ ecma_date_local_time_zone (ecma_number_t time) /**< time value */
ecma_number_t
ecma_date_utc (ecma_number_t time) /**< time value */
{
jerry_time_zone_t tz;

if (ecma_number_is_nan (time)
|| !jerry_port_get_time_zone (&tz))
{
return ecma_number_make_nan ();
}

ecma_number_t simple_utc_time = time - ecma_date_local_tza (&tz);
return simple_utc_time - ecma_date_daylight_saving_ta (&tz, simple_utc_time);
return time - jerry_port_get_local_tza (time, false);
} /* ecma_date_utc */

/**
Expand Down
30 changes: 14 additions & 16 deletions jerry-core/include/jerryscript-port.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,27 +111,25 @@ void JERRY_ATTR_FORMAT (printf, 2, 3) jerry_port_log (jerry_log_level_t level, c
*/

/**
* Jerry time zone structure
*/
typedef struct
{
int offset; /**< minutes from west */
int daylight_saving_time; /**< daylight saving time (1 - DST applies, 0 - not on DST) */
} jerry_time_zone_t;

/**
* Get timezone and daylight saving data
* Get local timezone adjustment, in milliseconds. This value, added to a timestamp in UTC
* time, should yield local time. Ideally, this function should satisfy the stipulations
* applied to LocalTZA in section 20.3.1.7 of ecmascript version 9.0.
*
* See Also:
* ECMA-262 v9, 20.3.1.7
*
* Note:
* This port function is called by jerry-core when
* CONFIG_DISABLE_DATE_BUILTIN is _not_ defined. Otherwise this function is
* not used.
* CONFIG_DISABLE_DATE_BUILTIN is _not_ defined. Otherwise this function
* is not used.
*
* @param js_time_ms a unix timestamp with millisecond precision, given in local time
* (is_utc is false), or UTC time (is_utc is true).
* @param is_utc is the above timestamp in UTC or local time?
*
* @param[out] tz_p time zone structure to fill.
* @return true - if success
* false - otherwise
* @return milliseconds between local time and UTC for the given timestamp.
*/
bool jerry_port_get_time_zone (jerry_time_zone_t *tz_p);
double jerry_port_get_local_tza (double js_time_ms, bool is_utc);

/**
* Get system time
Expand Down
6 changes: 6 additions & 0 deletions jerry-port/default/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ file(GLOB SOURCE_PORT_DEFAULT *.c)
# (should only be necessary if we used compiler default libc but not checking that)
set(DEFINES_PORT_DEFAULT _BSD_SOURCE _DEFAULT_SOURCE)

INCLUDE (CheckStructHasMember)
CHECK_STRUCT_HAS_MEMBER ("struct tm" tm_gmtoff time.h HAVE_TM_GMTOFF)
if(HAVE_TM_GMTOFF)
set(DEFINES_PORT_DEFAULT ${DEFINES_PORT_DEFAULT} HAVE_TM_GMTOFF)
endif()

# Sleep function availability check
INCLUDE (CheckIncludeFiles)
CHECK_INCLUDE_FILES (time.h HAVE_TIME_H)
Expand Down
46 changes: 24 additions & 22 deletions jerry-port/default/default-date.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
* limitations under the License.
*/

#ifdef HAVE_TM_GMTOFF
#include <time.h>
#endif
#ifdef __GNUC__
#include <sys/time.h>
#endif
Expand All @@ -21,33 +24,32 @@
#include "jerryscript-port-default.h"

/**
* Default implementation of jerry_port_get_time_zone. Uses 'gettimeofday' if
* available on the system, does nothing otherwise.
* Default implementation of jerry_port_get_local_tza. Uses the 'tm_gmtoff' field
* of 'struct tm' (a GNU extension) filled by 'localtime_r' if available on the
* system, does nothing otherwise.
*
* @return true - if 'gettimeofday' is available and executed successfully,
* false - otherwise.
* @return offset between UTC and local time at the given unix timestamp, if
* available. Otherwise, returns 0, assuming UTC time.
*/
bool jerry_port_get_time_zone (jerry_time_zone_t *tz_p) /**< [out] time zone structure to fill */
double jerry_port_get_local_tza (double js_time_ms, /**< ms since unix epoch */
bool is_utc) /**< is the time above in UTC? */
{
#ifdef __GNUC__
struct timeval tv;
struct timezone tz;

/* gettimeofday may not fill tz, so zero-initializing */
tz.tz_minuteswest = 0;
tz.tz_dsttime = 0;

if (gettimeofday (&tv, &tz) == 0)
#ifdef HAVE_TM_GMTOFF
struct tm tm;
time_t now = (time_t) (js_time_ms / 1000);
localtime_r (&now, &tm);
if (!is_utc)
{
tz_p->offset = tz.tz_minuteswest;
tz_p->daylight_saving_time = tz.tz_dsttime > 0 ? 1 : 0;

return true;
now -= tm.tm_gmtoff;
localtime_r (&now, &tm);
}
#endif /* __GNUC__ */

return false;
} /* jerry_port_get_time_zone */
return ((double) tm.tm_gmtoff) * 1000;
#else
(void) js_time_ms;
(void) is_utc;
return 0.0;
#endif /* HAVE_TM_GMTOFF */
} /* jerry_port_get_local_tza */

/**
* Default implementation of jerry_port_get_current_time. Uses 'gettimeofday' if
Expand Down
11 changes: 4 additions & 7 deletions targets/curie_bsp/source/curie-bsp-port.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,13 @@ void jerry_port_fatal (jerry_fatal_code_t code)
} /* jerry_port_fatal */

/**
* Curie BSP implementation of jerry_port_get_time_zone.
* Curie BSP implementation of jerry_port_get_local_tza.
*/
bool jerry_port_get_time_zone (jerry_time_zone_t *tz_p)
double jerry_port_get_local_tza (double js_time_ms, bool is_utc)
{
//EMPTY implementation
tz_p->offset = 0;
tz_p->daylight_saving_time = 0;

return true;
} /* jerry_port_get_time_zone */
return 0;
} /* jerry_port_get_local_tza */

/**
* Curie BSP implementation of jerry_port_get_current_time.
Expand Down
15 changes: 6 additions & 9 deletions targets/esp8266/user/jerry_port.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,13 @@ jerry_port_get_current_time (void)
} /* jerry_port_get_current_time */

/**
* Dummy function to get the time zone.
* Dummy function to get the time zone adjustment.
*
* @return true
* @return 0
*/
bool
jerry_port_get_time_zone (jerry_time_zone_t *tz_p)
double
jerry_port_get_local_tza (double js_time_ms, bool is_utc)
{
/* We live in UTC. */
tz_p->offset = 0;
tz_p->daylight_saving_time = 0;

return true;
} /* jerry_port_get_time_zone */
return 0;
} /* jerry_port_get_local_tza */
14 changes: 6 additions & 8 deletions targets/mbedos5/source/jerry_port_mbed.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,15 @@ jerry_port_log (jerry_log_level_t level, /**< log level */
#endif /* JSMBED_OVERRIDE_JERRY_PORT_LOG */

/**
* Implementation of jerry_port_get_time_zone.
* Implementation of jerry_port_get_local_tza.
*
* @return true - if success
* @return 0, as we live in UTC.
*/
bool
jerry_port_get_time_zone (jerry_time_zone_t *tz_p) /**< timezone pointer */
double
jerry_port_get_local_tza (double js_time_ms, bool is_utc)
{
tz_p->offset = 0;
tz_p->daylight_saving_time = 0;
return true;
} /* jerry_port_get_time_zone */
return 0;
} /* jerry_port_get_local_tza */

/**
* Implementation of jerry_port_get_current_time.
Expand Down
15 changes: 6 additions & 9 deletions targets/nuttx-stm32f4/jerry_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -492,19 +492,16 @@ jerry_port_log (jerry_log_level_t level, /**< log level */
} /* jerry_port_log */

/**
* Dummy function to get the time zone.
* Dummy function to get the time zone adjustment.
*
* @return true
* @return 0
*/
bool
jerry_port_get_time_zone (jerry_time_zone_t *tz_p)
double
jerry_port_get_local_tza (double js_time_ms, bool is_utc)
{
/* We live in UTC. */
tz_p->offset = 0;
tz_p->daylight_saving_time = 0;

return true;
} /* jerry_port_get_time_zone */
return 0;
} /* jerry_port_get_local_tza */

/**
* Dummy function to get the current time.
Expand Down
15 changes: 6 additions & 9 deletions targets/tizenrt-artik053/apps/jerryscript/jerry_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -474,19 +474,16 @@ jerry_port_log (jerry_log_level_t level, /**< log level */
} /* jerry_port_log */

/**
* Dummy function to get the time zone.
* Dummy function to get the time zone adjustment.
*
* @return true
* @return 0
*/
bool
jerry_port_get_time_zone (jerry_time_zone_t *tz_p)
double
jerry_port_get_local_tza (double js_time_ms, bool is_utc)
{
/* We live in UTC. */
tz_p->offset = 0;
tz_p->daylight_saving_time = 0;

return true;
} /* jerry_port_get_time_zone */
return 0;
} /* jerry_port_get_local_tza */

/**
* Dummy function to get the current time.
Expand Down
Loading

0 comments on commit b81a97f

Please sign in to comment.