Skip to content

Commit b0821b5

Browse files
committed
Change jerry_port interface to allow for a correct implementation of 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 #1661 JerryScript-DCO-1.0-Signed-off-by: crazy2be [email protected]
1 parent 35fbcd1 commit b0821b5

File tree

11 files changed

+96
-174
lines changed

11 files changed

+96
-174
lines changed

docs/05.PORT-API.md

+23-32
Original file line numberDiff line numberDiff line change
@@ -76,27 +76,25 @@ void jerry_port_log (jerry_log_level_t level, const char *fmt, ...);
7676
7777
```c
7878
/**
79-
* Jerry time zone structure
80-
*/
81-
typedef struct
82-
{
83-
int offset; /**< minutes from west */
84-
int daylight_saving_time; /**< daylight saving time (1 - DST applies, 0 - not on DST) */
85-
} jerry_time_zone_t;
86-
87-
/**
88-
* Get timezone and daylight saving data
79+
* Get local timezone adjustment, in milliseconds, for the given timestamp.
80+
* The timestamp can be specified in either utc or local time, depending on
81+
* the value of is_utc. Adding the value returned from this function to
82+
* a timestamp in utc time should result in local time for the current timezone.
8983
*
9084
* Note:
9185
* This port function is called by jerry-core when
9286
* CONFIG_DISABLE_DATE_BUILTIN is _not_ defined. Otherwise this function is
9387
* not used.
9488
*
95-
* @param[out] tz_p time zone structure to fill.
96-
* @return true - if success
97-
* false - otherwise
89+
* @param js_time_ms The timestamp we want an offset for (could be now, in
90+
* the future, or in the past)
91+
* @param is_utc Is the given timestamp in UTC time? If false, it is in local
92+
time.
93+
*
94+
* @return offset in milliseconds, if available
95+
*. 0 if not available / we are in UTC.
9896
*/
99-
bool jerry_port_get_time_zone (jerry_time_zone_t *tz_p);
97+
bool jerry_port_get_local_tza (double js_time_ms, bool is_utc);
10098
10199
/**
102100
* Get system time
@@ -198,27 +196,20 @@ jerry_port_log (jerry_log_level_t level, /**< log level */
198196
#include "jerryscript-port.h"
199197

200198
/**
201-
* Default implementation of jerry_port_get_time_zone.
199+
* Default implementation of jerry_port_get_local_tza.
202200
*/
203-
bool jerry_port_get_time_zone (jerry_time_zone_t *tz_p)
201+
double jerry_port_get_local_tza (double unix_ms, /**< ms since unix epoch */
202+
bool is_utc) /**< is the time above in utc? */
204203
{
205-
struct timeval tv;
206-
struct timezone tz;
207-
208-
/* gettimeofday may not fill tz, so zero-initializing */
209-
tz.tz_minuteswest = 0;
210-
tz.tz_dsttime = 0;
211-
212-
if (gettimeofday (&tv, &tz) != 0)
213-
{
214-
return false;
204+
struct tm tm;
205+
time_t now = (time_t)(unix_ms / 1000);
206+
localtime_r(&now, &tm);
207+
if (!is_utc) {
208+
now -= tm.tm_gmtoff;
209+
localtime_r(&now, &tm);
215210
}
216-
217-
tz_p->offset = tz.tz_minuteswest;
218-
tz_p->daylight_saving_time = tz.tz_dsttime > 0 ? 1 : 0;
219-
220-
return true;
221-
} /* jerry_port_get_time_zone */
211+
return tm.tm_gmtoff * 1000;
212+
} /* jerry_port_get_local_tza */
222213

223214
/**
224215
* Default implementation of jerry_port_get_current_time.

jerry-core/ecma/builtin-objects/ecma-builtin-helpers-date.c

+2-54
Original file line numberDiff line numberDiff line change
@@ -301,41 +301,6 @@ ecma_date_week_day (ecma_number_t time) /**< time value */
301301
return (week_day < 0) ? (7 + week_day) : week_day;
302302
} /* ecma_date_week_day */
303303

304-
/**
305-
* Helper function to get local time zone adjustment.
306-
*
307-
* See also:
308-
* ECMA-262 v5, 15.9.1.7
309-
*
310-
* @return local time zone adjustment
311-
*/
312-
static inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
313-
ecma_date_local_tza (jerry_time_zone_t *tz) /**< time zone information */
314-
{
315-
return tz->offset * -ECMA_DATE_MS_PER_MINUTE;
316-
} /* ecma_date_local_tza */
317-
318-
/**
319-
* Helper function to get the daylight saving time adjustment.
320-
*
321-
* See also:
322-
* ECMA-262 v5, 15.9.1.8
323-
*
324-
* @return daylight saving time adjustment
325-
*/
326-
static inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
327-
ecma_date_daylight_saving_ta (jerry_time_zone_t *tz, /**< time zone information */
328-
ecma_number_t time) /**< time value */
329-
{
330-
JERRY_ASSERT (!ecma_number_is_nan (time));
331-
332-
/*
333-
* TODO: Fix daylight saving calculation.
334-
* https://github.com/jerryscript-project/jerryscript/issues/1661
335-
*/
336-
return tz->daylight_saving_time * ECMA_DATE_MS_PER_HOUR;
337-
} /* ecma_date_daylight_saving_ta */
338-
339304
/**
340305
* Helper function to get local time from UTC.
341306
*
@@ -347,15 +312,7 @@ ecma_date_daylight_saving_ta (jerry_time_zone_t *tz, /**< time zone information
347312
inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
348313
ecma_date_local_time_zone (ecma_number_t time) /**< time value */
349314
{
350-
jerry_time_zone_t tz;
351-
352-
if (ecma_number_is_nan (time)
353-
|| !jerry_port_get_time_zone (&tz))
354-
{
355-
return ecma_number_make_nan ();
356-
}
357-
358-
return ecma_date_local_tza (&tz) + ecma_date_daylight_saving_ta (&tz, time);
315+
return jerry_port_get_local_tza (time, true);
359316
} /* ecma_date_local_time_zone */
360317

361318
/**
@@ -369,16 +326,7 @@ ecma_date_local_time_zone (ecma_number_t time) /**< time value */
369326
ecma_number_t
370327
ecma_date_utc (ecma_number_t time) /**< time value */
371328
{
372-
jerry_time_zone_t tz;
373-
374-
if (ecma_number_is_nan (time)
375-
|| !jerry_port_get_time_zone (&tz))
376-
{
377-
return ecma_number_make_nan ();
378-
}
379-
380-
ecma_number_t simple_utc_time = time - ecma_date_local_tza (&tz);
381-
return simple_utc_time - ecma_date_daylight_saving_ta (&tz, simple_utc_time);
329+
return time - jerry_port_get_local_tza (time, false);
382330
} /* ecma_date_utc */
383331

384332
/**

jerry-core/include/jerryscript-port.h

+8-16
Original file line numberDiff line numberDiff line change
@@ -111,27 +111,19 @@ void JERRY_ATTR_FORMAT (printf, 2, 3) jerry_port_log (jerry_log_level_t level, c
111111
*/
112112

113113
/**
114-
* Jerry time zone structure
115-
*/
116-
typedef struct
117-
{
118-
int offset; /**< minutes from west */
119-
int daylight_saving_time; /**< daylight saving time (1 - DST applies, 0 - not on DST) */
120-
} jerry_time_zone_t;
121-
122-
/**
123-
* Get timezone and daylight saving data
114+
* Get local timezone adjustment, in milliseconds. This value, added to a timestamp in UTC
115+
* time, should yield local time. Ideally, this function should satisfy the stipulations
116+
* applied to LocalTZA in section 20.3.1.7 of ecmascript version 9.0 [1].
117+
* [1] https://www.ecma-international.org/ecma-262/9.0/#sec-local-time-zone-adjustment
124118
*
125119
* Note:
126120
* This port function is called by jerry-core when
127-
* CONFIG_DISABLE_DATE_BUILTIN is _not_ defined. Otherwise this function is
128-
* not used.
121+
* CONFIG_DISABLE_DATE_BUILTIN is _not_ defined. Otherwise this function
122+
* is not used.
129123
*
130-
* @param[out] tz_p time zone structure to fill.
131-
* @return true - if success
132-
* false - otherwise
124+
* @return milliseconds between local time and utc for the given timestamp.
133125
*/
134-
bool jerry_port_get_time_zone (jerry_time_zone_t *tz_p);
126+
double jerry_port_get_local_tza (double js_time_ms, bool is_utc);
135127

136128
/**
137129
* Get system time

jerry-port/default/CMakeLists.txt

+6
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ file(GLOB SOURCE_PORT_DEFAULT *.c)
2626
# (should only be necessary if we used compiler default libc but not checking that)
2727
set(DEFINES_PORT_DEFAULT _BSD_SOURCE _DEFAULT_SOURCE)
2828

29+
INCLUDE (CheckStructHasMember)
30+
CHECK_STRUCT_HAS_MEMBER ("struct tm" tm_gmtoff time.h HAVE_TM_GMTOFF)
31+
if(HAVE_TM_GMTOFF)
32+
set(DEFINES_PORT_DEFAULT ${DEFINES_PORT_DEFAULT} HAVE_TM_GMTOFF)
33+
endif()
34+
2935
# Sleep function availability check
3036
INCLUDE (CheckIncludeFiles)
3137
CHECK_INCLUDE_FILES (time.h HAVE_TIME_H)

jerry-port/default/default-date.c

+24-22
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
* limitations under the License.
1414
*/
1515

16+
#ifdef HAVE_TM_GMTOFF
17+
#include <time.h>
18+
#endif
1619
#ifdef __GNUC__
1720
#include <sys/time.h>
1821
#endif
@@ -21,33 +24,32 @@
2124
#include "jerryscript-port-default.h"
2225

2326
/**
24-
* Default implementation of jerry_port_get_time_zone. Uses 'gettimeofday' if
25-
* available on the system, does nothing otherwise.
27+
* Default implementation of jerry_port_get_local_tza. Uses the `tm_gmtoff` field
28+
* of `struct tm` (a GNU extension) filled by `localtime_r` if available on the
29+
* system, does nothing otherwise.
2630
*
27-
* @return true - if 'gettimeofday' is available and executed successfully,
28-
* false - otherwise.
31+
* @return offset between utc and localtime at the given unix timestamp, if
32+
* available. 0 otherwise.
2933
*/
30-
bool jerry_port_get_time_zone (jerry_time_zone_t *tz_p) /**< [out] time zone structure to fill */
34+
double jerry_port_get_local_tza (double unix_ms, /**< ms since unix epoch */
35+
bool is_utc) /**< is the time above in utc? */
3136
{
32-
#ifdef __GNUC__
33-
struct timeval tv;
34-
struct timezone tz;
35-
36-
/* gettimeofday may not fill tz, so zero-initializing */
37-
tz.tz_minuteswest = 0;
38-
tz.tz_dsttime = 0;
39-
40-
if (gettimeofday (&tv, &tz) == 0)
37+
#ifdef HAVE_TM_GMTOFF
38+
struct tm tm;
39+
time_t now = (time_t)(unix_ms / 1000);
40+
localtime_r (&now, &tm);
41+
if (!is_utc)
4142
{
42-
tz_p->offset = tz.tz_minuteswest;
43-
tz_p->daylight_saving_time = tz.tz_dsttime > 0 ? 1 : 0;
44-
45-
return true;
43+
now -= tm.tm_gmtoff;
44+
localtime_r (&now, &tm);
4645
}
47-
#endif /* __GNUC__ */
48-
49-
return false;
50-
} /* jerry_port_get_time_zone */
46+
return ((double)tm.tm_gmtoff) * 1000;
47+
#else
48+
(void)unix_ms;
49+
(void)is_utc;
50+
return 0.0;
51+
#endif /* HAVE_TM_GMTOFF */
52+
} /* jerry_port_get_local_tza */
5153

5254
/**
5355
* Default implementation of jerry_port_get_current_time. Uses 'gettimeofday' if

targets/curie_bsp/source/curie-bsp-port.c

+4-7
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,13 @@ void jerry_port_fatal (jerry_fatal_code_t code)
5252
} /* jerry_port_fatal */
5353

5454
/**
55-
* Curie BSP implementation of jerry_port_get_time_zone.
55+
* Curie BSP implementation of jerry_port_get_local_tza.
5656
*/
57-
bool jerry_port_get_time_zone (jerry_time_zone_t *tz_p)
57+
double jerry_port_get_local_tza (double js_time_ms, bool is_utc)
5858
{
5959
//EMPTY implementation
60-
tz_p->offset = 0;
61-
tz_p->daylight_saving_time = 0;
62-
63-
return true;
64-
} /* jerry_port_get_time_zone */
60+
return 0;
61+
} /* jerry_port_get_local_tza */
6562

6663
/**
6764
* Curie BSP implementation of jerry_port_get_current_time.

targets/esp8266/user/jerry_port.c

+5-8
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,11 @@ jerry_port_get_current_time (void)
6363
/**
6464
* Dummy function to get the time zone.
6565
*
66-
* @return true
66+
* @return 0, no time zone.
6767
*/
68-
bool
69-
jerry_port_get_time_zone (jerry_time_zone_t *tz_p)
68+
double
69+
jerry_port_get_local_tza (double js_time_ms, bool is_utc)
7070
{
7171
/* We live in UTC. */
72-
tz_p->offset = 0;
73-
tz_p->daylight_saving_time = 0;
74-
75-
return true;
76-
} /* jerry_port_get_time_zone */
72+
return 0;
73+
} /* jerry_port_get_local_tza */

targets/mbedos5/source/jerry_port_mbed.c

+6-8
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,15 @@ jerry_port_log (jerry_log_level_t level, /**< log level */
4646
#endif /* JSMBED_OVERRIDE_JERRY_PORT_LOG */
4747

4848
/**
49-
* Implementation of jerry_port_get_time_zone.
49+
* Implementation of jerry_port_get_local_tza.
5050
*
51-
* @return true - if success
51+
* @return 0, as we live in UTC.
5252
*/
53-
bool
54-
jerry_port_get_time_zone (jerry_time_zone_t *tz_p) /**< timezone pointer */
53+
double
54+
jerry_port_get_local_tza (double js_time_ms, bool is_utc)
5555
{
56-
tz_p->offset = 0;
57-
tz_p->daylight_saving_time = 0;
58-
return true;
59-
} /* jerry_port_get_time_zone */
56+
return 0;
57+
} /* jerry_port_get_local_tza */
6058

6159
/**
6260
* Implementation of jerry_port_get_current_time.

targets/nuttx-stm32f4/jerry_main.c

+6-9
Original file line numberDiff line numberDiff line change
@@ -492,19 +492,16 @@ jerry_port_log (jerry_log_level_t level, /**< log level */
492492
} /* jerry_port_log */
493493

494494
/**
495-
* Dummy function to get the time zone.
495+
* Dummy function to get the time zone adjustment.
496496
*
497-
* @return true
497+
* @return 0
498498
*/
499-
bool
500-
jerry_port_get_time_zone (jerry_time_zone_t *tz_p)
499+
double
500+
jerry_port_get_local_tza (double js_time_ms, bool is_utc)
501501
{
502502
/* We live in UTC. */
503-
tz_p->offset = 0;
504-
tz_p->daylight_saving_time = 0;
505-
506-
return true;
507-
} /* jerry_port_get_time_zone */
503+
return 0;
504+
} /* jerry_port_get_local_tza */
508505

509506
/**
510507
* Dummy function to get the current time.

targets/tizenrt-artik053/apps/jerryscript/jerry_main.c

+6-9
Original file line numberDiff line numberDiff line change
@@ -474,19 +474,16 @@ jerry_port_log (jerry_log_level_t level, /**< log level */
474474
} /* jerry_port_log */
475475

476476
/**
477-
* Dummy function to get the time zone.
477+
* Dummy function to get the time zone adjustment.
478478
*
479-
* @return true
479+
* @return 0
480480
*/
481-
bool
482-
jerry_port_get_time_zone (jerry_time_zone_t *tz_p)
481+
double
482+
jerry_port_get_local_tza (double js_time_ms, bool is_utc)
483483
{
484484
/* We live in UTC. */
485-
tz_p->offset = 0;
486-
tz_p->daylight_saving_time = 0;
487-
488-
return true;
489-
} /* jerry_port_get_time_zone */
485+
return 0;
486+
} /* jerry_port_get_local_tza */
490487

491488
/**
492489
* Dummy function to get the current time.

0 commit comments

Comments
 (0)