ساخت ساعت جهانی و مبدل مناطق زمانی زنده با جاوااسکریپت خالص

آموزش ساخت داشبورد ساعت جهانی و مبدل مناطق زمانی زنده با جاوااسکریپت خالص بدون نیاز به کتابخانه‌های سنگین برای فریلنسرها.

🎧 خلاصه صوتی مقاله (پادکست ۲ دقیقه‌ای):

فرصت مطالعه ندارید؟ چکیده این مطلب را همین‌جا گوش دهید:

مدیریت زمان در پروژه‌های دورکاری و همکاری با تیم‌های بین‌المللی یکی از بزرگ‌ترین چالش‌های فریلنسرهاست. محاسبه‌ی ذهنی اختلاف ساعت بین تهران، لندن، نیویورک یا توکیو همواره با خطا همراه است و استفاده از ابزارهای آنلاین متفرقه نیز گاهی نیازمند باز کردن تب‌های متعدد یا مواجهه با تبلیغات آزاردهنده است. اگر توسعه‌دهنده وب هستید یا دوست دارید ابزاری اختصاصی، سبک و پر سرعت برای خود داشته باشید، بهترین راه حل ساخت یک داشبورد شخصی است.

در این مقاله قصد داریم پروژه‌ای جذاب و کاملاً کاربردی را پیاده‌سازی کنیم: ساخت یک ساعت جهانی و مبدل مناطق زمانی زنده تنها با استفاده از جاوااسکریپت خالص (Vanilla JavaScript)، HTML و CSS. این ابزار به هیچ پکیج جانبی، کتابخانه‌ی سنگین یا اتصال به APIهای خارجی نیازی ندارد و تمام منطق آن داخل مرورگر پردازش می‌شود. پیش از شروع، اگر به ابزارهای کاربردی دیگر برای بهینه‌سازی کارهای خود علاقه دارید، پیشنهاد می‌کنیم نگاهی به معرفی Knowledge Work Plugins؛ پلاگین‌های متن‌باز برای شخصی‌سازی کلود بیندازید تا ابزارهای توسعه‌ی خود را گسترش دهید.

چرا ساخت ساعت جهانی با جاوااسکریپت خالص؟

بسیاری از برنامه‌نویسان برای نمایش تاریخ و ساعت به سراغ کتابخانه‌های حجیمی مانند Moment.js می‌روند که امروزه منسوخ شده‌اند یا جایگزین‌های سنگینی مثل Luxon و Day.js را انتخاب می‌کنند. با این حال، موتور جاوااسکریپت مدرن در مرورگرها ابزار فوق‌العاده قدرتمندی به نام شیء Intl.DateTimeFormat در اختیار ما می‌گذارد. این شیء به طور بومی از مناطق زمانی مختلف، فرمت‌های محلی و قوانین تغییر ساعت تابستانی (DST) پشتیبانی می‌کند.

مزیت بزرگ استفاده از کدهای خالص این است که فایل خروجی شما چند کیلوبایت بیشتر حجم ندارد، بدون نیاز به فرآیندهای پیچیده‌ی بیلد (Build) اجرا می‌شود و سرعت بارگذاری آنی دارد. علاوه بر این، در حین کدنویسی این پروژه با منطق کار با زمان در مرورگرها آشنا می‌شوید که یکی از مهارت‌های کلیدی هر طراح وب است. برای طراحی ظاهر این داشبورد، هماهنگی رنگ‌ها اهمیت بالایی دارد؛ درست همان‌طور که در مقاله معرفی WebGradients؛ گنجینه‌ی ۱۸۰ گرادیانت رنگی CSS برای طراحان بررسی کردیم، انتخاب پالت رنگی مناسب تاثیر مستقیمی بر تجربه کاربری خواهد داشت.

جدول مشخصات فنی پروژه ساعت جهانی

ویژگیمقدار / توضیحات
فناوری‌های استفاده شدهHTML5, CSS3, Vanilla JavaScript
وابستگی‌ها (Dependencies)صفر (کاملاً مستقل از کتابخانه‌های خارجی)
قابلیت‌های کلیدینمایش ساعت زنده، تاریخ میلادی و شمسی، قابلیت افزودن شهر جدید، مبدل زمان
سازگاری با مرورگرهاتمامی مرورگرهای مدرن (Chrome, Firefox, Safari, Edge)
وضعیت دسترسی برای ایرانبدون محدودیت (کاملاً قابل اجرا روی سیستم‌های داخلی)

کد کامل و یک‌پارچه پروژه (HTML + CSS + JS)

برای اجرای این پروژه، کافی است کد زیر را کپی کرده، در یک فایل متنی با نام دلخواه مثلاً index.html ذخیره کنید و آن را با هر مرورگر وب دلخواهی باز کنید. تمام استایل‌ها، ساختار صفحه و منطق جاوااسکریپت درون همین یک فایل گنجانده شده است.

<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>داشبورد ساعت جهانی و مبدل زمان</title>
    <style>
        :root {
            --bg-color: #0f172a;
            --card-bg: #1e293b;
            --text-color: #f8fafc;
            --text-muted: #94a3b8;
            --accent-color: #38bdf8;
            --border-color: #334155;
        }
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
            font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
        }
        body {
            background-color: var(--bg-color);
            color: var(--text-color);
            min-height: 100vh;
            padding: 2rem 1rem;
        }
        .container {
            max-width: 900px;
            margin: 0 auto;
        }
        header {
            text-align: center;
            margin-bottom: 2rem;
        }
        header h1 {
            font-size: 2rem;
            margin-bottom: 0.5rem;
            color: var(--accent-color);
        }
        header p {
            color: var(--text-muted);
        }
        .controls {
            display: flex;
            gap: 1rem;
            margin-bottom: 2rem;
            background: var(--card-bg);
            padding: 1rem;
            border-radius: 12px;
            border: 1px solid var(--border-color);
        }
        select, button {
            padding: 0.75rem 1rem;
            border-radius: 8px;
            border: 1px solid var(--border-color);
            background: var(--bg-color);
            color: var(--text-color);
            font-size: 1rem;
            outline: none;
        }
        select {
            flex: 1;
        }
        button {
            background: var(--accent-color);
            color: #000;
            font-weight: bold;
            cursor: pointer;
            border: none;
            transition: opacity 0.2s;
        }
        button:hover {
            opacity: 0.9;
        }
        .grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
            gap: 1.5rem;
        }
        .card {
            background: var(--card-bg);
            border: 1px solid var(--border-color);
            border-radius: 12px;
            padding: 1.5rem;
            position: relative;
            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
        }
        .card h3 {
            font-size: 1.25rem;
            margin-bottom: 0.25rem;
        }
        .card .zone {
            font-size: 0.85rem;
            color: var(--text-muted);
            margin-bottom: 1rem;
        }
        .card .time {
            font-size: 2rem;
            font-weight: bold;
            font-family: monospace;
            margin-bottom: 0.5rem;
            color: var(--accent-color);
        }
        .card .date {
            font-size: 0.9rem;
            color: var(--text-muted);
        }
        .remove-btn {
            position: absolute;
            top: 1rem;
            left: 1rem;
            background: transparent;
            color: #ef4444;
            border: none;
            font-size: 1.2rem;
            cursor: pointer;
            padding: 0;
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1>ساعت جهانی فریلنسرها</h1>
            <p>مدیریت و مقایسه زمان شهرهای کلیدی جهان به صورت زنده</p>
        </header>

        <div class="controls">
            <select id="zoneSelect">
                <option value="Asia/Tehran">تهران (ایران)</option>
                <option value="Europe/London">لندن (انگلستان)</option>
                <option value="America/New_York">نیویورک (ایالات متحده)</option>
                <option value="Asia/Tokyo">توکیو (ژاپن)</option>
                <option value="Australia/Sydney">سیدنی (استرالیا)</option>
                <option value="Europe/Berlin">برلین (آلمان)</option>
                <option value="Asia/Dubai">دبی (امارات)</option>
            </select>
            <button id="addBtn">افزودن شهر</button>
        </div>

        <div class="grid" id="clockGrid"></div>
    </div>

    <script>
        // لیست پیش‌فرض شهرهایی که هنگام بارگذاری صفحه نمایش داده می‌شوند
        let activeZones = [
            { name: "تهران", zone: "Asia/Tehran" },
            { name: "لندن", zone: "Europe/London" },
            { name: "نیویورک", zone: "America/New_York" },
            { name: "توکیو", zone: "Asia/Tokyo" }
        ];

        const clockGrid = document.getElementById('clockGrid');
        const zoneSelect = document.getElementById('zoneSelect');
        const addBtn = document.getElementById('addBtn');

        function renderClocks() {
            clockGrid.innerHTML = '';
            activeZones.forEach((item, index) => {
                const card = document.createElement('div');
                card.className = 'card';
                card.innerHTML = `
                    <button class="remove-btn" onclick="removeZone(${index})" title="حذف">&times;</button>
                    <h3>${item.name}</h3>
                    <div class="zone">${item.zone}</div>
                    <div class="time" id="time-${index}">--:--:--</div>
                    <div class="date" id="date-${index}">در حال بارگذاری...</div>
                `;
                clockGrid.appendChild(card);
            });
            updateTimes();
        }

        function updateTimes() {
            const now = new Date();
            activeZones.forEach((item, index) => {
                const timeEl = document.getElementById(`time-${index}`);
                const dateEl = document.getElementById(`date-${index}`);
                
                if (timeEl && dateEl) {
                    try {
                        const timeString = now.toLocaleTimeString('fa-IR', { timeZone: item.zone, hour12: false });
                        const dateString = now.toLocaleDateString('fa-IR', { timeZone: item.zone, weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
                        
                        timeEl.textContent = timeString;
                        dateEl.textContent = dateString;
                    } catch (e) {
                        timeEl.textContent = "خطا در منطقه";
                    }
                }
            });
        }

        function removeZone(index) {
            activeZones.splice(index, 1);
            renderClocks();
        }

        addBtn.addEventListener('click', () => {
            const selectedOption = zoneSelect.options[zoneSelect.selectedIndex];
            const zone = selectedOption.value;
            const name = selectedOption.text.split(' ')[0]; // استخراج نام شهر

            // بررسی تکراری نبودن
            if (!activeZones.some(z => z.zone === zone)) {
                activeZones.push({ name, zone });
                renderClocks();
            }
        });

        // رندر اولیه و به‌روزرسانی هر ثانیه
        renderClocks();
        setInterval(updateTimes, 1000);
    </script>
</body>
</html>

تحلیل و بررسی بخش‌های مختلف کد

این کد به سه بخش اصلی تقسیم شده است: ساختار ظاهری (HTML)، استایل‌های مدرن با متغیرهای CSS و منطق پویا با جاوااسکریپت. در ادامه جزئیات عملکرد کدهای جاوااسکریپت را بررسی می‌کنیم.

مدیریت زمان با Intl.DateTimeFormat

هسته اصلی این برنامه متد toLocaleTimeString و toLocaleDateString است. با پاس دادن پارامتر timeZone به این متدها، جاوااسکریپت به طور خودکار ساعت محلیِ سیستم کاربر را به منطقه زمانی مشخص‌شده تبدیل می‌کند. همچنین با تعیین کردن fa-IR به عنوان لوکیل (Locale)، اعداد و نام ماه‌ها به صورت فارسی و استاندارد نمایش داده می‌شوند که خوانایی ابزار را برای کاربران فارسی‌زبان دوچندان می‌کند.

حلقه به‌روزرسانی لحظه‌ای (Interval)

تابع setInterval با فاصله‌ی زمانی ۱۰۰۰ میلی‌ثانیه (یک ثانیه) فراخوانی می‌شود تا مقادیر ساعت و تاریخ را به روز کند. در هر بار اجرا، شیء جدیدی از Date ساخته شده و ساعت مناطق مختلف محاسبه می‌شود. این فرآیند بسیار سبک است و هیچ‌گونه افت عملکردی روی مرورگر ایجاد نمی‌کند.

اشتباهات رایج و محدودیت‌های فنی

هنگام توسعه یا شخصی‌سازی این ابزار، ممکن است با چند چالش رایج روبه‌رو شوید:

  • اشتباه در نام‌گذاری منطقه زمانی (Timezone): رشته‌های مربوط به مناطق زمانی باید دقیقاً مطابق با استانداردهای پایگاه داده IANA باشند (مانند Asia/Tehran). نوشتن اشتباه نام شهرها باعث پرتاب خطای جاوااسکریپت می‌شود.
  • تغییرات ساعت تابستانی (DST): برخی کشورها در فصول مختلف سال ساعت خود را جلو یا عقب می‌کشند. استفاده از شیء بومی مرورگر این تغییرات را به صورت خودکار مدیریت می‌کند و نیازی به محاسبه دستی نیست.
  • فرمت ساعت ۱۲ یا ۲۴ ساعته: در کد بالا از حالت hour12: false استفاده شده است. اگر ترجیح می‌دهید ساعت به شکل AM/PM نمایش داده شود، می‌توانید این مقدار را به true تغییر دهید.

پرسش‌های متداول

آیا این ابزار نیاز به اتصال دائمی به اینترنت دارد؟

خیر. تمام محاسبات زمانی بر اساس ساعت سیستم عامل شما و پایگاه داده داخلی مرورگر انجام می‌شود و پس از بارگذاری صفحه، نیازی به اینترنت نیست.

چگونه می‌توانم شهرهای بیشتری به منو اضافه کنم؟

شما می‌توانید با اضافه کردن تگ‌های <option> جدید به عنصر <select> در بخش HTML و درج استاندارد IANA مربوط به آن منطقه، شهرهای دلخواه خود را به لیست اضافه کنید.

چرا فرمت تاریخ به صورت فارسی نمایش داده می‌شود؟

به دلیل استفاده از پارامتر fa-IR در متدهای تاریخ و زمان جاوااسکریپت، مرورگر به طور خودکار اعداد و تقویم را به صورت محلی‌سازی شده ارائه می‌دهد.

جمع‌بندی

در این مقاله یک داشبورد ساعت جهانی و مبدل مناطق زمانی زنده را با استفاده از جاوااسکریپت خالص از صفر تا صد پیاده‌سازی کردیم. این پروژه نشان داد که برای داشتن ابزارهای کاربردی و سریع، نیازی به نصب پکیج‌های سنگین نیست و با امکانات مدرن مرورگرها می‌توان کارهای بزرگی انجام داد. با ذخیره کردن این کد در قالب یک فایل HTML، همیشه یک ابزار اختصاصی و سبک برای مدیریت زمان در دست خواهید داشت.

پاسخی بگذارید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *