diff --git a/docs/05.PORT-API.md b/docs/05.PORT-API.md index 41c72a3252..e0fd93c0fa 100644 --- a/docs/05.PORT-API.md +++ b/docs/05.PORT-API.md @@ -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 @@ -198,27 +196,20 @@ 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 unix_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) - { - return false; + struct tm tm; + time_t now = (time_t)(unix_ms / 1000); + localtime_r(&now, &tm); + if (!is_utc) { + 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 tm.tm_gmtoff * 1000; +} /* jerry_port_get_local_tza */ /** * Default implementation of jerry_port_get_current_time. diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-date.c b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-date.c index 084b0ff479..2e1fba2d95 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-date.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-date.c @@ -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. * @@ -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 */ /** @@ -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 */ /** diff --git a/jerry-core/include/jerryscript-port.h b/jerry-core/include/jerryscript-port.h index 59e4b61d29..63ef499ae7 100644 --- a/jerry-core/include/jerryscript-port.h +++ b/jerry-core/include/jerryscript-port.h @@ -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 diff --git a/jerry-port/default/CMakeLists.txt b/jerry-port/default/CMakeLists.txt index e388dc9936..025965a24d 100644 --- a/jerry-port/default/CMakeLists.txt +++ b/jerry-port/default/CMakeLists.txt @@ -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) diff --git a/jerry-port/default/default-date.c b/jerry-port/default/default-date.c index 837ef7d80e..c31f51e3fe 100644 --- a/jerry-port/default/default-date.c +++ b/jerry-port/default/default-date.c @@ -13,6 +13,9 @@ * limitations under the License. */ +#ifdef HAVE_TM_GMTOFF +#include +#endif #ifdef __GNUC__ #include #endif @@ -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 unix_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) (unix_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) unix_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 diff --git a/targets/curie_bsp/source/curie-bsp-port.c b/targets/curie_bsp/source/curie-bsp-port.c index 97cb896c42..b92643be22 100644 --- a/targets/curie_bsp/source/curie-bsp-port.c +++ b/targets/curie_bsp/source/curie-bsp-port.c @@ -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. diff --git a/targets/esp8266/user/jerry_port.c b/targets/esp8266/user/jerry_port.c index 7ba25e43ad..66953275d5 100644 --- a/targets/esp8266/user/jerry_port.c +++ b/targets/esp8266/user/jerry_port.c @@ -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 */ diff --git a/targets/mbedos5/source/jerry_port_mbed.c b/targets/mbedos5/source/jerry_port_mbed.c index 3e225b0136..182a08cf32 100644 --- a/targets/mbedos5/source/jerry_port_mbed.c +++ b/targets/mbedos5/source/jerry_port_mbed.c @@ -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. diff --git a/targets/nuttx-stm32f4/jerry_main.c b/targets/nuttx-stm32f4/jerry_main.c index ef6a63c798..da7e10f470 100644 --- a/targets/nuttx-stm32f4/jerry_main.c +++ b/targets/nuttx-stm32f4/jerry_main.c @@ -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. diff --git a/targets/tizenrt-artik053/apps/jerryscript/jerry_main.c b/targets/tizenrt-artik053/apps/jerryscript/jerry_main.c index ce8cbe23ae..54d966b492 100644 --- a/targets/tizenrt-artik053/apps/jerryscript/jerry_main.c +++ b/targets/tizenrt-artik053/apps/jerryscript/jerry_main.c @@ -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. diff --git a/targets/zephyr/src/jerry-port.c b/targets/zephyr/src/jerry-port.c index b1eb9dcb67..9d05d2699e 100644 --- a/targets/zephyr/src/jerry-port.c +++ b/targets/zephyr/src/jerry-port.c @@ -59,19 +59,16 @@ 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 */ /** * Provide the implementation of jerryx_port_handler_print_char.