惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

A
Arctic Wolf
博客园 - 聂微东
F
Fortinet All Blogs
云风的 BLOG
云风的 BLOG
小众软件
小众软件
V
Visual Studio Blog
博客园 - 三生石上(FineUI控件)
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Apple Machine Learning Research
Apple Machine Learning Research
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The Cloudflare Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
The GitHub Blog
The GitHub Blog
Y
Y Combinator Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
博客园_首页
L
LangChain Blog
A
About on SuperTechFans
阮一峰的网络日志
阮一峰的网络日志
I
Intezer
T
The Blog of Author Tim Ferriss
Security Latest
Security Latest
C
CXSECURITY Database RSS Feed - CXSecurity.com
Know Your Adversary
Know Your Adversary
Simon Willison's Weblog
Simon Willison's Weblog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
P
Palo Alto Networks Blog
Scott Helme
Scott Helme
S
Secure Thoughts
Spread Privacy
Spread Privacy
T
Threat Research - Cisco Blogs
Attack and Defense Labs
Attack and Defense Labs
P
Privacy & Cybersecurity Law Blog
O
OpenAI News
H
Heimdal Security Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Help Net Security
Help Net Security
C
Cyber Attacks, Cyber Crime and Cyber Security
Blog — PlanetScale
Blog — PlanetScale
GbyAI
GbyAI
G
Google Developers Blog
博客园 - Franky
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
K
Kaspersky official blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
T
Tor Project blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
Tenable Blog
Google Online Security Blog
Google Online Security Blog
PCI Perspectives
PCI Perspectives

博客园 - 唯一浩哥

2026 年,macbook air 2015 升级硬盘注意事项 Java集合系列-HashSet Java基础系列-单例的7种写法 Java基础系列-Lambda Java基础系列-SPI你认识吗 Java基础系列-RandomAccess Java基础系列-Optional 那些字段适不适合建索引? Mysql笔记 Spring知识点 Java基础系列-浅拷贝和深拷贝 前端-javascript知识点 前端-jquery知识点 Java基础系列-substring的原理 - 唯一浩哥 - 博客园 Java设计模式之《抽象工厂模式》及使用场景 - 唯一浩哥 - 博客园 Java基础系列-Enum深入解析 - 唯一浩哥 - 博客园 Java基础系列-Collector和Collectors - 唯一浩哥 - 博客园 Java基础系列-Stream - 唯一浩哥 - 博客园 Java并发编程系列-AbstractQueuedSynchronizer - 唯一浩哥 - 博客园
Java基础系列-时间日期API
唯一浩哥 · 2020-10-13 · via 博客园 - 唯一浩哥

原创文章,转载请标注出处:https://www.cnblogs.com/V1haoge/p/10755253.html

一、概述

Java提供了有关时间的类和API,可以很方便的处理日期时间。

JDK 1.8之前使用的是Date和Calendar,JDK 1.8之后使用DateTime,前者毛病较多,后者更加适用。

二、基础知识

2.1 时区

我们都知道,地球是圆的,并且在不停的自转与公转,自转一圈是为一天,公转一圈是为一年。

我们这里关注自转的部分。

圆形的地球总是存在面向太阳的半球与背向太阳的半球,面向太阳的半球为白天,背向太阳的半球为黑夜,边界区域为凌晨和傍晚。

那么在这些处于地球不同位置的地区的时间也怎么分配的呢?

如果我们规定一个统一的时间,让全球共用。这样的话,0点时分,全球将拥有各种不同的景象,有的在凌晨,有的在早晨,有的在中午,有的在下午,有的在晚上等等,这也无关大雅。

但是当一个人从一个地方到另外一个地方后,他自认为的时间与光景将不再对应,这就是时差。

举个例子,比如规定中国晚上0点为统一的0点时间,而中国和美国都是在白天工作,晚上休息,但是中国是白天的时候,美国正好是晚上,一个人从中国到达美国之后,看到的就是人们在0点上班,12点休息,这与人的行为习惯相悖!

所以有了时区的概念,将全球以经线均分为24个时区,相邻时区的时间相差一个小时,当你跨越时区时,只要将你的手表调快或调慢一个小时即可,还是满足你的0点休息,12点上班的行为习惯。

实际上我们并没有绝对的使用标准的时区来划分时间,比如中国,横跨5个时区,为了国内的时间统一,我们规定统一使用北京时间为中国的时间。

2.2 格林威治时间

有了时区的概念,那么就有一个标准时间的问题了,以哪个地方为标准来定义时间呢?

那就是格林威治时间了,即GMT(Greenwich Mean Time)。

GMT表示的是格林威治平时,是指位于英国伦敦郊区的皇家格林尼治天文台当地的平太阳时,因为本初子午线被定义为通过那里的经线。

自1924年2月5日开始,格林尼治天文台负责每隔一小时向全世界发放调时信息。国际天文学联合会于1928年决定,将由格林威治平子夜起算的平太阳时作为世界时,也就是通常所说的格林威治时间。

比如中国北京位于东八区,所以北京时间即为GMT+8,即北京时间比格林威治平时快8个小时。

2.3 时间戳

时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总秒数。

这个值是全球固定值,全球通用,虽然各地的时间不同,但是时间戳是一致的。

有了时间戳,我们就是实现不同地区时间的转换。

三、Date/Calendar/SimpleDateFormat

3.1 Date

关于Date,请查看java基础系列--Date类

3.2 Calendar

关于Calendar,请查看java基础系列--Calendar类

3.3 SimpleDateFormat

SimpleDateFormat是JDK提供的用于实现Date与String之间相互转换的工具类,成为时间格式化工具。

我们来看一下简单的格式化方式:

public class SimpleDateFormatTest {
    public static void main(String[] args) throws ParseException {
        test();
    }

    public static void test() throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 格式化-将Date格式化输出
        Date date = new Date();
        System.out.println(sdf.format(date));
        // 解析-将String解析为Date
        String dateStr = "2019-01-01 12:12:12";
        System.out.println(sdf.parse(dateStr));
    }
}

执行结果为:

2019-02-20 18:01:30
Tue Jan 01 12:12:12 CST 2019

最后输出了“Tue Jan 01 12:12:12 CST 2019”格式的字符串是因为使用System.out.println()方式输出自动调用了Date的toString方法。

上面的东西就是基础,重点关注的是下面的内容。

SimpleDateFormat是非线程安全的类,如果将其作为共享变量使用,在多线程环境中将会发生线程安全问题。

下面是推荐的处理办法:

  1. 作为局部变量使用
  2. 加锁
  3. 使用ThreadLocal,这也是阿里巴巴java手册中推荐的方式。
public static ThreadLocal<SimpleDateFormat> sdfThreadLocal = new ThreadLocal<SimpleDateFormat>(){
    @Override
    protected SimpleDateFormat initialValue() {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    }
};
  1. 更彻底的方式是使用DateTimeFormatter来替换。

这里只补充一点关于时区的内容:

Date其实保存的就是时间戳,我们可以通过设定时区来获取不同地点的当前时间。

public class DateTest {
    public static void main(String[] args) {
        Date date1 = new Date(0);// 格林威治1970年1月1日0点0分0秒
        System.out.println("格林威治0时的时间戳:" + date1.getTime());
        System.out.println("格林威治0时的中国时区时间:" + date1);
        Date date2 = new Date();// 当前时间戳
        System.out.println("date2的时间戳:" + date2.getTime());
        System.out.println("date2表示的中国时区时间:" + date2);
        TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));// 设置时区为美国洛杉矶时区
        System.out.println("date2表示的美国洛杉矶时区时间:" + date2);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));// 设置为美国纽约时区
        System.out.println("date2表示的美国纽约时区时间:" + sdf.format(date2));
    }
}

执行结果为:

格林威治0时的时间戳:0
格林威治0时的中国时区时间:Thu Jan 01 08:00:00 CST 1970
date2的时间戳:1550656106538
date2表示的中国时区时间:Wed Feb 20 17:48:26 CST 2019
date2表示的美国洛杉矶时区时间:Wed Feb 20 01:48:26 PST 2019
date2表示的美国纽约时区时间:2019-02-20 04:48:26

可见中国时区的时间确实是比格林威治时间快8个小时,而美国洛杉矶时区的时间则是比格林威治时间慢8个小时,美国纽约时区的时间又比洛杉矶快3个小时。

如果不指定时区,则自动获取操作系统的默认时区。

参考: