Files
Thing/src/modules/devtools/tools/TimestampTools.vue
T
2026-09-12 11:05:26 +08:00

139 lines
4.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { computed, onUnmounted, ref } from 'vue'
import { Clock } from '@lucide/vue'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Button } from '@/components/ui/button'
import { Separator } from '@/components/ui/separator'
import Segmented from '../components/Segmented.vue'
import ResultArea from '../components/ResultArea.vue'
type Unit = 'auto' | 's' | 'ms'
const unit = ref<Unit>('auto')
const numberInput = ref('')
const dateInput = ref('')
const toNumber = (v: string): number | null => {
const n = Number(v.trim())
return Number.isFinite(n) ? n : null
}
/** 自动识别:13 位(>1e11)视为毫秒,10 位(>1e8)视为秒,其他按数值范围推断 */
function resolveUnit(n: number): 's' | 'ms' {
if (unit.value !== 'auto') return unit.value
if (Math.abs(n) >= 1e11) return 'ms'
return 's'
}
const unixToDate = (n: number, u: 's' | 'ms'): Date =>
new Date(u === 's' ? n * 1000 : n)
const formatLocal = (d: Date): string => {
const pad = (x: number) => String(x).padStart(2, '0')
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`
}
const formatUtc = (d: Date): string => {
const pad = (x: number) => String(x).padStart(2, '0')
return `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())} ${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}:${pad(d.getUTCSeconds())} UTC`
}
const fromNumber = computed<{ local: string; utc: string; iso: string; ts: string; unitUsed: 's' | 'ms' } | null>(() => {
const n = toNumber(numberInput.value)
if (n === null) return null
const u = resolveUnit(n)
const d = unixToDate(n, u)
if (Number.isNaN(d.getTime())) return null
return {
local: formatLocal(d),
utc: formatUtc(d),
iso: d.toISOString(),
ts: String(n),
unitUsed: u
}
})
const fromDate = computed<string>(() => {
if (!dateInput.value) return ''
const d = new Date(dateInput.value)
if (Number.isNaN(d.getTime())) return ''
// 日期输入统一同时给出秒与毫秒
return `${Math.floor(d.getTime() / 1000)}(秒)\n${d.getTime()}(毫秒)`
})
// ===== 当前时间戳 =====
const nowTick = ref(0)
const timer = window.setInterval(() => (nowTick.value++), 1000)
onUnmounted(() => window.clearInterval(timer))
const now = computed(() => {
void nowTick.value
const d = new Date()
return {
s: String(Math.floor(d.getTime() / 1000)),
ms: String(d.getTime()),
local: formatLocal(d)
}
})
function copy(text: string) {
void navigator.clipboard.writeText(text)
}
</script>
<template>
<div class="flex flex-col gap-4">
<Segmented
v-model="unit"
label="单位"
:options="[
{ value: 'auto', label: '自动' },
{ value: 's', label: '秒' },
{ value: 'ms', label: '毫秒' }
]"
/>
<!-- 时间戳 时间 -->
<div class="flex flex-col gap-3">
<div class="flex flex-col gap-1.5">
<Label class="text-xs">Unix 时间戳 日期时间</Label>
<Input v-model="numberInput" placeholder="例如 1757419200 或 1757419200000" class="font-mono text-sm" />
</div>
<template v-if="fromNumber">
<ResultArea :text="fromNumber.local" label="本地时间" placeholder="本地时间" />
<ResultArea :text="fromNumber.utc" label="UTC 时间" placeholder="UTC 时间" />
<ResultArea :text="fromNumber.iso" label="ISO 8601" placeholder="ISO 8601" />
<p class="text-xs text-muted-foreground">已识别为{{ fromNumber.unitUsed === 's' ? '秒级' : '毫秒级' }}时间戳</p>
</template>
<p v-else-if="numberInput" class="text-xs text-destructive">请输入有效的数字时间戳</p>
</div>
<Separator />
<!-- 时间 时间戳 -->
<div class="flex flex-col gap-1.5">
<Label class="text-xs">日期时间 Unix 时间戳</Label>
<Input v-model="dateInput" type="datetime-local" class="font-mono text-sm" />
<ResultArea v-if="fromDate" :text="fromDate" label="结果" placeholder="结果" />
</div>
<Separator />
<!-- 当前时间戳 -->
<div class="flex flex-col gap-2">
<Label class="text-xs">当前时间{{ now.local }}</Label>
<div class="flex items-center gap-2 flex-wrap">
<Button size="sm" variant="outline" class="h-8 font-mono text-xs gap-1.5" @click="copy(now.s)">
<Clock class="size-3.5" />
{{ now.s }}点击复制
</Button>
<Button size="sm" variant="outline" class="h-8 font-mono text-xs gap-1.5" @click="copy(now.ms)">
<Clock class="size-3.5" />
{{ now.ms }}毫秒点击复制
</Button>
</div>
</div>
</div>
</template>