From f29049af7e44f72f40447ad5d63233140c4267a4 Mon Sep 17 00:00:00 2001 From: "Krueger, John" Date: Tue, 3 Feb 2026 09:38:27 -0500 Subject: [PATCH 1/2] use ET timezone consistently in the admin UI --- .../admin-ui/app/utils/data-tables-helpers.js | 2 +- src/api-umbrella/utils/time.lua | 7 +++--- test/admin_ui/test_stats_logs.rb | 22 +++++++++++++++++++ test/apis/admin/stats/test_logs.rb | 22 +++++++++++++++++++ 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/src/api-umbrella/admin-ui/app/utils/data-tables-helpers.js b/src/api-umbrella/admin-ui/app/utils/data-tables-helpers.js index 984d56885..ccf98dea7 100644 --- a/src/api-umbrella/admin-ui/app/utils/data-tables-helpers.js +++ b/src/api-umbrella/admin-ui/app/utils/data-tables-helpers.js @@ -83,7 +83,7 @@ export default { renderTime(value, type) { if(type === 'display' && value && value !== '-') { - return moment(value).format('YYYY-MM-DD HH:mm:ss'); + return moment(value).tz('America/New_York').format('YYYY-MM-DD HH:mm:ss z'); } return value; diff --git a/src/api-umbrella/utils/time.lua b/src/api-umbrella/utils/time.lua index 033c56cbb..2aa4c91f3 100644 --- a/src/api-umbrella/utils/time.lua +++ b/src/api-umbrella/utils/time.lua @@ -7,7 +7,6 @@ local null = ngx.null local date = icu_date.new() local format_iso8601 = icu_date.formats.pattern("yyyy-MM-dd'T'HH:mm:ssZZZZZ") local format_iso8601_ms = icu_date.formats.pattern("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ") -local format_csv = icu_date.formats.pattern("yyyy-MM-dd HH:mm:ss") local format_postgres = icu_date.formats.pattern("yyyy-MM-dd HH:mm:ss.SSSSxxx") local format_postgres_no_millis = icu_date.formats.pattern("yyyy-MM-dd HH:mm:ssxxx") @@ -80,7 +79,7 @@ function _M.timestamp_ms_to_csv(timestamp) end date:set_millis(timestamp) - return date:format(format_csv) + return date:format(format_iso8601_ms) end function _M.iso8601_to_timestamp(string) @@ -116,7 +115,7 @@ function _M.iso8601_to_csv(string) end date:parse(format_iso8601, string) - return date:format(format_csv) + return date:format(format_iso8601) end function _M.iso8601_ms_to_csv(string) @@ -125,7 +124,7 @@ function _M.iso8601_ms_to_csv(string) end date:parse(format_iso8601_ms, string) - return date:format(format_csv) + return date:format(format_iso8601_ms) end function _M.opensearch_to_csv(value) diff --git a/test/admin_ui/test_stats_logs.rb b/test/admin_ui/test_stats_logs.rb index 17949f1d8..4ba9f6bfa 100644 --- a/test/admin_ui/test_stats_logs.rb +++ b/test/admin_ui/test_stats_logs.rb @@ -305,4 +305,26 @@ def test_filter_options "is not null", ] end + + def test_table_displays_time_in_eastern_timezone + FactoryBot.create(:log_item, :request_at => Time.parse("2015-01-16T06:06:28.816Z").utc, :request_method => "OPTIONS") + LogItem.refresh_indices! + + admin_login + visit "/admin/#/stats/logs?search=&start_at=2015-01-12&end_at=2015-01-18&interval=day" + refute_selector(".busy-blocker") + + assert_text("2015-01-16 01:06:28 EST") + end + + def test_table_displays_time_in_eastern_timezone_during_dst + FactoryBot.create(:log_item, :request_at => Time.parse("2015-07-16T06:06:28.816Z").utc, :request_method => "OPTIONS") + LogItem.refresh_indices! + + admin_login + visit "/admin/#/stats/logs?search=&start_at=2015-07-12&end_at=2015-07-18&interval=day" + refute_selector(".busy-blocker") + + assert_text("2015-07-16 02:06:28 EDT") + end end diff --git a/test/apis/admin/stats/test_logs.rb b/test/apis/admin/stats/test_logs.rb index fc08ec336..756c0d5ab 100644 --- a/test/apis/admin/stats/test_logs.rb +++ b/test/apis/admin/stats/test_logs.rb @@ -226,4 +226,26 @@ def test_no_results_non_existent_indices "recordsTotal" => 0, }, data) end + + def test_csv_timestamps_in_iso8601_utc_format + FactoryBot.create(:log_item, :request_at => Time.parse("2015-01-16T06:06:28.816Z").utc, :request_user_agent => unique_test_id) + LogItem.refresh_indices! + + response = Typhoeus.get("https://127.0.0.1:9081/admin/stats/logs.csv", http_options.deep_merge(admin_session).deep_merge({ + :params => { + "start_at" => "2015-01-13", + "end_at" => "2015-01-18", + "interval" => "day", + "start" => "0", + "length" => "10", + }, + })) + + assert_response_code(200, response) + + csv = CSV.parse(response.body) + assert_equal(2, csv.length) + assert_equal("Time", csv[0][0]) + assert_equal("2015-01-16T06:06:28.816Z", csv[1][0]) + end end From 0e3cdf1196a96f6d9f780c36c77ff7ab58d1523e Mon Sep 17 00:00:00 2001 From: "Krueger, John" Date: Thu, 5 Feb 2026 10:35:24 -0500 Subject: [PATCH 2/2] use session TZ; fix tests; change to using MST in new tests --- .../admin-ui/app/components/admins/index-table.js | 4 ++-- .../admin-ui/app/components/api-users/index-table.js | 2 +- .../app/components/stats/logs/results-table.js | 6 +++++- .../app/components/stats/users/results-table.js | 8 ++++++-- .../admin-ui/app/utils/data-tables-helpers.js | 12 +++++++----- test/admin_ui/test_stats_logs.rb | 8 ++++---- test/apis/admin/stats/test_users.rb | 8 ++++---- 7 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/api-umbrella/admin-ui/app/components/admins/index-table.js b/src/api-umbrella/admin-ui/app/components/admins/index-table.js index 61b062009..ac5b953e1 100644 --- a/src/api-umbrella/admin-ui/app/components/admins/index-table.js +++ b/src/api-umbrella/admin-ui/app/components/admins/index-table.js @@ -65,7 +65,7 @@ export default class IndexTable extends Component { name: 'Last Signed In', title: t('Last Signed In'), defaultContent: '-', - render: DataTablesHelpers.renderTime, + render: DataTablesHelpers.renderTime(this.session.data.authenticated.analytics_timezone), }, { data: 'created_at', @@ -73,7 +73,7 @@ export default class IndexTable extends Component { name: 'Created', title: t('Created'), defaultContent: '-', - render: DataTablesHelpers.renderTime, + render: DataTablesHelpers.renderTime(this.session.data.authenticated.analytics_timezone), }, ], }); diff --git a/src/api-umbrella/admin-ui/app/components/api-users/index-table.js b/src/api-umbrella/admin-ui/app/components/api-users/index-table.js index 4c439fe37..9f53a4a61 100644 --- a/src/api-umbrella/admin-ui/app/components/api-users/index-table.js +++ b/src/api-umbrella/admin-ui/app/components/api-users/index-table.js @@ -58,7 +58,7 @@ export default class IndexTable extends Component { type: 'date', title: 'Created', defaultContent: '-', - render: DataTablesHelpers.renderTime, + render: DataTablesHelpers.renderTime(this.session.data.authenticated.analytics_timezone), }, { data: 'registration_source', diff --git a/src/api-umbrella/admin-ui/app/components/stats/logs/results-table.js b/src/api-umbrella/admin-ui/app/components/stats/logs/results-table.js index 8e168c2d6..d2e689c65 100644 --- a/src/api-umbrella/admin-ui/app/components/stats/logs/results-table.js +++ b/src/api-umbrella/admin-ui/app/components/stats/logs/results-table.js @@ -1,6 +1,7 @@ // eslint-disable-next-line ember/no-classic-components import Component from '@ember/component'; import { action, computed } from '@ember/object'; +import { inject } from '@ember/service'; import { observes } from '@ember-decorators/object'; import Logs from 'api-umbrella-admin-ui/models/stats/logs'; import DataTablesHelpers from 'api-umbrella-admin-ui/utils/data-tables-helpers'; @@ -22,6 +23,9 @@ marked.use({ export default class ResultsTable extends Component { tagName = ''; + @inject('session') + session; + @action didInsert(element) { this.table = $(element).find('table').DataTable({ @@ -58,7 +62,7 @@ export default class ResultsTable extends Component { type: 'date', title: 'Time', defaultContent: '-', - render: DataTablesHelpers.renderTime, + render: DataTablesHelpers.renderTime(this.session.data.authenticated.analytics_timezone), }, { data: 'request_method', diff --git a/src/api-umbrella/admin-ui/app/components/stats/users/results-table.js b/src/api-umbrella/admin-ui/app/components/stats/users/results-table.js index f62ff806a..c3bf13e2c 100644 --- a/src/api-umbrella/admin-ui/app/components/stats/users/results-table.js +++ b/src/api-umbrella/admin-ui/app/components/stats/users/results-table.js @@ -1,6 +1,7 @@ // eslint-disable-next-line ember/no-classic-components import Component from '@ember/component'; import { action, computed } from '@ember/object'; +import { inject } from '@ember/service'; import { observes } from '@ember-decorators/object'; import DataTablesHelpers from 'api-umbrella-admin-ui/utils/data-tables-helpers'; import classic from 'ember-classic-decorator'; @@ -14,6 +15,9 @@ import numeral from 'numeral'; export default class ResultsTable extends Component { tagName = ''; + @inject('session') + session; + @action didInsert(element) { this.table = $(element).find('table').DataTable({ @@ -60,7 +64,7 @@ export default class ResultsTable extends Component { type: 'date', title: 'Signed Up', defaultContent: '-', - render: DataTablesHelpers.renderTime, + render: DataTablesHelpers.renderTime(this.session.data.authenticated.analytics_timezone), }, { data: 'hits', @@ -79,7 +83,7 @@ export default class ResultsTable extends Component { type: 'date', title: 'Last Request', defaultContent: '-', - render: DataTablesHelpers.renderTime, + render: DataTablesHelpers.renderTime(this.session.data.authenticated.analytics_timezone), }, { data: 'use_description', diff --git a/src/api-umbrella/admin-ui/app/utils/data-tables-helpers.js b/src/api-umbrella/admin-ui/app/utils/data-tables-helpers.js index ccf98dea7..9e4963b50 100644 --- a/src/api-umbrella/admin-ui/app/utils/data-tables-helpers.js +++ b/src/api-umbrella/admin-ui/app/utils/data-tables-helpers.js @@ -81,11 +81,13 @@ export default { } }, - renderTime(value, type) { - if(type === 'display' && value && value !== '-') { - return moment(value).tz('America/New_York').format('YYYY-MM-DD HH:mm:ss z'); - } + renderTime(timezone) { + return function(value, type) { + if(type === 'display' && value && value !== '-') { + return moment(value).tz(timezone).format('YYYY-MM-DD HH:mm:ss z'); + } - return value; + return value; + } }, }; diff --git a/test/admin_ui/test_stats_logs.rb b/test/admin_ui/test_stats_logs.rb index 4ba9f6bfa..25c9f5ccd 100644 --- a/test/admin_ui/test_stats_logs.rb +++ b/test/admin_ui/test_stats_logs.rb @@ -306,7 +306,7 @@ def test_filter_options ] end - def test_table_displays_time_in_eastern_timezone + def test_table_displays_time_in_local_timezone FactoryBot.create(:log_item, :request_at => Time.parse("2015-01-16T06:06:28.816Z").utc, :request_method => "OPTIONS") LogItem.refresh_indices! @@ -314,10 +314,10 @@ def test_table_displays_time_in_eastern_timezone visit "/admin/#/stats/logs?search=&start_at=2015-01-12&end_at=2015-01-18&interval=day" refute_selector(".busy-blocker") - assert_text("2015-01-16 01:06:28 EST") + assert_text("2015-01-15 23:06:28 MST") end - def test_table_displays_time_in_eastern_timezone_during_dst + def test_table_displays_time_in_local_timezone_during_dst FactoryBot.create(:log_item, :request_at => Time.parse("2015-07-16T06:06:28.816Z").utc, :request_method => "OPTIONS") LogItem.refresh_indices! @@ -325,6 +325,6 @@ def test_table_displays_time_in_eastern_timezone_during_dst visit "/admin/#/stats/logs?search=&start_at=2015-07-12&end_at=2015-07-18&interval=day" refute_selector(".busy-blocker") - assert_text("2015-07-16 02:06:28 EDT") + assert_text("2015-07-16 00:06:28 MDT") end end diff --git a/test/apis/admin/stats/test_users.rb b/test/apis/admin/stats/test_users.rb index f57cd654a..d8e95346f 100644 --- a/test/apis/admin/stats/test_users.rb +++ b/test/apis/admin/stats/test_users.rb @@ -96,9 +96,9 @@ def test_csv_download @user1.last_name, @user1.website, @user1.registration_source, - @user1.created_at.utc.strftime("%Y-%m-%d %H:%M:%S"), + @user1.created_at.utc.iso8601, "2", - "2015-01-16 00:00:00", + "2015-01-16T00:00:00Z", @user1.use_description, ], csv[1]) assert_equal([ @@ -107,9 +107,9 @@ def test_csv_download @user2.last_name, @user2.website, @user2.registration_source, - @user2.created_at.utc.strftime("%Y-%m-%d %H:%M:%S"), + @user2.created_at.utc.iso8601, "1", - "2015-01-17 00:00:00", + "2015-01-17T00:00:00Z", @user2.use_description, ], csv[2]) end