diff --git a/frontend_tests/node_tests/timerender.js b/frontend_tests/node_tests/timerender.js index c2d7fe8e9e..0357b813b6 100644 --- a/frontend_tests/node_tests/timerender.js +++ b/frontend_tests/node_tests/timerender.js @@ -221,33 +221,21 @@ run_test("absolute_time_24_hour", () => { run_test("get_full_datetime", () => { const time = new Date(1495141973000); // 2017/5/18 9:12:53 PM (UTC+0) - let expected_date = "Thursday, May 18, 2017"; - let expected_time = "9:12:53 PM Coordinated Universal Time"; - assert.deepEqual(timerender.get_full_datetime(time), { - date: expected_date, - time: expected_time, - }); + let expected = "translated: 5/18/2017 at 9:12:53 PM UTC"; + assert.equal(timerender.get_full_datetime(time), expected); // test 24 hour time setting. page_params.twenty_four_hour_time = true; - expected_time = "21:12:53 Coordinated Universal Time"; - assert.deepEqual(timerender.get_full_datetime(time), { - date: expected_date, - time: expected_time, - }); + expected = "translated: 5/18/2017 at 21:12:53 UTC"; + assert.equal(timerender.get_full_datetime(time), expected); - // Test year not shown if current. - const current_year = new Date().getFullYear(); - time.setFullYear(current_year); - expected_date = time.toLocaleDateString(undefined, { - weekday: "long", - month: "long", - day: "numeric", - }); - assert.deepEqual(timerender.get_full_datetime(time), { - date: expected_date, - time: expected_time, - }); + page_params.twenty_four_hour_time = false; + + // Test the GMT[+-]x:y logic. + process.env.TZ = "Asia/Kolkata"; + expected = "translated: 5/19/2017 at 2:42:53 AM (UTC+5.5)"; + assert.equal(timerender.get_full_datetime(time), expected); + delete process.env.TZ; }); run_test("last_seen_status_from_date", () => { diff --git a/static/js/timerender.js b/static/js/timerender.js index 323728b667..1054cdc112 100644 --- a/static/js/timerender.js +++ b/static/js/timerender.js @@ -307,21 +307,29 @@ export const absolute_time = (function () { })(); export function get_full_datetime(time) { - const date_string_options = {weekday: "long", month: "long", day: "numeric"}; - const time_string_options = {timeStyle: "full"}; + // Convert to number of hours ahead/behind UTC. + // The sign of getTimezoneOffset() is reversed wrt + // the conventional meaning of UTC+n / UTC-n + const tz_offset = -time.getTimezoneOffset() / 60; + + const time_options = {timeStyle: "long"}; if (page_params.twenty_four_hour_time) { - time_string_options.hourCycle = "h24"; + time_options.hourCycle = "h24"; } - const current_date = new Date(); - if (time.getFullYear() !== current_date.getFullYear()) { - // Show year only if not current year. - date_string_options.year = "numeric"; - } + const date_string = time.toLocaleDateString(); + let time_string = time.toLocaleTimeString(undefined, time_options); - return { - date: time.toLocaleDateString(page_params.request_language, date_string_options), - time: time.toLocaleTimeString(page_params.request_language, time_string_options), - }; + // In some rare cases where user's locale and timeZone doesn't suit, + // for eg. en-US with Indian timeZone gives GMT+5:30. We want to + // avoid showing something like: 27/6/21 at 12:00 GMT+x:y (UTC+N). + time_string = time_string.replace(/ GMT[+-][\d:]*/, ""); + + const tz_offset_sign = tz_offset > 0 ? "+" : "-"; + const tz_offset_str = time_string.includes("UTC") ? "" : ` (UTC${tz_offset_sign}${tz_offset})`; + + time_string = time_string + tz_offset_str; + + return $t({defaultMessage: "{date} at {time}"}, {date: date_string, time: time_string}); } diff --git a/static/js/tippyjs.js b/static/js/tippyjs.js index 0b1e73570b..1aac9dd747 100644 --- a/static/js/tippyjs.js +++ b/static/js/tippyjs.js @@ -154,7 +154,6 @@ export function initialize() { delegate("body", { target: ".message_time", - allowHTML: true, placement: "top", appendTo: () => document.body, onShow(instance) { @@ -162,8 +161,7 @@ export function initialize() { const row = time_elem.closest(".message_row"); const message = message_lists.current.get(rows.id(row)); const time = new Date(message.timestamp * 1000); - const full_datetime = timerender.get_full_datetime(time); - instance.setContent(full_datetime.date + "
" + full_datetime.time); + instance.setContent(timerender.get_full_datetime(time)); }, onHidden(instance) { instance.destroy();