mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-08-06 14:05:18 +02:00
Add new tool - epoch converter
This commit is contained in:
parent
d7578e23a5
commit
00b1148e3a
7 changed files with 220 additions and 1 deletions
1
components.d.ts
vendored
1
components.d.ts
vendored
|
@ -77,6 +77,7 @@ declare module '@vue/runtime-core' {
|
|||
EmojiGrid: typeof import('./src/tools/emoji-picker/emoji-grid.vue')['default']
|
||||
EmojiPicker: typeof import('./src/tools/emoji-picker/emoji-picker.vue')['default']
|
||||
Encryption: typeof import('./src/tools/encryption/encryption.vue')['default']
|
||||
EpochConverter: typeof import('./src/tools/epoch-converter/epoch-converter.vue')['default']
|
||||
EtaCalculator: typeof import('./src/tools/eta-calculator/eta-calculator.vue')['default']
|
||||
FavoriteButton: typeof import('./src/components/FavoriteButton.vue')['default']
|
||||
FormatTransformer: typeof import('./src/components/FormatTransformer.vue')['default']
|
||||
|
|
31
src/tools/epoch-converter/epoch-converter.e2e.spec.ts
Normal file
31
src/tools/epoch-converter/epoch-converter.e2e.spec.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
import { expect, test } from '@playwright/test';
|
||||
|
||||
test.describe('Tool - Epoch converter', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/epoch-converter');
|
||||
});
|
||||
|
||||
test('Has correct title', async ({ page }) => {
|
||||
await expect(page).toHaveTitle('Epoch converter - IT Tools');
|
||||
});
|
||||
|
||||
test('Converts epoch to human-readable date', async ({ page }) => {
|
||||
await page.getByPlaceholder('Enter epoch timestamp').fill('1750452480');
|
||||
await page.getByRole('button', { name: 'Convert to Date' }).click();
|
||||
|
||||
await expect(page.getByText('6/23/2025, 12:31:00 PM')).toBeVisible();
|
||||
});
|
||||
|
||||
test('Converts known date to epoch timestamp', async ({ page }) => {
|
||||
await page.getByPlaceholder('YYYY').fill('2025');
|
||||
await page.getByPlaceholder('MM').first().fill('06');
|
||||
await page.getByPlaceholder('DD').fill('20');
|
||||
await page.getByPlaceholder('HH').fill('13');
|
||||
await page.getByPlaceholder('MM').nth(1).fill('48');
|
||||
await page.getByPlaceholder('SS').fill('00');
|
||||
|
||||
await page.getByRole('button', { name: 'Convert to Epoch' }).click();
|
||||
|
||||
await expect(page.getByText('1750452480')).toBeVisible();
|
||||
});
|
||||
});
|
36
src/tools/epoch-converter/epoch-converter.service.test.ts
Normal file
36
src/tools/epoch-converter/epoch-converter.service.test.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
import { dateToEpoch, epochToDate } from './epoch-converter.service';
|
||||
|
||||
describe('epochToDate', () => {
|
||||
it('converts known epoch seconds to correct local date string', () => {
|
||||
const epoch = 1750707060;
|
||||
const expectedDate = '6/23/2025, 12:31:00 PM';
|
||||
const result = epochToDate(epoch);
|
||||
expect(result).toBe(expectedDate);
|
||||
});
|
||||
|
||||
it('throws for invalid string input', () => {
|
||||
expect(() => epochToDate('not-a-number')).toThrowError(TypeError);
|
||||
});
|
||||
|
||||
it('throws for NaN input', () => {
|
||||
expect(() => epochToDate(Number.NaN)).toThrowError(TypeError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('dateToEpoch', () => {
|
||||
it('converts a known date to correct epoch (2025-06-20 13:48:00)', () => {
|
||||
const input = '2025-06-20T13:48:00';
|
||||
const expectedEpoch = 1750452480;
|
||||
const result = dateToEpoch(input);
|
||||
expect(result).toBe(expectedEpoch);
|
||||
});
|
||||
|
||||
it('throws for invalid date string', () => {
|
||||
expect(() => dateToEpoch('not-a-date')).toThrowError(TypeError);
|
||||
});
|
||||
|
||||
it('throws for empty string', () => {
|
||||
expect(() => dateToEpoch('')).toThrowError(TypeError);
|
||||
});
|
||||
});
|
23
src/tools/epoch-converter/epoch-converter.service.ts
Normal file
23
src/tools/epoch-converter/epoch-converter.service.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
// Convert Epoch to Human Readable Date
|
||||
export function epochToDate(epoch: string | number): string {
|
||||
const num = typeof epoch === 'string' ? Number.parseInt(epoch, 10) : epoch;
|
||||
|
||||
if (Number.isNaN(num)) {
|
||||
throw new TypeError('Invalid epoch timestamp');
|
||||
}
|
||||
|
||||
const timestamp = num < 1e12 ? num * 1000 : num;
|
||||
|
||||
return new Date(timestamp).toLocaleString();
|
||||
}
|
||||
|
||||
// Convert Human Readable Date to Epoch
|
||||
export function dateToEpoch(dateString: string): number {
|
||||
const date = new Date(dateString);
|
||||
|
||||
if (Number.isNaN(date.getTime())) {
|
||||
throw new TypeError('Invalid date string');
|
||||
}
|
||||
|
||||
return Math.floor(date.getTime() / 1000);
|
||||
}
|
115
src/tools/epoch-converter/epoch-converter.vue
Normal file
115
src/tools/epoch-converter/epoch-converter.vue
Normal file
|
@ -0,0 +1,115 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { dateToEpoch, epochToDate } from './epoch-converter.service.ts';
|
||||
|
||||
const epochInput = ref('');
|
||||
const dateOutput = ref('');
|
||||
const epochOutput = ref('');
|
||||
const error = ref<string | null>(null);
|
||||
|
||||
const dateParts = ref({
|
||||
year: '',
|
||||
month: '',
|
||||
day: '',
|
||||
hour: '',
|
||||
minute: '',
|
||||
second: '',
|
||||
});
|
||||
|
||||
function convertEpochToDate() {
|
||||
error.value = null;
|
||||
try {
|
||||
dateOutput.value = epochToDate(epochInput.value);
|
||||
}
|
||||
catch (e: any) {
|
||||
error.value = e.message;
|
||||
}
|
||||
}
|
||||
|
||||
function convertDateToEpoch() {
|
||||
error.value = null;
|
||||
try {
|
||||
const { year, month, day, hour, minute, second } = dateParts.value;
|
||||
|
||||
const isoString = `${year}-${pad(month)}-${pad(day)}T${pad(hour)}:${pad(minute)}:${pad(second)}`;
|
||||
epochOutput.value = dateToEpoch(isoString);
|
||||
}
|
||||
catch (e: any) {
|
||||
error.value = e.message;
|
||||
}
|
||||
}
|
||||
|
||||
function pad(value: string): string {
|
||||
return value.toString().padStart(2, '0');
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<c-card title="Epoch Time Converter (24 hour time format)" class="mx-auto max-w-4xl px-4">
|
||||
<!-- Epoch to Date -->
|
||||
<div class="mb-8">
|
||||
<div class="mb-2 font-semibold">
|
||||
Epoch to Date
|
||||
</div>
|
||||
<c-input-text
|
||||
v-model:value="epochInput"
|
||||
placeholder="Enter epoch timestamp (e.g. 1718822594)"
|
||||
class="mb-4"
|
||||
raw-text
|
||||
/>
|
||||
<c-button @click="convertEpochToDate">
|
||||
Convert to Date
|
||||
</c-button>
|
||||
|
||||
<div v-if="dateOutput" class="mt-4 text-sm text-green-400">
|
||||
Human-Readable Date: <strong>{{ dateOutput }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Date to Epoch -->
|
||||
<div class="mb-8">
|
||||
<div class="mb-2 font-semibold">
|
||||
Date to Epoch
|
||||
</div>
|
||||
|
||||
<div class="mb-4 max-w-sm space-y-3">
|
||||
<div class="flex items-center">
|
||||
<label class="w-24 text-sm font-medium">Year:</label>
|
||||
<c-input-text v-model:value="dateParts.year" placeholder="YYYY" class="ml-auto w-32" />
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<label class="w-24 text-sm font-medium">Month:</label>
|
||||
<c-input-text v-model:value="dateParts.month" placeholder="MM" class="ml-auto w-24" />
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<label class="w-24 text-sm font-medium">Day:</label>
|
||||
<c-input-text v-model:value="dateParts.day" placeholder="DD" class="ml-auto w-24" />
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<label class="w-24 text-sm font-medium">Hour:</label>
|
||||
<c-input-text v-model:value="dateParts.hour" placeholder="HH" class="ml-auto w-24" />
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<label class="w-24 text-sm font-medium">Minute:</label>
|
||||
<c-input-text v-model:value="dateParts.minute" placeholder="MM" class="ml-auto w-24" />
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<label class="w-24 text-sm font-medium">Second:</label>
|
||||
<c-input-text v-model:value="dateParts.second" placeholder="SS" class="ml-auto w-24" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<c-button @click="convertDateToEpoch">
|
||||
Convert to Epoch
|
||||
</c-button>
|
||||
|
||||
<div v-if="epochOutput" class="mt-4 text-sm text-green-400">
|
||||
Epoch Timestamp: <strong>{{ epochOutput }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<c-alert v-if="error" type="error" class="mt-6">
|
||||
{{ error }}
|
||||
</c-alert>
|
||||
</c-card>
|
||||
</template>
|
12
src/tools/epoch-converter/index.ts
Normal file
12
src/tools/epoch-converter/index.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { ArrowsShuffle } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: 'Epoch converter',
|
||||
path: '/epoch-converter',
|
||||
description: 'Converts epoch to human readable date and vice versa',
|
||||
keywords: ['epoch', 'converter'],
|
||||
component: () => import('./epoch-converter.vue'),
|
||||
icon: ArrowsShuffle,
|
||||
createdAt: new Date('2025-06-19'),
|
||||
});
|
|
@ -1,7 +1,7 @@
|
|||
import { tool as base64FileConverter } from './base64-file-converter';
|
||||
import { tool as base64StringConverter } from './base64-string-converter';
|
||||
import { tool as basicAuthGenerator } from './basic-auth-generator';
|
||||
import { tool as gzipDecompressor } from './gzip-decompressor';
|
||||
import { tool as epochConverter } from './epoch-converter';
|
||||
import { tool as emailNormalizer } from './email-normalizer';
|
||||
|
||||
import { tool as asciiTextDrawer } from './ascii-text-drawer';
|
||||
|
@ -118,6 +118,7 @@ export const toolsByCategory: ToolCategory[] = [
|
|||
jsonToXml,
|
||||
markdownToHtml,
|
||||
gzipDecompressor,
|
||||
epochConverter,
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue