/**
* FeHelper - 专业时间戳工具
* 使用原生JavaScript实现,无需Vue依赖,兼容Chrome扩展CSP策略
*/
// 全局状态管理
var AppState = {
// 当前活跃的标签页
activeTab: 'smart-parser',
// 当前时间显示
currentTime: {
local: '',
timestamp: 0,
timestampMs: 0
},
isTimeRunning: true,
// 智能时间解析器
smartParser: {
input: '',
results: [],
error: '',
detectedFormat: ''
},
// 代码生成器
codeGenerator: {
input: '',
codes: [],
selectedLang: 'all'
},
// 时间计算器
calculator: {
startTime: '',
endTime: '',
difference: null
},
// 批量转换器
batchConverter: {
input: '',
results: []
},
// 时区转换
timezoneExpert: {
inputTime: '',
fromTimezone: 'Asia/Shanghai',
toTimezone: 'America/New_York',
result: null
},
// 数据库工具
dbTools: {
inputTime: '',
dbType: 'mysql',
formats: []
}
};
// 工具类 - 简易时间处理
var TimeUtils = {
// 解析时间输入
parseTimeInput: function(input) {
if (!input || !input.trim()) {
throw new Error('请输入时间值');
}
input = input.trim();
// Unix时间戳(秒) - 10位数字
if (/^\d{10}$/.test(input)) {
return {
timestamp: parseInt(input) * 1000,
format: 'Unix时间戳(秒)'
};
}
// Unix时间戳(毫秒) - 13位数字
if (/^\d{13}$/.test(input)) {
return {
timestamp: parseInt(input),
format: 'Unix时间戳(毫秒)'
};
}
// 特殊关键字
var now = new Date();
if (input.toLowerCase() === 'now') {
return {
timestamp: now.getTime(),
format: '当前时间(now)'
};
}
if (input.toLowerCase() === 'today') {
var today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
return {
timestamp: today.getTime(),
format: '今天开始时间(today)'
};
}
if (input.toLowerCase() === 'yesterday') {
var yesterday = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1);
return {
timestamp: yesterday.getTime(),
format: '昨天开始时间(yesterday)'
};
}
// 尝试解析为日期字符串
var date = new Date(input);
if (!isNaN(date.getTime())) {
return {
timestamp: date.getTime(),
format: '日期字符串'
};
}
throw new Error('无法识别的时间格式');
},
// 格式化时间戳为各种格式
formatTimestamp: function(timestamp) {
var date = new Date(timestamp);
return [
{ label: '标准格式', value: this.formatDate(date, 'YYYY-MM-DD HH:mm:ss') },
{ label: 'Unix时间戳(秒)', value: Math.floor(timestamp / 1000).toString() },
{ label: 'Unix时间戳(毫秒)', value: timestamp.toString() },
{ label: 'UTC时间', value: this.formatDate(new Date(date.getTime() + date.getTimezoneOffset() * 60000), 'YYYY-MM-DD HH:mm:ss') + ' UTC' },
{ label: '本地格式', value: date.toLocaleString('zh-CN') },
{ label: '相对时间', value: this.getRelativeTime(date) },
{ label: 'ISO 8601', value: date.toISOString() }
];
},
// 格式化日期
formatDate: function(date, format) {
var year = date.getFullYear();
var month = (date.getMonth() + 1).toString().padStart(2, '0');
var day = date.getDate().toString().padStart(2, '0');
var hour = date.getHours().toString().padStart(2, '0');
var minute = date.getMinutes().toString().padStart(2, '0');
var second = date.getSeconds().toString().padStart(2, '0');
return format
.replace('YYYY', year)
.replace('MM', month)
.replace('DD', day)
.replace('HH', hour)
.replace('mm', minute)
.replace('ss', second);
},
// 获取相对时间
getRelativeTime: function(date) {
var now = new Date();
var diff = now.getTime() - date.getTime();
var seconds = Math.floor(diff / 1000);
var minutes = Math.floor(seconds / 60);
var hours = Math.floor(minutes / 60);
var days = Math.floor(hours / 24);
if (days > 0) {
return days + '天前';
} else if (hours > 0) {
return hours + '小时前';
} else if (minutes > 0) {
return minutes + '分钟前';
} else if (seconds > 0) {
return seconds + '秒前';
} else {
return '刚刚';
}
},
// 生成各种语言代码
generateCode: function(input, lang) {
var parsed = this.parseTimeInput(input);
var timestamp = Math.floor(parsed.timestamp / 1000); // 转为秒
var codes = {
javascript: 'var date = new Date(' + parsed.timestamp + ');\nconsole.log(date.toISOString());\n// 输出: ' + new Date(parsed.timestamp).toISOString(),
python: 'import datetime\nfrom datetime import timezone\n\ntimestamp = ' + timestamp + '\ndate = datetime.datetime.fromtimestamp(timestamp, timezone.utc)\nprint(date.isoformat())\n# 输出: ' + new Date(parsed.timestamp).toISOString(),
java: 'import java.time.Instant;\nimport java.time.ZoneId;\nimport java.time.format.DateTimeFormatter;\n\nInstant instant = Instant.ofEpochSecond(' + timestamp + ');\nString formatted = instant.atZone(ZoneId.systemDefault())\n .format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);\nSystem.out.println(formatted);',
go: 'package main\n\nimport (\n "fmt"\n "time"\n)\n\nfunc main() {\n timestamp := int64(' + timestamp + ')\n t := time.Unix(timestamp, 0)\n fmt.Println(t.Format(time.RFC3339))\n // 输出: ' + new Date(parsed.timestamp).toISOString() + '\n}',
php: 'format("c");\n// 输出: ' + new Date(parsed.timestamp).toISOString() + '\n?>',
sql: '-- MySQL\nSELECT FROM_UNIXTIME(' + timestamp + ') AS formatted_date;\n\n-- PostgreSQL\nSELECT to_timestamp(' + timestamp + ') AS formatted_date;\n\n-- SQLite\nSELECT datetime(' + timestamp + ', "unixepoch") AS formatted_date;'
};
return codes[lang] || '不支持的语言';
}
};
// DOM操作工具
var DOMUtils = {
// 查找元素
$: function(selector) {
return document.querySelector(selector);
},
// 查找所有元素
$$: function(selector) {
return document.querySelectorAll(selector);
},
// 设置元素内容
setText: function(element, text) {
if (element) {
element.textContent = text;
}
},
// 设置元素值
setValue: function(element, value) {
if (element) {
element.value = value;
}
},
// 设置元素HTML
setHTML: function(element, html) {
if (element) {
element.innerHTML = html;
}
},
// 添加类
addClass: function(element, className) {
if (element) {
element.classList.add(className);
}
},
// 移除类
removeClass: function(element, className) {
if (element) {
element.classList.remove(className);
}
},
// 切换类
toggleClass: function(element, className) {
if (element) {
element.classList.toggle(className);
}
},
// 显示元素
show: function(element) {
if (element) {
element.style.display = '';
}
},
// 隐藏元素
hide: function(element) {
if (element) {
element.style.display = 'none';
}
}
};
// 应用主类
var TimestampApp = {
// 初始化
init: function() {
console.log('初始化时间戳工具...');
// 移除Vue相关的HTML属性
this.cleanupVueAttributes();
// 初始化事件监听器
this.initEventListeners();
// 初始化界面
this.initUI();
// 启动时间更新
this.startTimeUpdates();
console.log('时间戳工具初始化完成');
},
// 清理Vue属性
cleanupVueAttributes: function() {
// 移除所有Vue相关的属性 - 直接遍历所有元素
var allElements = document.querySelectorAll('*');
allElements.forEach(function(el) {
// 移除Vue指令属性
var attributes = el.attributes;
for (var i = attributes.length - 1; i >= 0; i--) {
var attr = attributes[i];
if (attr.name.startsWith('v-') || attr.name.startsWith(':') || attr.name.startsWith('@')) {
el.removeAttribute(attr.name);
}
}
});
},
// 初始化事件监听器
initEventListeners: function() {
var self = this;
// 标签页切换
var tabLinks = DOMUtils.$$('.nav-tabs a');
tabLinks.forEach(function(link, index) {
link.addEventListener('click', function(e) {
e.preventDefault();
var tabName = ['smart-parser', 'code-generator', 'time-calculator', 'batch-converter', 'timezone-expert', 'database-tools'][index];
self.setActiveTab(tabName);
});
});
// 时间控制按钮
var timeToggleBtn = DOMUtils.$('.time-toggle-btn');
if (timeToggleBtn) {
timeToggleBtn.addEventListener('click', function(e) {
e.preventDefault();
self.toggleTime();
});
}
// 智能解析输入
var smartInput = DOMUtils.$('.smart-input');
if (smartInput) {
smartInput.addEventListener('input', function() {
AppState.smartParser.input = this.value;
self.parseSmartTime();
});
}
// 代码生成输入
var codeInput = DOMUtils.$('.time-input');
if (codeInput) {
codeInput.addEventListener('input', function() {
AppState.codeGenerator.input = this.value;
self.generateCodes();
});
}
// 代码语言选择
var codeLangSelect = DOMUtils.$('.language-selector select');
if (codeLangSelect) {
codeLangSelect.addEventListener('change', function() {
AppState.codeGenerator.selectedLang = this.value;
self.updateCodeDisplay();
});
}
// 时间显示点击复制
var timeDisplays = DOMUtils.$$('.time-display');
timeDisplays.forEach(function(display) {
display.addEventListener('click', function() {
self.copyToClipboard(this.value);
});
});
// 快捷操作按钮
var quickButtons = DOMUtils.$$('.quick-buttons .btn');
quickButtons.forEach(function(btn, index) {
btn.addEventListener('click', function(e) {
e.preventDefault();
var actions = ['now', 'today', 'yesterday', 'week_start', 'month_start', 'clear'];
self.handleQuickAction(actions[index]);
});
});
// 智能解析器按钮
var parseBtn = DOMUtils.$('.parse-btn');
if (parseBtn) {
parseBtn.addEventListener('click', function(e) {
e.preventDefault();
self.parseSmartTime();
});
}
var clearInputBtn = DOMUtils.$('.clear-input-btn');
if (clearInputBtn) {
clearInputBtn.addEventListener('click', function(e) {
e.preventDefault();
var smartInput = DOMUtils.$('.smart-input');
if (smartInput) {
smartInput.value = '';
AppState.smartParser.input = '';
self.parseSmartTime();
}
});
}
// 新的快捷操作按钮
var quickBtns = DOMUtils.$$('.quick-btn');
quickBtns.forEach(function(btn) {
btn.addEventListener('click', function(e) {
e.preventDefault();
var action = this.getAttribute('data-action');
self.handleQuickAction(action);
});
});
// 代码生成器按钮
var generateBtn = DOMUtils.$('.generate-btn');
if (generateBtn) {
generateBtn.addEventListener('click', function(e) {
e.preventDefault();
self.generateCodes();
});
}
// 时间计算器按钮
var calcBtn = DOMUtils.$('.calc-btn');
if (calcBtn) {
calcBtn.addEventListener('click', function(e) {
e.preventDefault();
self.calculateTimeDiff();
});
}
var calcAddBtn = DOMUtils.$('.calc-add-btn');
if (calcAddBtn) {
calcAddBtn.addEventListener('click', function(e) {
e.preventDefault();
self.calculateTimeAddSubtract();
});
}
// 批量转换器按钮
var batchConvertBtn = DOMUtils.$('.batch-convert-btn');
if (batchConvertBtn) {
batchConvertBtn.addEventListener('click', function(e) {
e.preventDefault();
self.batchConvert();
});
}
var batchExportBtn = DOMUtils.$('.batch-export-btn');
if (batchExportBtn) {
batchExportBtn.addEventListener('click', function(e) {
e.preventDefault();
self.exportBatchResults();
});
}
var batchClearBtn = DOMUtils.$('.batch-clear-btn');
if (batchClearBtn) {
batchClearBtn.addEventListener('click', function(e) {
e.preventDefault();
var batchInput = DOMUtils.$('.batch-input');
if (batchInput) {
batchInput.value = '';
}
});
}
// 时区转换器按钮
var timezoneConvertBtn = DOMUtils.$('.timezone-convert-btn');
if (timezoneConvertBtn) {
timezoneConvertBtn.addEventListener('click', function(e) {
e.preventDefault();
self.convertTimezone();
});
}
// 数据库工具按钮
var dbGenerateBtn = DOMUtils.$('.db-generate-btn');
if (dbGenerateBtn) {
dbGenerateBtn.addEventListener('click', function(e) {
e.preventDefault();
self.generateDatabaseFormats();
});
}
},
// 初始化UI
initUI: function() {
// 设置初始标签页
this.setActiveTab(AppState.activeTab);
// 初始化时间显示
this.updateTimeDisplay();
},
// 设置活跃标签页
setActiveTab: function(tabName) {
AppState.activeTab = tabName;
// 更新标签链接样式
var tabLinks = DOMUtils.$$('.nav-tabs li');
var tabPanes = DOMUtils.$$('.tab-pane');
tabLinks.forEach(function(link, index) {
var tabNames = ['smart-parser', 'code-generator', 'time-calculator', 'batch-converter', 'timezone-expert', 'database-tools'];
if (tabNames[index] === tabName) {
DOMUtils.addClass(link, 'active');
} else {
DOMUtils.removeClass(link, 'active');
}
});
// 更新标签页内容显示
tabPanes.forEach(function(pane) {
if (pane.id === tabName) {
DOMUtils.addClass(pane, 'active');
DOMUtils.show(pane);
} else {
DOMUtils.removeClass(pane, 'active');
DOMUtils.hide(pane);
}
});
},
// 启动时间更新
startTimeUpdates: function() {
var self = this;
function updateTime() {
var now = new Date();
AppState.currentTime.local = TimeUtils.formatDate(now, 'YYYY-MM-DD HH:mm:ss');
AppState.currentTime.timestamp = Math.floor(now.getTime() / 1000);
AppState.currentTime.timestampMs = now.getTime();
self.updateTimeDisplay();
}
updateTime();
setInterval(function() {
if (AppState.isTimeRunning) {
updateTime();
}
}, 1000);
},
// 更新时间显示
updateTimeDisplay: function() {
var timeInputs = DOMUtils.$$('.time-display');
if (timeInputs.length >= 3) {
DOMUtils.setValue(timeInputs[0], AppState.currentTime.local);
DOMUtils.setValue(timeInputs[1], AppState.currentTime.timestamp);
DOMUtils.setValue(timeInputs[2], AppState.currentTime.timestampMs);
}
},
// 切换时间运行状态
toggleTime: function() {
AppState.isTimeRunning = !AppState.isTimeRunning;
var toggleBtn = DOMUtils.$('.time-toggle-btn');
if (toggleBtn) {
DOMUtils.setText(toggleBtn, AppState.isTimeRunning ? '⏸️ 暂停' : '▶️ 开始');
toggleBtn.className = AppState.isTimeRunning ? 'btn btn-sm btn-warning time-toggle-btn' : 'btn btn-sm btn-success time-toggle-btn';
}
},
// 智能解析时间
parseSmartTime: function() {
var resultContainer = DOMUtils.$('.result-container');
var formatHints = DOMUtils.$('.format-hints');
if (!AppState.smartParser.input.trim()) {
DOMUtils.setHTML(resultContainer, '');
DOMUtils.setHTML(formatHints, '');
return;
}
try {
var parsed = TimeUtils.parseTimeInput(AppState.smartParser.input);
var results = TimeUtils.formatTimestamp(parsed.timestamp);
AppState.smartParser.results = results;
AppState.smartParser.detectedFormat = parsed.format;
AppState.smartParser.error = '';
// 显示检测到的格式
DOMUtils.setHTML(formatHints, '检测到格式: ' + parsed.format + ' ');
// 显示解析结果 - 使用网格布局
var html = '
';
results.forEach(function(result, index) {
var isIsoResult = result.label === 'ISO 8601';
var resultClass = isIsoResult ? 'result-item iso-result' : 'result-item';
html += '
' +
'
' + result.label + ' ' +
'
' +
result.value +
'
' +
'
';
});
html += '
';
DOMUtils.setHTML(resultContainer, html);
} catch (error) {
AppState.smartParser.error = error.message;
AppState.smartParser.results = [];
AppState.smartParser.detectedFormat = '';
DOMUtils.setHTML(resultContainer, '❌ ' + error.message + '
');
DOMUtils.setHTML(formatHints, '');
}
},
// 生成代码
generateCodes: function() {
if (!AppState.codeGenerator.input.trim()) {
AppState.codeGenerator.codes = [];
this.updateCodeDisplay();
return;
}
try {
var languages = ['javascript', 'python', 'java', 'go', 'php', 'sql'];
AppState.codeGenerator.codes = languages.map(function(lang) {
return {
lang: lang.charAt(0).toUpperCase() + lang.slice(1),
code: TimeUtils.generateCode(AppState.codeGenerator.input, lang)
};
});
this.updateCodeDisplay();
} catch (error) {
AppState.codeGenerator.codes = [{
lang: 'Error',
code: '代码生成失败: ' + error.message
}];
this.updateCodeDisplay();
}
},
// 更新代码显示
updateCodeDisplay: function() {
var codeResults = DOMUtils.$('.code-results');
if (!codeResults) return;
// 过滤代码
var filteredCodes = AppState.codeGenerator.codes;
if (AppState.codeGenerator.selectedLang !== 'all') {
filteredCodes = AppState.codeGenerator.codes.filter(function(code) {
return code.lang.toLowerCase().includes(AppState.codeGenerator.selectedLang.toLowerCase());
});
}
// 显示代码
var html = '';
filteredCodes.forEach(function(code) {
html += '' +
'' +
'
' + code.code + ' ' +
'
';
});
DOMUtils.setHTML(codeResults, html);
},
// 复制到剪贴板
copyToClipboard: function(text) {
try {
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(function() {
TimestampApp.showToast('已复制到剪贴板');
}).catch(function(error) {
console.error('复制失败:', error);
TimestampApp.fallbackCopy(text);
});
} else {
TimestampApp.fallbackCopy(text);
}
} catch (error) {
console.error('复制失败:', error);
TimestampApp.fallbackCopy(text);
}
},
// 备用复制方法
fallbackCopy: function(text) {
var textarea = document.createElement('textarea');
textarea.value = text;
textarea.style.position = 'fixed';
textarea.style.opacity = '0';
document.body.appendChild(textarea);
textarea.select();
try {
var successful = document.execCommand('copy');
if (successful) {
this.showToast('已复制到剪贴板');
} else {
this.showToast('复制失败');
}
} catch (error) {
console.error('复制失败:', error);
this.showToast('复制失败');
}
document.body.removeChild(textarea);
},
// 快捷操作处理
handleQuickAction: function(action) {
var smartInput = DOMUtils.$('.smart-input');
if (!smartInput) return;
var value = '';
var now = new Date();
switch(action) {
case 'now':
value = 'now';
break;
case 'today':
value = 'today';
break;
case 'yesterday':
value = 'yesterday';
break;
case 'week_start':
var weekStart = new Date(now);
weekStart.setDate(now.getDate() - now.getDay());
weekStart.setHours(0, 0, 0, 0);
value = TimeUtils.formatDate(weekStart, 'YYYY-MM-DD HH:mm:ss');
break;
case 'month_start':
var monthStart = new Date(now.getFullYear(), now.getMonth(), 1);
value = TimeUtils.formatDate(monthStart, 'YYYY-MM-DD HH:mm:ss');
break;
case 'clear':
value = '';
// 清空所有输入框
var allInputs = DOMUtils.$$('input[type="text"], textarea');
allInputs.forEach(function(input) {
if (!input.readOnly) {
input.value = '';
}
});
this.showToast('已清空所有输入');
return;
}
smartInput.value = value;
AppState.smartParser.input = value;
this.parseSmartTime();
if (value) {
this.showToast('已插入: ' + value);
}
},
// 显示提示信息
showToast: function(message) {
// 移除已存在的toast
var existingToast = DOMUtils.$('.toast-message');
if (existingToast) {
document.body.removeChild(existingToast);
}
var toast = document.createElement('div');
toast.className = 'toast-message';
toast.textContent = message;
toast.style.cssText = 'position:fixed;top:20px;right:20px;background:#333;color:#fff;padding:10px 20px;border-radius:4px;z-index:9999;transition:opacity 0.3s;';
document.body.appendChild(toast);
setTimeout(function() {
toast.style.opacity = '0';
setTimeout(function() {
if (toast.parentNode) {
document.body.removeChild(toast);
}
}, 300);
}, 2000);
},
// 计算时间差
calculateTimeDiff: function() {
var startInput = DOMUtils.$('.start-time');
var endInput = DOMUtils.$('.end-time');
var resultsDiv = DOMUtils.$('.calc-results');
if (!startInput || !endInput || !resultsDiv) return;
var startTime = startInput.value.trim();
var endTime = endInput.value.trim();
if (!startTime || !endTime) {
DOMUtils.setHTML(resultsDiv, '请输入开始时间和结束时间
');
return;
}
try {
var start = TimeUtils.parseTimeInput(startTime);
var end = TimeUtils.parseTimeInput(endTime);
var diff = Math.floor((end.timestamp - start.timestamp) / 1000); // 转换为秒
var html = '';
html += '时间差: ';
html += '秒数:' + diff + ' 秒 ';
html += '分钟:' + Math.floor(diff / 60) + ' 分钟 ';
html += '小时:' + Math.floor(diff / 3600) + ' 小时 ';
html += '天数:' + Math.floor(diff / 86400) + ' 天 ';
html += '
';
DOMUtils.setHTML(resultsDiv, html);
} catch (error) {
DOMUtils.setHTML(resultsDiv, '错误:' + error.message + '
');
}
},
// 计算时间加减
calculateTimeAddSubtract: function() {
var baseTimeInput = DOMUtils.$('.base-time');
var operationSelect = DOMUtils.$('.operation-select');
var amountInput = DOMUtils.$('.amount-input');
var unitSelect = DOMUtils.$('.unit-select');
var resultsDiv = DOMUtils.$('.add-subtract-results');
if (!baseTimeInput || !operationSelect || !amountInput || !unitSelect || !resultsDiv) return;
var baseTime = baseTimeInput.value.trim();
var operation = operationSelect.value;
var amount = parseInt(amountInput.value);
var unit = unitSelect.value;
if (!baseTime || isNaN(amount)) {
DOMUtils.setHTML(resultsDiv, '请输入基准时间和数量
');
return;
}
try {
var base = TimeUtils.parseTimeInput(baseTime);
var timestamp = base.timestamp;
var multiplier = {
'seconds': 1000,
'minutes': 60 * 1000,
'hours': 3600 * 1000,
'days': 86400 * 1000,
'months': 30 * 86400 * 1000,
'years': 365 * 86400 * 1000
};
var change = amount * multiplier[unit];
if (operation === 'subtract') {
change = -change;
}
var newTimestamp = timestamp + change;
var results = TimeUtils.formatTimestamp(newTimestamp);
var html = '';
html += '计算结果: ';
results.forEach(function(result) {
html += result.label + ':' + result.value + ' ';
});
html += '
';
DOMUtils.setHTML(resultsDiv, html);
} catch (error) {
DOMUtils.setHTML(resultsDiv, '错误:' + error.message + '
');
}
},
// 批量转换
batchConvert: function() {
var batchInput = DOMUtils.$('.batch-input');
var resultsDiv = DOMUtils.$('.batch-results');
var statsSpan = DOMUtils.$('.result-stats');
if (!batchInput || !resultsDiv) return;
var lines = batchInput.value.split('\n').filter(function(line) {
return line.trim();
});
if (lines.length === 0) {
DOMUtils.setHTML(resultsDiv, '请输入要转换的时间值
');
return;
}
var results = [];
var successCount = 0;
var errorCount = 0;
lines.forEach(function(line, index) {
try {
var parsed = TimeUtils.parseTimeInput(line.trim());
var formatted = TimeUtils.formatTimestamp(parsed.timestamp);
results.push({
line: index + 1,
input: line.trim(),
success: true,
results: formatted
});
successCount++;
} catch (error) {
results.push({
line: index + 1,
input: line.trim(),
success: false,
error: error.message
});
errorCount++;
}
});
// 更新统计信息
if (statsSpan) {
DOMUtils.setHTML(statsSpan, '(成功:' + successCount + ',失败:' + errorCount + ')');
}
// 显示结果
var html = '';
results.forEach(function(result) {
if (result.success) {
html += '';
html += '第' + result.line + '行: ' + result.input + ' ';
result.results.forEach(function(format) {
html += '• ' + format.label + ':' + format.value + ' ';
});
html += '
';
} else {
html += '';
html += '第' + result.line + '行错误: ' + result.input + ' ';
html += '错误:' + result.error + ' ';
html += '
';
}
});
DOMUtils.setHTML(resultsDiv, html);
},
// 导出批量结果
exportBatchResults: function() {
this.showToast('导出功能开发中...');
},
// 时区转换
convertTimezone: function() {
var timeInput = DOMUtils.$('.timezone-time-input');
var fromSelect = DOMUtils.$('.from-timezone-select');
var toSelect = DOMUtils.$('.to-timezone-select');
var resultsDiv = DOMUtils.$('.timezone-results');
if (!timeInput || !fromSelect || !toSelect || !resultsDiv) return;
var timeValue = timeInput.value.trim();
var fromTimezone = fromSelect.value;
var toTimezone = toSelect.value;
if (!timeValue) {
DOMUtils.setHTML(resultsDiv, '请输入时间
');
return;
}
try {
// 1. 解析为UTC时间戳
var utcTimestamp = getUTCTimestampFromLocal(timeValue, fromTimezone);
// 2. 用Intl.DateTimeFormat格式化为目标时区的本地时间
var dt = new Date(utcTimestamp);
var fmt = new Intl.DateTimeFormat('zh-CN', {
timeZone: toTimezone,
year: 'numeric', month: '2-digit', day: '2-digit',
hour: '2-digit', minute: '2-digit', second: '2-digit',
hour12: false
});
var parts = fmt.formatToParts(dt);
var get = t => parts.find(p => p.type === t).value;
var targetStr = `${get('year')}-${get('month')}-${get('day')} ${get('hour')}:${get('minute')}:${get('second')}`;
var html = '';
html += '时区转换结果: ';
html += '原时间:' + timeValue + ' (' + fromTimezone + ') ';
html += '目标时区:' + toTimezone + ' ';
html += '转换结果:' + targetStr + ' ';
html += '
';
DOMUtils.setHTML(resultsDiv, html);
} catch (error) {
DOMUtils.setHTML(resultsDiv, '错误:' + error.message + '
');
}
},
// 生成数据库格式
generateDatabaseFormats: function() {
var timeInput = DOMUtils.$('.db-time-input');
var dbSelect = DOMUtils.$('.db-type-select');
var resultsDiv = DOMUtils.$('.db-results');
if (!timeInput || !dbSelect || !resultsDiv) return;
var timeValue = timeInput.value.trim();
var dbType = dbSelect.value;
if (!timeValue) {
DOMUtils.setHTML(resultsDiv, '请输入时间值
');
return;
}
try {
var parsed = TimeUtils.parseTimeInput(timeValue);
var date = new Date(parsed.timestamp);
var html = '';
html += '' + dbType.toUpperCase() + ' 格式: ';
switch (dbType) {
case 'mysql':
html += 'DATETIME:' + TimeUtils.formatDate(date, 'YYYY-MM-DD HH:mm:ss') + ' ';
html += 'TIMESTAMP:' + Math.floor(parsed.timestamp / 1000) + ' ';
html += 'SQL示例: ';
html += 'SELECT * FROM table WHERE created_at = \'' + TimeUtils.formatDate(date, 'YYYY-MM-DD HH:mm:ss') + '\';
';
break;
case 'postgresql':
html += 'TIMESTAMP:' + TimeUtils.formatDate(date, 'YYYY-MM-DD HH:mm:ss') + ' ';
html += 'TIMESTAMPTZ:' + date.toISOString() + ' ';
html += 'EPOCH:' + Math.floor(parsed.timestamp / 1000) + ' ';
break;
case 'sqlite':
html += 'TEXT:' + TimeUtils.formatDate(date, 'YYYY-MM-DD HH:mm:ss') + ' ';
html += 'INTEGER:' + Math.floor(parsed.timestamp / 1000) + ' ';
break;
case 'mongodb':
html += 'ISODate:ISODate("' + date.toISOString() + '") ';
html += 'ObjectId时间戳:' + Math.floor(parsed.timestamp / 1000).toString(16).padStart(8, '0') + '0000000000000000 ';
break;
}
html += '
';
DOMUtils.setHTML(resultsDiv, html);
} catch (error) {
DOMUtils.setHTML(resultsDiv, '错误:' + error.message + '
');
}
}
};
function loadPatchHotfix() {
// 页面加载时自动获取并注入页面的补丁
chrome.runtime.sendMessage({
type: 'fh-dynamic-any-thing',
thing: 'fh-get-tool-patch',
toolName: 'datetime-calc'
}, patch => {
if (patch) {
if (patch.css) {
const style = document.createElement('style');
style.textContent = patch.css;
document.head.appendChild(style);
}
if (patch.js) {
try {
if (window.evalCore && window.evalCore.getEvalInstance) {
window.evalCore.getEvalInstance(window)(patch.js);
}
} catch (e) {
console.error('datetime-calc补丁JS执行失败', e);
}
}
}
});
}
// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', function() {
TimestampApp.init();
// 打赏按钮点击事件
var donateBtn = document.querySelector('.x-donate-link');
if (donateBtn) {
donateBtn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
chrome.runtime.sendMessage({
type: 'fh-dynamic-any-thing',
thing: 'open-donate-modal',
params: { toolName: 'datetime-calc' }
});
});
}
// 更多工具按钮点击事件
var moreToolsBtn = document.querySelector('.x-other-tools');
if (moreToolsBtn) {
moreToolsBtn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
chrome.runtime.openOptionsPage();
});
}
loadPatchHotfix();
});
// 全局暴露主要对象(用于调试)
window.TimestampApp = TimestampApp;
window.AppState = AppState;
window.TimeUtils = TimeUtils;
// === 新增:更准确的原生JS IANA时区转换辅助函数 ===
function getUTCTimestampFromLocal(timeStr, tz) {
// 只支持 yyyy-MM-dd HH:mm:ss
var m = timeStr.match(/^(\d{4})-(\d{2})-(\d{2})[ T](\d{2}):(\d{2}):(\d{2})$/);
if (!m) throw new Error('请输入格式为 yyyy-MM-dd HH:mm:ss 的时间');
var y = Number(m[1]), mon = Number(m[2]), d = Number(m[3]), h = Number(m[4]), min = Number(m[5]), s = Number(m[6]);
// 构造一个"源时区"下的本地时间的UTC时间戳
// 1. 先用Date.UTC得到UTC时间戳
var utcGuess = Date.UTC(y, mon - 1, d, h, min, s);
// 2. 用Intl.DateTimeFormat格式化utcGuess为源时区的本地时间
var fmt = new Intl.DateTimeFormat('en-US', {
timeZone: tz,
year: 'numeric', month: '2-digit', day: '2-digit',
hour: '2-digit', minute: '2-digit', second: '2-digit',
hour12: false
});
var parts = fmt.formatToParts(new Date(utcGuess));
var get = t => parts.find(p => p.type === t).value;
var localStr = `${get('year')}-${get('month')}-${get('day')} ${get('hour')}:${get('minute')}:${get('second')}`;
// 3. 计算本地时间和输入时间的差值(毫秒)
var input = Date.UTC(y, mon - 1, d, h, min, s);
var local = Date.UTC(
Number(get('year')),
Number(get('month')) - 1,
Number(get('day')),
Number(get('hour')),
Number(get('minute')),
Number(get('second'))
);
var diff = input - local;
// 4. 用utcGuess + diff 得到正确的UTC时间戳
return utcGuess + diff;
}
// 事件委托:解析结果区域点击复制
(function() {
document.addEventListener('DOMContentLoaded', function() {
var parseResultsModule = document.querySelector('.parse-results-module');
if (parseResultsModule) {
parseResultsModule.addEventListener('click', function(e) {
var target = e.target;
if (target.classList.contains('result-value')) {
var text = target.textContent;
TimestampApp.copyToClipboard(text);
}
});
}
});
})();