Unix 时间戳转换
时间戳与日期时间双向互转,秒 / 毫秒 / 微秒 / 纳秒自动识别,可切换任意时区,另附 20 种编程语言与数据库的写法。
时区只影响「普通时间」的显示与解析,时间戳本身与时区无关。
当前 Unix 时间戳
取的是本机时间,本机时钟不准这里也会不准。
时间戳 → 普通时间
按位数自动判断单位:10 位为秒、13 位为毫秒、16 位为微秒、19 位为纳秒。
普通时间 → 时间戳
支持 2026-09-21 12:00:00、2026/9/21、2026年9月21日、2026-09-21T12:00:00Z、2026-09-21T12:00:00+08:00 等写法;只写日期按当天零点算。带 Z 或 ±时区后缀时,以写法里的时区为准。
什么是 Unix 时间戳
Unix 时间戳(Unix timestamp),也叫 Unix 时间(Unix time)、POSIX 时间(POSIX time)、纪元时间(Epoch time),是从协调世界时(UTC)1970 年 1 月 1 日 00:00:00 起到当前时刻所经过的总秒数,不计闰秒。它起源于 Unix 系统,如今在类 Unix 系统、Windows、各类数据库和几乎所有编程语言里都被广泛采用。
时间戳是一个纯数字,本身不带时区。同一个时间戳在北京是 12:00,在伦敦就是 04:00 —— 变的只是显示方式,数值完全一样。所以在接口传参、日志记录、数据库存储里用时间戳,可以彻底绕开时区和夏令时的坑,只在展示给人看的那一步再按时区格式化。
常见的精度有四种:秒(10 位,如 1774000000)、毫秒(13 位,Java 的 System.currentTimeMillis、JavaScript 的 Date.now 都是它)、微秒(16 位)、纳秒(19 位,Go 的 UnixNano)。拿到一串数字先数位数,基本就能判断单位;两个系统对接时单位不一致,是时间对不上最常见的原因。
用 32 位有符号整数存秒级时间戳时,最大值是 2147483647,对应 UTC 的 2038-01-19 03:14:07,再往后就会溢出成负数,这就是所谓的「2038 年问题」(Y2K38)。现在新写的代码应该用 64 位整型存时间戳。
另外注意 Unix 时间戳不包含闰秒:闰秒发生时,同一个时间戳会被复用一秒,所以它严格来说不是「自 1970 年以来真实流逝的秒数」,而是一种按每天固定 86400 秒计算的约定。
各编程语言的时间戳写法
点代码即可复制。示例中的 ts 代表秒级时间戳,s 代表时间字符串。
获取当前 Unix 时间戳
| 语言 | 代码 | 备注 |
|---|---|---|
| JavaScript | Math.floor(Date.now() / 1000) | Date.now() 本身是毫秒 |
| Java | Instant.now().getEpochSecond() | 旧写法 System.currentTimeMillis() / 1000L |
| PHP | time() | 毫秒用 (int)(microtime(true) * 1000) |
| Python | import time int(time.time()) |
time.time() 返回带小数的秒 |
| Go | time.Now().Unix() | 毫秒 time.Now().UnixMilli() |
| C# / .NET | DateTimeOffset.UtcNow.ToUnixTimeSeconds() | .NET Framework 4.6+ |
| Ruby | Time.now.to_i | |
| Rust | SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() | 需 use std::time::{SystemTime, UNIX_EPOCH} |
| C / C++ | time(NULL) | 头文件 time.h |
| Swift | Int(Date().timeIntervalSince1970) | |
| Kotlin | System.currentTimeMillis() / 1000 | |
| Perl | time | |
| Lua | os.time() | |
| Shell | date +%s | Linux / macOS 通用 |
| MySQL | SELECT UNIX_TIMESTAMP() | 等价 UNIX_TIMESTAMP(NOW()) |
| PostgreSQL | SELECT EXTRACT(EPOCH FROM NOW()) | |
| SQL Server | SELECT DATEDIFF(s, '1970-01-01', GETUTCDATE()) | 2038 年后请用 DATEDIFF_BIG |
| SQLite | SELECT strftime('%s', 'now') | |
| Oracle | SELECT (SYSDATE - TO_DATE('1970-01-01', 'YYYY-MM-DD')) * 86400 FROM dual | SYSDATE 为数据库服务器本地时间 |
| Excel | =(NOW() - DATE(1970,1,1)) * 86400 - 8 * 3600 | 单元格是北京时间,所以减 8 小时 |
Unix 时间戳 → 普通时间
| 语言 | 代码 | 备注 |
|---|---|---|
| JavaScript | new Date(ts * 1000).toLocaleString() | 按浏览器所在时区显示 |
| Java | LocalDateTime.ofInstant(Instant.ofEpochSecond(ts), ZoneId.of("Asia/Shanghai")) | |
| PHP | date('Y-m-d H:i:s', $ts) | 受 date_default_timezone_set 影响 |
| Python | import time time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(ts)) |
UTC 用 time.gmtime(ts) |
| Go | time.Unix(ts, 0).Format("2006-01-02 15:04:05") | Go 的格式串是固定的参考时间 |
| C# / .NET | DateTimeOffset.FromUnixTimeSeconds(ts).LocalDateTime | |
| Ruby | Time.at(ts).strftime('%Y-%m-%d %H:%M:%S') | |
| Rust | chrono::DateTime::from_timestamp(ts, 0).unwrap() | 需 chrono crate |
| C / C++ | time_t t = ts; strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&t)); |
|
| Swift | Date(timeIntervalSince1970: TimeInterval(ts)) | |
| Kotlin | Instant.ofEpochSecond(ts).atZone(ZoneId.systemDefault()) | |
| Perl | scalar localtime($ts) | |
| Lua | os.date('%Y-%m-%d %H:%M:%S', ts) | |
| Shell | date -d @ts '+%F %T' # GNU / Linux date -r ts '+%F %T' # macOS / BSD |
两个系统参数不一样 |
| MySQL | SELECT FROM_UNIXTIME(ts) | 可带格式 FROM_UNIXTIME(ts, '%Y-%m-%d') |
| PostgreSQL | SELECT TO_TIMESTAMP(ts) | |
| SQL Server | SELECT DATEADD(s, ts, '1970-01-01 00:00:00') | 结果是 UTC 时间 |
| SQLite | SELECT datetime(ts, 'unixepoch', 'localtime') | |
| Oracle | SELECT TO_DATE('1970-01-01', 'YYYY-MM-DD') + ts / 86400 FROM dual | |
| Excel | =(ts + 8 * 3600) / 86400 + DATE(1970,1,1) | 再把单元格设成日期格式 |
普通时间 → Unix 时间戳
| 语言 | 代码 | 备注 |
|---|---|---|
| JavaScript | Math.floor(new Date('2026-09-21T12:00:00+08:00').getTime() / 1000) | 写全时区才不会因浏览器时区而变 |
| Java | LocalDateTime.parse("2026-09-21T12:00:00").toEpochSecond(ZoneOffset.ofHours(8)) | |
| PHP | strtotime('2026-09-21 12:00:00') | 也可 mktime(12, 0, 0, 9, 21, 2026) |
| Python | from datetime import datetime int(datetime.strptime('2026-09-21 12:00:00', '%Y-%m-%d %H:%M:%S').timestamp()) |
|
| Go | t, _ := time.ParseInLocation("2006-01-02 15:04:05", s, time.Local) t.Unix() |
time.Parse 按 UTC 解析 |
| C# / .NET | new DateTimeOffset(dt, TimeSpan.FromHours(8)).ToUnixTimeSeconds() | |
| Ruby | require 'time' Time.parse('2026-09-21 12:00:00').to_i |
|
| Rust | NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S")?.and_utc().timestamp() | 需 chrono crate |
| C / C++ | struct tm tm = {0}; strptime("2026-09-21 12:00:00", "%Y-%m-%d %H:%M:%S", &tm); mktime(&tm); |
mktime 按本地时区 |
| Swift | formatter.date(from: s)!.timeIntervalSince1970 | formatter 为 DateFormatter |
| Kotlin | LocalDateTime.parse(s).atZone(ZoneId.systemDefault()).toEpochSecond() | |
| Perl | use Time::Local; timelocal($sec, $min, $hour, $day, $mon - 1, $year) |
月份从 0 开始 |
| Lua | os.time({year = 2026, month = 9, day = 21, hour = 12, min = 0, sec = 0}) | |
| Shell | date -d '2026-09-21 12:00:00' +%s # GNU date -j -f '%Y-%m-%d %H:%M:%S' '2026-09-21 12:00:00' +%s # macOS |
|
| MySQL | SELECT UNIX_TIMESTAMP('2026-09-21 12:00:00') | 按会话 time_zone 解释 |
| PostgreSQL | SELECT EXTRACT(EPOCH FROM TIMESTAMP '2026-09-21 12:00:00') | |
| SQL Server | SELECT DATEDIFF(s, '1970-01-01 00:00:00', '2026-09-21 12:00:00') | |
| SQLite | SELECT strftime('%s', '2026-09-21 12:00:00') | 字符串按 UTC 解释 |
| Oracle | SELECT (TO_DATE('2026-09-21 12:00:00', 'YYYY-MM-DD HH24:MI:SS') - TO_DATE('1970-01-01', 'YYYY-MM-DD')) * 86400 FROM dual |
|
| Excel | =(A1 - DATE(1970,1,1)) * 86400 - 8 * 3600 | A1 为北京时间的日期单元格 |
几个常被用到的时间戳
| 时间戳 | 北京时间(UTC+8) | 说明 |
|---|---|---|
| 0 | 1970-01-01 08:00:00 | Unix 纪元起点,UTC 的 1970-01-01 00:00:00 |
| 1000000000 | 2001-09-09 09:46:40 | 十亿秒,时间戳首次进到 10 位 |
| 1234567890 | 2009-02-14 07:31:30 | 被程序员当节日过的顺序数 |
| 1500000000 | 2017-07-14 10:40:00 | |
| 2000000000 | 2033-05-18 11:33:20 | |
| 2147483647 | 2038-01-19 11:14:07 | 32 位有符号整数上限,即「2038 年问题」 |
| 4102444800 | 2100-01-01 08:00:00 | UTC 的 2100-01-01 00:00:00 |