Add Discord timestamp tool with copy + reverse conversion
This commit is contained in:
@@ -119,5 +119,14 @@
|
||||
"description": "Convert a formatted time duration (HH:MM:SS) into a decimal hour value.",
|
||||
"shortDescription": "Convert human time to decimal time",
|
||||
"longDescription": "Convert a formatted time string (HH:MM:SS or HH:MM) into its decimal-hour equivalent. Hours can be any positive number, while minutes and seconds accept values from 0-59 and can be single or double digits (e.g., '12:5' or '12:05'). This function interprets hours, minutes, and seconds, then calculates the total duration as a single decimal value. It is useful for productivity tracking, payroll calculations, time-based billing, data analysis, or any workflow that requires converting human-readable time into a numerical format that can be easily summed, compared, or processed. For example, '03:26:00' becomes 3.43 hours, and '12:5' becomes 12.08 hours."
|
||||
},
|
||||
"discordTimestamp": {
|
||||
"name": "Discord Timestamp Generator",
|
||||
"description": "Generate Discord formatted timestamps from date and time",
|
||||
"shortDescription": "Generate Discord timestamps",
|
||||
"toolInfo": {
|
||||
"title": "What is a Discord Timestamp",
|
||||
"description": "Discord timestamps allow you to display dynamic dates and times that automatically adjust to each user's local timezone. This tool converts a date and time into the special Discord timestamp format."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
function convertInput(input: string) {
|
||||
const trimmed = input.trim();
|
||||
|
||||
// Case 1: Discord timestamp → normal date
|
||||
const match = trimmed.match(/^<t:(\d+):[A-Za-z]>$/);
|
||||
if (match) {
|
||||
const unix = Number(match[1]);
|
||||
const date = new Date(unix * 1000);
|
||||
if (!isNaN(date.getTime())) {
|
||||
return date.toISOString().replace('T', ' ').slice(0, 16);
|
||||
}
|
||||
}
|
||||
|
||||
// Case 2: normal date → Discord timestamp
|
||||
const date = new Date(trimmed);
|
||||
if (isNaN(date.getTime())) return 'Invalid date/time';
|
||||
const unix = Math.floor(date.getTime() / 1000);
|
||||
return `<t:${unix}:F>`;
|
||||
}
|
||||
|
||||
export default function DiscordTimestamp() {
|
||||
const [value, setValue] = useState('');
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
const result = value ? convertInput(value) : '';
|
||||
|
||||
const handleCopy = async () => {
|
||||
if (!result || result === 'Invalid date/time') return;
|
||||
try {
|
||||
await navigator.clipboard.writeText(result);
|
||||
setCopied(true);
|
||||
setTimeout(() => setCopied(false), 1200);
|
||||
} catch (e) {
|
||||
console.error('Copy failed', e);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex gap-3 items-stretch">
|
||||
<textarea
|
||||
placeholder="Enter date like: 2026-02-23 18:30"
|
||||
value={value}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
className="flex-1 min-h-[140px] p-3 rounded-lg bg-neutral-900 text-white border border-neutral-700 placeholder-neutral-400 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
|
||||
<div className="flex-1 relative flex">
|
||||
<textarea
|
||||
readOnly
|
||||
value={value ? result : 'Enter a date to generate timestamp'}
|
||||
className="flex-1 w-full min-h-[140px] p-3 pr-12 pt-10 rounded-lg bg-neutral-900 text-white border border-neutral-700 focus:outline-none"
|
||||
/>
|
||||
|
||||
<button
|
||||
onClick={handleCopy}
|
||||
disabled={!result || result === 'Invalid date/time'}
|
||||
className="absolute top-2 right-2 w-8 h-8 flex items-center justify-center rounded-md bg-neutral-800 border border-neutral-700 hover:bg-neutral-700 text-neutral-200 disabled:opacity-40"
|
||||
title="Copy to clipboard"
|
||||
>
|
||||
{copied ? '✓' : '📋'}
|
||||
</button>
|
||||
{copied && (
|
||||
<span className="absolute top-3 right-12 text-xs text-green-400">
|
||||
Copied
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { defineTool } from '@tools/defineTool';
|
||||
import { lazy } from 'react';
|
||||
const DiscordTimestamp = lazy(() => import('./index'));
|
||||
|
||||
export const tool = defineTool('time', {
|
||||
path: 'discord-timestamp',
|
||||
component: DiscordTimestamp,
|
||||
icon: 'mdi:clock',
|
||||
keywords: ['discord', 'timestamp', 'time'],
|
||||
i18n: {
|
||||
name: 'time:discordTimestamp.name',
|
||||
description: 'time:discordTimestamp.description',
|
||||
shortDescription: 'time:discordTimestamp.shortDescription'
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
// Converts a Date object to a Discord timestamp string
|
||||
export function generateDiscordTimestamp(date: Date, format: string = 'F') {
|
||||
const unix = Math.floor(date.getTime() / 1000);
|
||||
return `<t:${unix}:${format}>`;
|
||||
}
|
||||
|
||||
// Attempts to parse a Discord timestamp like <t:1712345678:F>
|
||||
// Returns a Date object or null if invalid
|
||||
export function parseDiscordTimestamp(input: string): Date | null {
|
||||
const match = input.trim().match(/^<t:(\d+):[A-Za-z]>$/);
|
||||
if (!match) return null;
|
||||
|
||||
const unix = Number(match[1]);
|
||||
const date = new Date(unix * 1000);
|
||||
return isNaN(date.getTime()) ? null : date;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export interface DiscordTimestampInput {
|
||||
date: string;
|
||||
}
|
||||
|
||||
export interface DiscordTimestampResult {
|
||||
value: string;
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import { tool as convertSecondsToTime } from './convert-seconds-to-time/meta';
|
||||
import { tool as convertTimetoSeconds } from './convert-time-to-seconds/meta';
|
||||
import { tool as truncateClockTime } from './truncate-clock-time/meta';
|
||||
import { tool as checkLeapYear } from './check-leap-years/meta';
|
||||
import { tool as discordTimestamp } from './discord-timestamp/meta';
|
||||
|
||||
export const timeTools = [
|
||||
daysDoHours,
|
||||
@@ -19,5 +20,6 @@ export const timeTools = [
|
||||
timeCrontabGuru,
|
||||
checkLeapYear,
|
||||
timeConvertUnixToDate,
|
||||
timeConvertTimeToDecimal
|
||||
timeConvertTimeToDecimal,
|
||||
discordTimestamp
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user