backups: show timestamps in the site timezone
Backup timestamps read wrong because of two faults stacked, which is why it
looked like a single offset.
The API serialised naive ISO ("2026-08-07T12:00:00"), with nothing saying the
value was UTC. JavaScript's new Date() parses that as BROWSER-LOCAL, so every
timestamp shifted by the viewer's offset before any timezone formatting ran.
Every datetime this plugin stores is naive UTC, so the wire format now carries
a trailing Z.
The history view then formatted with toLocaleString(), i.e. the viewer's zone,
ignoring the site_timezone setting entirely. It now loads that setting and
formats through the shared formatInZone helper, matching NotificationsList.
The panel list label is built server-side with strftime, so a client cannot
correct it afterwards. It now converts to the site zone using the same Setting
lookup the notifications plugin uses - without that it showed UTC, four hours
out at West Jefferson.
Tests cover the wire format and that 16:30Z renders as 12:30 in
America/New_York.
This commit is contained in:
@@ -95,7 +95,8 @@
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import api from '@/api'
|
||||
import api, { settingsApi } from '@/api'
|
||||
import { formatInZone, DEFAULT_TZ } from '@/utils/datetime'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
@@ -111,11 +112,13 @@ const diffs = ref({})
|
||||
const assetname = ref('')
|
||||
const loading = ref(true)
|
||||
const error = ref('')
|
||||
// Timestamps are stored UTC and must show in the SITE's zone, not the viewer's,
|
||||
// so a remote admin and someone at the bay read the same wall clock.
|
||||
const siteTimezone = ref(DEFAULT_TZ)
|
||||
|
||||
function formatWhen(value) {
|
||||
if (!value) return 'unknown'
|
||||
const d = new Date(value)
|
||||
return isNaN(d) ? value : d.toLocaleString()
|
||||
return formatInZone(value, siteTimezone.value, { second: '2-digit' }) || value
|
||||
}
|
||||
|
||||
function display(value) {
|
||||
@@ -124,6 +127,16 @@ function display(value) {
|
||||
return String(value)
|
||||
}
|
||||
|
||||
async function loadTimezone() {
|
||||
try {
|
||||
const response = await settingsApi.get('site_timezone')
|
||||
const value = response?.data?.data?.value
|
||||
if (value) siteTimezone.value = value
|
||||
} catch (e) {
|
||||
// Keep the default zone; a missing setting must not blank the page.
|
||||
}
|
||||
}
|
||||
|
||||
async function load() {
|
||||
loading.value = true
|
||||
error.value = ''
|
||||
@@ -183,7 +196,10 @@ async function download(rev, fmt) {
|
||||
URL.revokeObjectURL(link.href)
|
||||
}
|
||||
|
||||
onMounted(load)
|
||||
onMounted(async () => {
|
||||
await loadTimezone()
|
||||
await load()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user