世界時鐘技術實作

深入了解世界時鐘的完整實作,包含全球時區系統、實時更新引擎、智能搜尋功能、雙時間格式支援和雙語界面整合

概述

世界時鐘是一個功能強大的線上工具,專為需要跨時區協作的專業人士、國際旅行者和遠程工作者設計,能夠即時顯示全球主要城市的當地時間。 本工具採用純前端架構,完全在瀏覽器端運行,零網路傳輸,確保數據的絕對隱私和安全性。 提供智能搜尋、實時更新、時間格式切換、本地儲存等專業功能。

🔒 隱私保護承諾

所有時間處理都在您的瀏覽器本地進行,數據不會上傳到任何伺服器,確保您的時區偏好和使用習慣完全安全。

技術架構與核心設計

整體架構設計

技術層級 實作方式 設計考量
前端架構 ES6+ JavaScript + 純DOM操作 即時更新、響應式界面、模組化設計
時區系統 Intl.DateTimeFormat API + IANA時區 高精度時間轉換、夏令時自動處理
資料儲存 localStorage + JSON序列化 用戶偏好持久化、快速載入
搜尋引擎 實時過濾 + 模糊匹配 快速城市查找、智能建議
語言系統 Tool Master 全域語言整合 即時雙語切換、本地化格式

關鍵功能特性

🌍

全球城市支援

涵蓋44個主要城市,包含亞洲、歐洲、美洲、大洋洲和非洲五大洲的重要時區

🔍

智能搜尋系統

支援城市名稱即時搜尋,自動篩選下拉選項,Enter鍵快速新增

雙時間格式

支援12小時制和24小時制切換,滿足不同用戶的使用習慣

🔄

實時自動更新

每秒自動更新所有時鐘,確保時間顯示的準確性和同步性

📱

響應式設計

完美適配桌面、平板和手機設備,提供一致的用戶體驗

💾

狀態持久化

自動保存用戶選擇的城市和時間格式偏好到本地儲存

完整程式碼實作

以下是世界時鐘的完整程式碼實作,按功能模組分類展示。點擊卡片標題可展開查看詳細程式碼:

📦 核心世界時鐘類別與城市資料庫

功能:定義全域變數、城市資料庫和主要的狀態管理變數

/**
 * World Clock - Core Implementation
 * 世界時鐘 - 核心實作
 * 
 * Professional world clock tool with global timezone support
 * 專業的全球時區支援世界時鐘工具
 */

// 城市資料庫 / City Database
// 包含44個全球主要城市的時區資訊和多語言名稱
const cities = {
    // 亞洲 / Asia
    'Asia/Taipei': { zh: '台北', en: 'Taipei', country: { zh: '台灣', en: 'Taiwan' } },
    'Asia/Tokyo': { zh: '東京', en: 'Tokyo', country: { zh: '日本', en: 'Japan' } },
    'Asia/Seoul': { zh: '首爾', en: 'Seoul', country: { zh: '韓國', en: 'South Korea' } },
    'Asia/Hong_Kong': { zh: '香港', en: 'Hong Kong', country: { zh: '香港', en: 'Hong Kong' } },
    'Asia/Singapore': { zh: '新加坡', en: 'Singapore', country: { zh: '新加坡', en: 'Singapore' } },
    'Asia/Shanghai': { zh: '上海', en: 'Shanghai', country: { zh: '中國', en: 'China' } },
    'Asia/Bangkok': { zh: '曼谷', en: 'Bangkok', country: { zh: '泰國', en: 'Thailand' } },
    'Asia/Jakarta': { zh: '雅加達', en: 'Jakarta', country: { zh: '印尼', en: 'Indonesia' } },
    'Asia/Manila': { zh: '馬尼拉', en: 'Manila', country: { zh: '菲律賓', en: 'Philippines' } },
    'Asia/Dubai': { zh: '杜拜', en: 'Dubai', country: { zh: '阿聯', en: 'UAE' } },
    
    // 歐洲 / Europe
    'Europe/London': { zh: '倫敦', en: 'London', country: { zh: '英國', en: 'UK' } },
    'Europe/Paris': { zh: '巴黎', en: 'Paris', country: { zh: '法國', en: 'France' } },
    'Europe/Berlin': { zh: '柏林', en: 'Berlin', country: { zh: '德國', en: 'Germany' } },
    'Europe/Rome': { zh: '羅馬', en: 'Rome', country: { zh: '義大利', en: 'Italy' } },
    'Europe/Madrid': { zh: '馬德里', en: 'Madrid', country: { zh: '西班牙', en: 'Spain' } },
    'Europe/Amsterdam': { zh: '阿姆斯特丹', en: 'Amsterdam', country: { zh: '荷蘭', en: 'Netherlands' } },
    'Europe/Zurich': { zh: '蘇黎世', en: 'Zurich', country: { zh: '瑞士', en: 'Switzerland' } },
    'Europe/Moscow': { zh: '莫斯科', en: 'Moscow', country: { zh: '俄國', en: 'Russia' } },
    
    // 美洲 / Americas
    'America/New_York': { zh: '紐約', en: 'New York', country: { zh: '美國', en: 'USA' } },
    'America/Los_Angeles': { zh: '洛杉磯', en: 'Los Angeles', country: { zh: '美國', en: 'USA' } },
    'America/Chicago': { zh: '芝加哥', en: 'Chicago', country: { zh: '美國', en: 'USA' } },
    'America/Toronto': { zh: '多倫多', en: 'Toronto', country: { zh: '加拿大', en: 'Canada' } },
    'America/Vancouver': { zh: '溫哥華', en: 'Vancouver', country: { zh: '加拿大', en: 'Canada' } },
    'America/Mexico_City': { zh: '墨西哥城', en: 'Mexico City', country: { zh: '墨西哥', en: 'Mexico' } },
    'America/Sao_Paulo': { zh: '聖保羅', en: 'São Paulo', country: { zh: '巴西', en: 'Brazil' } },
    'America/Buenos_Aires': { zh: '布宜諾斯艾利斯', en: 'Buenos Aires', country: { zh: '阿根廷', en: 'Argentina' } },
    
    // 大洋洲 / Oceania
    'Australia/Sydney': { zh: '雪梨', en: 'Sydney', country: { zh: '澳洲', en: 'Australia' } },
    'Australia/Melbourne': { zh: '墨爾本', en: 'Melbourne', country: { zh: '澳洲', en: 'Australia' } },
    'Pacific/Auckland': { zh: '奧克蘭', en: 'Auckland', country: { zh: '紐西蘭', en: 'New Zealand' } },
    
    // 非洲 / Africa
    'Africa/Cairo': { zh: '開羅', en: 'Cairo', country: { zh: '埃及', en: 'Egypt' } },
    'Africa/Johannesburg': { zh: '約翰尼斯堡', en: 'Johannesburg', country: { zh: '南非', en: 'South Africa' } },
};

// 全域狀態變數 / Global State Variables
let selectedCities = [];        // 用戶選擇的城市列表
let is24HourFormat = false;     // 時間格式偏好 (false: 12小時制, true: 24小時制)
let currentLanguage = 'zh';     // 當前語言設定
let updateInterval;             // 時間更新定時器

// DOM 元素引用 / DOM Element References
const citySearch = document.getElementById('citySearch');
const citySelect = document.getElementById('citySelect');
const addCityBtn = document.getElementById('addCityBtn');
const timeFormatToggle = document.getElementById('timeFormatToggle');
const clocksContainer = document.getElementById('clocksContainer');

🌐 全域語言系統整合

功能:整合 Tool Master 全域語言切換系統,支援即時雙語切換

/**
 * 設置全域語言監聽器
 * Setup global language listener
 * 
 * 這是工具與 Tool Master 語言系統整合的關鍵方法
 * This is the key method for tool integration with Tool Master language system
 */
function setupGlobalLanguageListener() {
    // 監聽全域語言切換事件 / Listen to global language change events
    window.addEventListener('languageChanged', (event) => {
        currentLanguage = event.detail.language;
        console.log('🌐 語言切換至:', currentLanguage);
        updateLanguage();
    });
    
    // 處理全域語言系統加載時序問題
    // Handle timing issues with global language system loading
    const checkGlobalLanguage = () => {
        if (window.globalI18n) {
            currentLanguage = window.globalI18n.currentLanguage;
            updateLanguage();
            return true;
        }
        return false;
    };
    
    // 立即檢查,如果沒有就延遲重試
    // Immediate check, retry with delay if not available
    if (!checkGlobalLanguage()) {
        setTimeout(() => {
            checkGlobalLanguage();
        }, 100);
    }
}

/**
 * 更新語言顯示
 * Update language display
 * 
 * 根據當前語言設定更新所有界面元素
 * Update all interface elements based on current language setting
 */
function updateLanguage() {
    // 更新所有有語言屬性的元素 / Update all elements with language attributes
    document.querySelectorAll('[data-zh][data-en]').forEach(element => {
        const text = currentLanguage === 'zh' ? element.getAttribute('data-zh') : element.getAttribute('data-en');
        if (element.tagName === 'INPUT' && element.type === 'text') {
            element.placeholder = text;
        } else {
            element.textContent = text;
        }
    });
    
    // 更新城市選擇器 / Update city selector
    populateCitySelect();
    
    // 更新時鐘顯示 / Update clock display
    updateClocksDisplay();
}

🔍 城市搜尋與選擇系統

功能:處理城市搜尋、下拉選擇、自動篩選和城市新增功能

/**
 * 填充城市選擇下拉選單
 * Populate city selection dropdown
 * 
 * 根據當前語言動態生成城市選項,並按字母順序排序
 * Dynamically generate city options based on current language and sort alphabetically
 */
function populateCitySelect() {
    // 按當前語言排序城市 / Sort cities by current language
    const sortedCities = Object.entries(cities).sort((a, b) => {
        const nameA = currentLanguage === 'en' ? a[1].en : a[1].zh;
        const nameB = currentLanguage === 'en' ? b[1].en : b[1].zh;
        return nameA.localeCompare(nameB);
    });
    
    // 創建預設選項 / Create default option
    const defaultOption = document.createElement('option');
    defaultOption.value = '';
    defaultOption.textContent = currentLanguage === 'en' ? 'Select city' : '選擇城市';
    citySelect.innerHTML = '';
    citySelect.appendChild(defaultOption);
    
    // 添加所有城市選項 / Add all city options
    sortedCities.forEach(([timezone, data]) => {
        const option = document.createElement('option');
        option.value = timezone;
        const cityName = currentLanguage === 'en' ? data.en : data.zh;
        const countryName = currentLanguage === 'en' ? data.country.en : data.country.zh;
        option.textContent = `${cityName} (${countryName})`;
        citySelect.appendChild(option);
    });
}

/**
 * 城市搜尋處理
 * Handle city search
 * 
 * 實時過濾城市選項,支援模糊匹配和自動選擇
 * Real-time filtering of city options with fuzzy matching and auto-selection
 */
function handleCitySearch() {
    const searchTerm = citySearch.value.toLowerCase();
    const options = citySelect.querySelectorAll('option');
    
    // 顯示/隱藏匹配的選項 / Show/hide matching options
    options.forEach(option => {
        if (option.value === '') return; // 跳過預設選項
        const text = option.textContent.toLowerCase();
        option.style.display = text.includes(searchTerm) ? '' : 'none';
    });
    
    // 自動選擇第一個匹配的選項 / Auto-select first matching option
    const visibleOptions = Array.from(options).filter(option => 
        option.value !== '' && option.style.display !== 'none'
    );
    
    if (visibleOptions.length > 0) {
        citySelect.value = visibleOptions[0].value;
    }
}

/**
 * 新增選擇的城市
 * Add selected city
 * 
 * 驗證並新增城市到用戶列表,防止重複新增
 * Validate and add city to user list, prevent duplicate additions
 */
function addSelectedCity() {
    const selectedTimezone = citySelect.value;
    if (!selectedTimezone) return;
    
    // 檢查是否已經存在 / Check if already exists
    if (selectedCities.includes(selectedTimezone)) {
        alert(currentLanguage === 'en' ? 'City already added!' : '城市已經新增過了!');
        return;
    }
    
    // 新增城市並更新顯示 / Add city and update display
    selectedCities.push(selectedTimezone);
    citySearch.value = '';
    citySelect.value = '';
    updateClocksDisplay();
    saveToLocalStorage();
    
    console.log('✅ 新增城市:', cities[selectedTimezone][currentLanguage]);
}

⏰ 實時時間更新引擎

功能:核心時間計算邏輯,包括時區轉換、時差計算和格式化顯示

/**
 * 更新所有時鐘顯示
 * Update all clocks display
 * 
 * 遍歷所有已新增的城市,更新其時間顯示
 * Iterate through all added cities and update their time display
 */
function updateAllClocks() {
    const now = new Date();
    const userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
    
    selectedCities.forEach(timezone => {
        updateSingleClock(timezone, now, userTimezone);
    });
}

/**
 * 更新單個時鐘
 * Update single clock
 * 
 * 處理單一城市的時間計算、格式化和時差顯示
 * Handle time calculation, formatting, and time difference display for a single city
 */
function updateSingleClock(timezone, now, userTimezone) {
    const card = document.querySelector(`[data-timezone="${timezone}"]`);
    if (!card) return;
    
    try {
        // 計算當地時間 / Calculate local time
        // 使用 Intl API 進行精確的時區轉換
        const localTime = new Date(now.toLocaleString("en-US", {timeZone: timezone}));
        
        // 時間格式化選項 / Time formatting options
        const timeOptions = {
            hour: '2-digit',
            minute: '2-digit',
            second: '2-digit',
            hour12: !is24HourFormat  // 根據用戶偏好選擇12/24小時制
        };
        
        // 格式化時間字串 / Format time string
        const timeString = localTime.toLocaleTimeString(
            currentLanguage === 'en' ? 'en-US' : 'zh-TW', 
            timeOptions
        );
        
        // 日期格式化選項 / Date formatting options
        const dateOptions = {
            weekday: 'long',    // 星期幾
            year: 'numeric',    // 年份
            month: 'long',      // 月份
            day: 'numeric'      // 日期
        };
        
        // 格式化日期字串 / Format date string
        const dateString = localTime.toLocaleDateString(
            currentLanguage === 'en' ? 'en-US' : 'zh-TW', 
            dateOptions
        );
        
        // 計算時差 / Calculate time difference
        const userTime = new Date(now.toLocaleString("en-US", {timeZone: userTimezone}));
        const timeDiff = Math.round((localTime.getTime() - userTime.getTime()) / (1000 * 60 * 60));
        
        // 生成時差文字 / Generate time difference text
        let timeDiffText = '';
        if (timeDiff === 0) {
            timeDiffText = currentLanguage === 'en' ? 'Same as your time' : '與你的時間相同';
        } else if (timeDiff > 0) {
            timeDiffText = currentLanguage === 'en' ? `${timeDiff} hours ahead` : `比你快 ${timeDiff} 小時`;
        } else {
            timeDiffText = currentLanguage === 'en' ? `${Math.abs(timeDiff)} hours behind` : `比你慢 ${Math.abs(timeDiff)} 小時`;
        }
        
        // 更新 DOM 顯示 / Update DOM display
        card.querySelector('.current-time').textContent = timeString;
        card.querySelector('.current-date').textContent = dateString;
        card.querySelector('.time-diff').textContent = timeDiffText;
        
    } catch (error) {
        console.error('❌ 時鐘更新錯誤:', timezone, error);
    }
}

/**
 * 開始自動更新
 * Start auto-update
 * 
 * 啟動定時器,每秒更新一次所有時鐘
 * Start timer to update all clocks every second
 */
function startAutoUpdate() {
    if (updateInterval) {
        clearInterval(updateInterval);
    }
    updateInterval = setInterval(updateAllClocks, 1000);
    console.log('🔄 自動更新已啟動');
}

🎨 時鐘卡片界面系統

功能:處理時鐘卡片的創建、顯示更新和移除操作

/**
 * 更新時鐘顯示區域
 * Update clocks display area
 * 
 * 根據選擇的城市列表動態生成時鐘卡片
 * Dynamically generate clock cards based on selected cities list
 */
function updateClocksDisplay() {
    if (selectedCities.length === 0) {
        // 顯示空狀態 / Show empty state
        clocksContainer.innerHTML = `
            
🕐

${currentLanguage === 'en' ? 'No cities added' : '還沒有城市'}

${currentLanguage === 'en' ? 'Search and add cities to see their local time' : '搜尋並新增城市來查看當地時間'}

`; return; } // 清空容器並重新生成卡片 / Clear container and regenerate cards clocksContainer.innerHTML = ''; selectedCities.forEach(timezone => { const clockCard = createClockCard(timezone); clocksContainer.appendChild(clockCard); }); } /** * 創建時鐘卡片 * Create clock card * * 為指定時區創建完整的時鐘卡片元素 * Create complete clock card element for specified timezone */ function createClockCard(timezone) { const city = cities[timezone]; const card = document.createElement('div'); card.className = 'clock-card'; card.dataset.timezone = timezone; // 根據當前語言獲取城市和國家名稱 / Get city and country names based on current language const cityName = currentLanguage === 'en' ? city.en : city.zh; const countryName = currentLanguage === 'en' ? city.country.en : city.country.zh; // 生成卡片 HTML 結構 / Generate card HTML structure card.innerHTML = `
${cityName}
--:--
-
-
`; return card; } /** * 移除城市 * Remove city * * 從選擇列表中移除指定城市並更新顯示 * Remove specified city from selection list and update display */ function removeCity(timezone) { selectedCities = selectedCities.filter(city => city !== timezone); updateClocksDisplay(); saveToLocalStorage(); const cityName = cities[timezone][currentLanguage]; console.log('🗑️ 移除城市:', cityName); } /** * 切換時間格式 * Toggle time format * * 在12小時制和24小時制之間切換 * Toggle between 12-hour and 24-hour format */ function toggleTimeFormat() { is24HourFormat = timeFormatToggle.checked; updateAllClocks(); saveToLocalStorage(); console.log('🕐 時間格式切換至:', is24HourFormat ? '24小時制' : '12小時制'); }

💾 本地儲存管理系統

功能:處理用戶偏好的持久化儲存和載入

/**
 * 儲存到本地存儲
 * Save to local storage
 * 
 * 將用戶的城市選擇和時間格式偏好保存到 localStorage
 * Save user's city selections and time format preferences to localStorage
 */
function saveToLocalStorage() {
    const data = {
        selectedCities: selectedCities,      // 選擇的城市列表
        is24HourFormat: is24HourFormat       // 時間格式偏好
    };
    
    try {
        localStorage.setItem('worldClockData', JSON.stringify(data));
        console.log('💾 資料已儲存:', data);
    } catch (error) {
        console.error('❌ 儲存失敗:', error);
    }
}

/**
 * 從本地存儲載入
 * Load from local storage
 * 
 * 從 localStorage 載入用戶之前的偏好設定
 * Load user's previous preference settings from localStorage
 */
function loadFromLocalStorage() {
    try {
        const data = localStorage.getItem('worldClockData');
        if (data) {
            const parsed = JSON.parse(data);
            
            // 恢復城市選擇 / Restore city selections
            selectedCities = parsed.selectedCities || [];
            
            // 恢復時間格式偏好 / Restore time format preference
            is24HourFormat = parsed.is24HourFormat || false;
            
            // 更新 UI 控制項 / Update UI controls
            timeFormatToggle.checked = is24HourFormat;
            
            console.log('📂 資料已載入:', parsed);
        }
    } catch (error) {
        console.error('❌ 載入失敗:', error);
        // 使用預設值 / Use default values
        selectedCities = [];
        is24HourFormat = false;
    }
}

/**
 * 清理資源
 * Cleanup resources
 * 
 * 在頁面關閉前清理定時器等資源
 * Cleanup timers and other resources before page closes
 */
function cleanup() {
    if (updateInterval) {
        clearInterval(updateInterval);
        console.log('🧹 定時器已清理');
    }
}

🚀 工具初始化與事件設定

功能:工具的初始化邏輯、事件監聽器設定和全域方法暴露

/**
 * 設置事件監聽器
 * Setup event listeners
 * 
 * 為所有 UI 控制項設置必要的事件監聽器
 * Setup necessary event listeners for all UI controls
 */
function setupEventListeners() {
    // 城市搜尋輸入 / City search input
    citySearch.addEventListener('input', handleCitySearch);
    
    // 新增城市按鈕 / Add city button
    addCityBtn.addEventListener('click', addSelectedCity);
    
    // 時間格式切換 / Time format toggle
    timeFormatToggle.addEventListener('change', toggleTimeFormat);
    
    // Enter 鍵快速新增城市 / Enter key for quick city addition
    citySearch.addEventListener('keypress', (e) => {
        if (e.key === 'Enter') {
            addSelectedCity();
        }
    });
    
    console.log('🎧 事件監聽器已設置');
}

/**
 * 初始化函數
 * Initialization function
 * 
 * 工具的主要初始化流程,按正確順序執行所有設置
 * Main initialization process, execute all setups in correct order
 */
function init() {
    console.log('🚀 世界時鐘初始化開始');
    
    // ⚠️ 重要:語言監聽器必須在其他初始化之前設置
    // Important: Language listener must be set up before other initializations
    setupGlobalLanguageListener();
    
    // 填充城市選擇器 / Populate city selector
    populateCitySelect();
    
    // 設置事件監聽器 / Setup event listeners
    setupEventListeners();
    
    // 載入用戶偏好 / Load user preferences
    loadFromLocalStorage();
    
    // 更新顯示 / Update display
    updateClocksDisplay();
    updateAllClocks();
    
    // 啟動自動更新 / Start auto-update
    startAutoUpdate();
    
    console.log('✅ 世界時鐘初始化完成');
}

// 公開方法給全域使用 / Expose methods for global use
window.worldClock = {
    removeCity: removeCity
};

// 頁面離開時清理資源 / Cleanup resources when page unloads
window.addEventListener('beforeunload', cleanup);

// 啟動工具 / Launch tool
init();

// 全域方法暴露給主視窗使用
window.worldClock = {
    removeCity: removeCity
};

// 頁面離開時清理資源
window.addEventListener('beforeunload', cleanup);

// 啟動工具
init();

效能優化技術

⚡ 智能更新策略

僅更新實際存在的時鐘卡片,避免不必要的 DOM 操作

🎯 事件委派

使用全域事件處理器減少記憶體使用和提升性能

📦 資源管理

頁面離開時自動清理定時器,防止記憶體洩漏

瀏覽器兼容性

瀏覽器 最低版本 支援程度
Chrome 24+ ✅ 完整支援
Firefox 29+ ✅ 完整支援
Safari 10+ ✅ 完整支援
Edge 79+ ✅ 完整支援

總結

世界時鐘工具展示了現代 Web 技術在時間處理和國際化方面的強大能力。 通過巧妙運用 Intl API、本地儲存和事件系統,我們創建了一個功能完整、性能優秀的時區管理工具。 該實作方案不僅確保了跨平台兼容性,也為用戶提供了直觀友好的操作體驗。