2018-02-05 06:25:19 +01:00
|
|
|
<template>
|
2023-04-08 02:01:42 +02:00
|
|
|
<time :title="absolute">
|
2023-06-24 03:33:37 +02:00
|
|
|
<template v-if="invalid">{{ i18n.ts._ago.invalid }}</template>
|
|
|
|
<template v-else-if="mode === 'relative'">{{ relative }}</template>
|
2023-04-08 02:01:42 +02:00
|
|
|
<template v-else-if="mode === 'absolute'">{{ absolute }}</template>
|
|
|
|
<template v-else-if="mode === 'detail'"
|
|
|
|
>{{ absolute }} ({{ relative }})</template
|
|
|
|
>
|
|
|
|
</time>
|
2018-02-05 06:25:19 +01:00
|
|
|
</template>
|
2016-12-28 23:49:51 +01:00
|
|
|
|
2022-01-15 23:47:28 +01:00
|
|
|
<script lang="ts" setup>
|
2023-06-24 03:33:37 +02:00
|
|
|
import { onMounted, onUnmounted } from "vue";
|
2023-04-08 02:01:42 +02:00
|
|
|
import { i18n } from "@/i18n";
|
2023-06-24 03:33:37 +02:00
|
|
|
import { dateTimeFormat } from "@/scripts/intl-const";
|
2023-04-08 02:01:42 +02:00
|
|
|
|
|
|
|
const props = withDefaults(
|
|
|
|
defineProps<{
|
2023-06-24 03:33:37 +02:00
|
|
|
time: Date | string | number | null;
|
|
|
|
origin?: Date | null;
|
2023-06-19 05:34:57 +02:00
|
|
|
mode?: "relative" | "absolute" | "detail";
|
2023-04-08 02:01:42 +02:00
|
|
|
}>(),
|
|
|
|
{
|
|
|
|
mode: "relative",
|
2023-07-06 03:28:27 +02:00
|
|
|
},
|
2023-04-08 02:01:42 +02:00
|
|
|
);
|
2022-01-15 23:47:28 +01:00
|
|
|
|
2023-04-08 02:01:42 +02:00
|
|
|
const _time =
|
2023-06-24 03:33:37 +02:00
|
|
|
props.time == null
|
|
|
|
? NaN
|
|
|
|
: typeof props.time === "number"
|
|
|
|
? props.time
|
|
|
|
: (props.time instanceof Date
|
|
|
|
? props.time
|
|
|
|
: new Date(props.time)
|
|
|
|
).getTime();
|
|
|
|
const invalid = Number.isNaN(_time);
|
|
|
|
const absolute = !invalid ? dateTimeFormat.format(_time) : i18n.ts._ago.invalid;
|
2018-06-10 01:03:02 +02:00
|
|
|
|
2023-06-24 03:33:37 +02:00
|
|
|
let now = $ref((props.origin ?? new Date()).getTime());
|
|
|
|
const relative = $computed<string>(() => {
|
|
|
|
if (props.mode === "absolute") return ""; // absoluteではrelativeを使わないので計算しない
|
|
|
|
if (invalid) return i18n.ts._ago.invalid;
|
|
|
|
|
2023-07-17 00:32:32 +02:00
|
|
|
const ago = (now - _time) / 1000; /* ms */
|
2023-04-08 02:01:42 +02:00
|
|
|
return ago >= 31536000
|
|
|
|
? i18n.t("_ago.yearsAgo", { n: Math.round(ago / 31536000).toString() })
|
|
|
|
: ago >= 2592000
|
|
|
|
? i18n.t("_ago.monthsAgo", { n: Math.round(ago / 2592000).toString() })
|
|
|
|
: ago >= 604800
|
|
|
|
? i18n.t("_ago.weeksAgo", { n: Math.round(ago / 604800).toString() })
|
|
|
|
: ago >= 86400
|
|
|
|
? i18n.t("_ago.daysAgo", { n: Math.round(ago / 86400).toString() })
|
|
|
|
: ago >= 3600
|
|
|
|
? i18n.t("_ago.hoursAgo", { n: Math.round(ago / 3600).toString() })
|
|
|
|
: ago >= 60
|
|
|
|
? i18n.t("_ago.minutesAgo", { n: (~~(ago / 60)).toString() })
|
|
|
|
: ago >= 10
|
|
|
|
? i18n.t("_ago.secondsAgo", { n: (~~(ago % 60)).toString() })
|
|
|
|
: ago >= -1
|
|
|
|
? i18n.ts._ago.justNow
|
|
|
|
: i18n.ts._ago.future;
|
2018-02-13 05:49:48 +01:00
|
|
|
});
|
2022-01-15 23:47:28 +01:00
|
|
|
|
2023-06-24 03:33:37 +02:00
|
|
|
let tickId: number;
|
|
|
|
|
2022-01-15 23:47:28 +01:00
|
|
|
function tick() {
|
2023-06-24 03:33:37 +02:00
|
|
|
const _now = new Date().getTime();
|
2023-07-17 00:32:32 +02:00
|
|
|
const agoPrev = (now - _time) / 1000; /* ms */ // 現状のinterval
|
2022-01-15 23:47:28 +01:00
|
|
|
|
2023-06-24 03:33:37 +02:00
|
|
|
now = _now;
|
2022-01-15 23:47:28 +01:00
|
|
|
|
2023-07-17 00:32:32 +02:00
|
|
|
const ago = (now - _time) / 1000; /* ms */ // 次のinterval
|
2023-06-24 03:33:37 +02:00
|
|
|
const prev = agoPrev < 60 ? 10000 : agoPrev < 3600 ? 60000 : 180000;
|
|
|
|
const next = ago < 60 ? 10000 : ago < 3600 ? 60000 : 180000;
|
2022-01-15 23:47:28 +01:00
|
|
|
|
2023-06-24 03:33:37 +02:00
|
|
|
if (!tickId) {
|
|
|
|
tickId = window.setInterval(tick, next);
|
|
|
|
} else if (prev < next) {
|
|
|
|
window.clearInterval(tickId);
|
|
|
|
tickId = window.setInterval(tick, next);
|
|
|
|
}
|
|
|
|
}
|
2022-01-15 23:47:28 +01:00
|
|
|
|
2023-06-24 03:33:37 +02:00
|
|
|
if (
|
|
|
|
!invalid &&
|
|
|
|
props.origin === null &&
|
|
|
|
(props.mode === "relative" || props.mode === "detail")
|
|
|
|
) {
|
|
|
|
onMounted(() => {
|
|
|
|
tick();
|
|
|
|
});
|
2022-01-15 23:47:28 +01:00
|
|
|
onUnmounted(() => {
|
2023-06-24 03:33:37 +02:00
|
|
|
if (tickId) window.clearInterval(tickId);
|
2022-01-15 23:47:28 +01:00
|
|
|
});
|
|
|
|
}
|
2018-02-05 06:25:19 +01:00
|
|
|
</script>
|