一、时间戳是什么?

时间戳(Timestamp),简单来说就是从1970年1月1日0时0分0秒(UTC) 到当前时间点所经过的秒数(或毫秒数)。这个起点在计算机领域被称为 “时间纪元”(Epoch Time) 。

举个例子,时间戳 1717248000000 这个数字,对应的就是2024年6月1日00:00:00 UTC——不过在不同时区的本地时间会不同,比如北京时间是2024年6月1日08:00:00。

一个关键概念:时间戳是“绝对时间”,不随时区变化。同一个时间戳 1717248000000,在纽约是2024年5月31日16:00:00,在北京是2024年6月1日08:00:00,但时间戳本身完全一样

二、为什么是1970年1月1日?——时间戳的来历

2.1 Unix的诞生

1969年8月,贝尔实验室的程序员肯·汤普逊利用妻儿离开一个月的机会,在PDP-7机器上用B语言开发出了Unix操作系统的第一个版本。随后,汤普逊和同事丹尼斯·里奇改进了B语言,开发出了C语言,并用C语言重写了Unix,新版于1971年发布。

Unix诞生后,需要在操作系统上表示时间,于是Unix时间戳被定义出来——通过当前时间与一个“纪元时间”的差值(秒数)来表示时间。

2.2 从1971到1970的调整

最初,Unix的开发者把纪元时间定为了1971年1月1日——也就是Unix正式发布的时间。而且最初的时间戳也不是每1秒变动一次,而是每1/60秒变动一次

但问题很快就来了:当时的计算机系统是32位的,32位有符号整数最大值是 2^31 - 1 = 2147483647。如果用“每1/60秒变动一次”的方式来计算,Unix时间戳最多只能表示约828.5天——一个只能表示两年多时间的系统,显然不实用。

于是开发者做了一次重要调整:

  1. 把时间戳的变动频率从“每1/60秒”改为每1秒变动一次,可表示的时间一下子放大了60倍;

  2. 把纪元时间从1971-01-01向前调整到1970-01-01,方便记忆和使用。

从此,1970年1月1日00:00:00 UTC就成为了计算机世界的时间起点,并被后续几乎所有的编程语言和操作系统继承。

2.3 32位系统的“2038年问题”

32位系统能表示的最大秒数是 2147483647 秒,换算一下大约是68年。从1970年开始算,这个最大值将在2038年1月19日03:14:07到达。

过了这个时间点,32位系统的时钟会溢出回绕,变成1901年12月13日——这就是著名的 “2038年问题” 。好在随着64位系统的普及,这个问题已被大大缓解——64位时间戳可以支持到约2922亿年之后。

三、时间戳能做什么?——应用场景

时间戳在软件开发中应用极其广泛:

  • 日志记录:记录事件发生的精确时间,方便排查和分析问题

  • 数据库记录:记录数据的创建和修改时间

  • 缓存策略:基于时间戳判断缓存是否过期

  • 数据同步:在分布式系统中用时间戳确定数据的最新版本

  • 会话管理:设置会话的超时时间

  • 时间差计算:两个时间戳相减即可得到精确的时间差

  • 生成唯一ID:时间戳常作为唯一标识符的一部分

四、JavaScript中的时间戳操作

4.1 重要提醒:JS时间戳单位是毫秒

JavaScript中的时间戳是指从1970年1月1日00:00:00 UTC到当前时间的毫秒数。而很多后端语言(如PHP)的时间戳单位是

跨语言传递时间戳时,一定要注意单位换算:1秒 = 1000毫秒。

4.2 获取当前时间戳

javascript

// 方法1:Date.now() —— 最简洁,推荐
const timestamp = Date.now();
console.log(timestamp); // 示例:1717251689234

// 方法2:new Date().getTime() —— 兼容性好
const timestamp2 = new Date().getTime();

// 方法3:new Date().valueOf()
const timestamp3 = new Date().valueOf();

// 方法4:+new Date() —— 利用类型转换的“黑魔法”
const timestamp4 = +new Date();

Date.now() 是ES5.1新增的方法,语法最简单、性能最优,是日常开发的首选。如果需要兼容IE8及以下的老旧浏览器,则使用 new Date().getTime()

4.3 时间戳转Date对象

javascript

// 假设有一个毫秒级时间戳
const timestamp = 1717251689234;

// 直接传入Date构造函数
const date = new Date(timestamp);
console.log(date.toString()); 
// 输出:Sat Jun 01 2024 22:21:29 GMT+0800 (中国标准时间)

如果拿到的是秒级时间戳(比如从PHP接口返回的),需要先乘以1000再传入:

javascript

const secondsTimestamp = 1717251689; // 秒级时间戳
const date = new Date(secondsTimestamp * 1000);

4.4 时间戳转格式化日期字符串

方法一:使用Date对象的内置方法

javascript

function formatTimestamp(timestamp) {
    const date = new Date(timestamp);
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    const hours = String(date.getHours()).padStart(2, '0');
    const minutes = String(date.getMinutes()).padStart(2, '0');
    const seconds = String(date.getSeconds()).padStart(2, '0');
    return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}

console.log(formatTimestamp(1717251689234)); 
// 输出:2024-06-01 22:21:29
方法二:使用toLocaleString

javascript

const date = new Date(1717251689234);
// 转为本地时间字符串
console.log(date.toLocaleString()); 
// 输出:2024/6/1 22:21:29

// 可指定更多选项
console.log(date.toLocaleString('zh-CN', {
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit'
}));
方法三:使用toISOString(输出UTC时间)

javascript

const date = new Date(1717251689234);
console.log(date.toISOString()); 
// 输出:2024-06-01T14:21:29.234Z
// 注意:这里输出的是UTC时间,末尾的Z表示零时区

toISOString() 返回的是UTC格式的字符串,格式固定为 YYYY-MM-DDTHH:mm:ss.sssZ

4.5 日期字符串转时间戳

javascript

// 方法1:直接传字符串
const timestamp = new Date('2024-06-01 22:21:29').getTime();

// 方法2:传标准格式
const timestamp2 = new Date('2024-06-01T22:21:29+08:00').getTime();

// 方法3:使用Date.parse()
const timestamp3 = Date.parse('2024-06-01 22:21:29');

注意:不同浏览器对日期字符串的解析可能有差异,建议使用ISO标准格式 YYYY-MM-DDTHH:mm:ss

五、时区与时间戳

5.1 核心原则

时间戳本身不包含时区信息,它是一个绝对的、全球统一的时间度量

无论在世界的哪个角落,Date.now() 返回的值都是一样的。区别只在于将时间戳转换为人可读的日期时间时,会使用本地时区进行显示

5.2 查看当前时区偏移

javascript

// 获取当前时区与UTC的偏移量(分钟)
const offset = new Date().getTimezoneOffset();
console.log(offset); 
// 中国标准时间(UTC+8)输出:-480
// 注意:正值表示西时区,负值表示东时区

5.3 在不同时区显示时间

方法一:使用toLocaleString指定时区

javascript

const date = new Date(1717251689234);

// 显示为北京时间(UTC+8)
console.log(date.toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' }));
// 输出:2024/6/1 22:21:29

// 显示为纽约时间(UTC-4/5)
console.log(date.toLocaleString('en-US', { timeZone: 'America/New_York' }));
// 输出:6/1/2024, 10:21:29 AM

// 显示为伦敦时间(UTC+0/1)
console.log(date.toLocaleString('en-GB', { timeZone: 'Europe/London' }));
// 输出:01/06/2024, 15:21:29
方法二:使用Intl.DateTimeFormat

javascript

const date = new Date(1717251689234);

const formatter = new Intl.DateTimeFormat('zh-CN', {
    timeZone: 'America/New_York',
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit'
});

console.log(formatter.format(date));
// 输出:2024/06/01 10:21:29

Intl.DateTimeFormat 是JavaScript内置的国际化API,支持IANA时区标识符(如 Asia/ShanghaiAmerica/New_York),能正确处理夏令时。

方法三:手动进行时区偏移计算

javascript

/**
 * 将时间戳转换为指定时区的时间字符串
 * @param {number} timestamp - 毫秒级时间戳
 * @param {number} zoneOffset - 目标时区偏移小时数(如东八区为8)
 */
function convertToTimeZone(timestamp, zoneOffset) {
    const date = new Date(timestamp);
    // 获取本地时区与UTC的偏移(分钟)
    const localOffset = date.getTimezoneOffset();
    // 计算目标时区的时间戳
    const targetTime = timestamp + (localOffset + zoneOffset * 60) * 60000;
    return new Date(targetTime);
}

// 将时间戳转为北京时间(UTC+8)
const beijingTime = convertToTimeZone(1717251689234, 8);
console.log(beijingTime.toLocaleString());

5.4 实战:封装一个通用的时间格式化函数

javascript

/**
 * 格式化时间戳
 * @param {number|string} time - 时间戳(秒或毫秒)或Date对象
 * @param {string} format - 格式模板,如 '{y}-{m}-{d} {h}:{i}:{s}'
 * @param {number} zone - 目标时区,默认8(东八区)
 */
function parseTime(time, format = '{y}-{m}-{d} {h}:{i}:{s}', zone = 8) {
    if (!time) return null;
    
    let date;
    if (typeof time === 'object') {
        date = time;
    } else {
        // 如果是秒级时间戳(10位),转为毫秒
        if (String(time).length === 10) {
            time = parseInt(time) * 1000;
        }
        date = new Date(time);
    }
    
    // 时区调整
    const utc = time + date.getTimezoneOffset() * 60000;
    const wishTime = utc + 3600000 * zone;
    date = new Date(wishTime);
    
    const formatObj = {
        y: date.getFullYear(),
        m: date.getMonth() + 1,
        d: date.getDate(),
        h: date.getHours(),
        i: date.getMinutes(),
        s: date.getSeconds(),
        a: date.getDay()
    };
    
    return format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
        let value = formatObj[key];
        if (key === 'a') {
            return ['日', '一', '二', '三', '四', '五', '六'][value];
        }
        if (result.length > 0 && value < 10) {
            value = '0' + value;
        }
        return value || 0;
    });
}

// 使用示例
console.log(parseTime(Date.now(), '{y}-{m}-{d} {h}:{i}:{s}', 8));
// 输出:2024-06-01 22:21:29

这个函数参考了CSDN上常用的时间处理方案,支持秒级/毫秒级时间戳自动识别,并支持指定目标时区。

六、总结

要点 说明
定义 从1970-01-01 00:00:00 UTC到现在的秒数(或毫秒数)
起点 1970年1月1日,源于Unix操作系统的设计选择
特性 绝对时间,与时区无关,全球统一
JS单位 毫秒(注意与PHP等语言的秒区分)
获取 Date.now() / new Date().getTime()
转换 new Date(timestamp)
时区处理 toLocaleString() / Intl.DateTimeFormat

demo链接:时间戳转换工具 - 在线工具

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐