从 01 开始 从 01 开始
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • RSS
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金等
  • 职场规划
  • 关于离职
  • 杂谈
  • 📖 读书

    • 读书工具
    • 读书笔记
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档

晓林

程序猿,自由职业者,博主,英语爱好者,健身达人
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • RSS
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金等
  • 职场规划
  • 关于离职
  • 杂谈
  • 📖 读书

    • 读书工具
    • 读书笔记
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档
  • JavaSE

    • 我的 Java 学习路线
    • 安装 Java
    • Java数据类型

    • Java 多版本配置
    • 面向对象

    • Java核心类

    • IO

    • Java与时间

      • Java 中的时间
      • Date、Calendar 和 TimeZone
        • Date基本使用
        • Calendar 基本使用
        • TimeZone 类
        • SimpleDateFormat
        • 小结
      • LocalDate、LocalTime 和 LocalDateTime
      • 一些日期的枚举类
      • DateTimeFormatter
      • 时间调节器
      • Duration 和 Period
      • ZonedDateTime
      • Instant 时刻
      • Java 新旧时间 API 转换
    • 异常处理

    • 哈希和加密算法

    • Java8新特性

    • 网络编程

  • JavaSenior

  • JavaEE

  • JavaWeb

  • Spring

  • 主流框架

  • SpringMVC

  • SpringBoot

  • Java
  • JavaSE
  • Java与时间
2022-12-27
目录

Date、Calendar 和 TimeZone

# Date、Calendar 和 TimeZone

简单聊聊 Date、Calendar 和 TimeZone

# Date基本使用

前面我们说过,Java 使用 long 类型来存储时间戳,我们来看看 Date 的源码,验证下:

public class Date implements java.io.Serializable, Cloneable, Comparable<Date>{
    private transient long fastTime;
}
1
2
3

现在我们演示下其基本用法,比较简单,直接列出代码:

Date date = new Date();
System.out.println(date.getYear());     //返回年份
System.out.println(date.getMonth());    //返回月份
System.out.println(date.getDate());    //返回天数
System.out.println(date.toString());    //时间的String类型
System.out.println(date.toGMTString());    //GMT时区下的时间
System.out.println(date.toLocaleString());    //当地时间
1
2
3
4
5
6
7

编译和运行(笔者运行的时候是 2022-12-21 20:43 左右):

> javac .\TestDate.java
注: .\TestDate.java使用或覆盖了已过时的 API。
注: 有关详细信息, 请使用 -Xlint:deprecation 重新编译。

> java TestDate    
122
11
21
Wed Dec 21 20:43:18 CST 2022
21 Dec 2022 12:43:18 GMT
2022-12-21 20:43:18
1
2
3
4
5
6
7
8
9
10
11

首先我们看到,编译的时候就提示我们用了已过时的 API。

接下来我们来看看输出的内容,并讲解。

# date.getYear()

首先是 date.getYear() 的输出,顾名思义,是输出年份的,但为什么是 122?运行的时候不是 2022 年吗?相差了 1900 年!我们可以看看其源码和注释:

 /**
     * Returns a value that is the result of subtracting 1900 from the
     * year that contains or begins with the instant in time represented
     * by this Date object, as interpreted in the local
     * time zone.
     *
     * @return  the year represented by this date, minus 1900.
     * @see     java.util.Calendar
     * @deprecated As of JDK version 1.1,
     * replaced by Calendar.get(Calendar.YEAR) - 1900.
     */
    @Deprecated
    public int getYear() {
        return normalize().getYear() - 1900;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

可以看到其返回的是一个整数,并且是根据从 1900 年开始到今年,过了多少年来计算的(是不是很令人无语的设计 🤔)。所以我们如果要获取当前年份,得加上 1900:

date.getYear() + 1900;
1

# date.getMonth()

下面我们来看看 date.getMonth(),其用来输出当前月份,为什么是输出 11?运行的时候明明是 12 月! 老规矩,我们先看看注释和源码

/**
     * Returns a number representing the month that contains or begins
     * with the instant in time represented by this <tt>Date</tt> object.
     * The value returned is between 0 and 11,
     * with the value 0 representing January.
     *
     * @return  the month represented by this date.
     * @see     java.util.Calendar
     * @deprecated As of JDK version 1.1,
     * replaced by <code>Calendar.get(Calendar.MONTH)</code>.
     */
    @Deprecated
    public int getMonth() {
        return normalize().getMonth() - 1; // adjust 1-based to 0-based
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

注释的大意是说,0 表示 1 月,1 表示 2 月…… 11 表示 12 月 (这设计就更离谱了吧 🙄,跟 JavaScript 里的时间的设计有的比)。所以我们如果要获取当前月份,得加上 1:

date.getMont() + 1;
1

# date.getDate()

date.getDate() 是输出天数,这里输出的是 21,和运行的时候 2022 年 12 月 21 日一致,返回的日期范围是 1~31,不做多解释。

# date.toString()

date.toString() 就是返回一串字符串,其格式在不同计算机下可能不同。我们可以使用一个格式化工具类 SimpleDateFormat ,精确的控制其格式,具体我们后面再说。

# date.toGMTString()

date.toGMTString() 返回的是格林尼治时间的时间字符串,这里不多解释。

# Date.parse() 获取毫秒

可以通过 Date.parse() 来获取毫秒

    long t = Date.parse("Mon 6 Jan 1997 13:3:00");
    System.out.println(t);  //852526980000
1
2

Date.parse 接受什么格式的字符串呢?很多,规则也很复杂,读者记住一两个格式就行。感兴趣的可以看看官网文档 Date (Java Platform SE 8 ) (opens new window),

如果输入的格式有问题,会抛出参数不合法的异常,注意捕获:

Exception in thread "main" java.lang.IllegalArgumentException
        at java.util.Date.parse(Date.java:617)
        at TestDate.main(TestDate.java:19)
1
2
3

# 其他构造方法

还可以通过如下方式创建 Date 对象:

Date(int year, int month, int date);
Date(int year, int month, int date, int hrs, int min)
Date(int year, int month, int date, int hrs, int min, int sec)
Date(long date) //毫秒数,可以通过Date.parse()来获取毫秒
Date(String s)    //s - 日期的字符串表示形式,和Date.parse(String s)中s的格式相同
1
2
3
4
5

注意

  • year 的值需要-1900. 例如你想设置 2022 年,得传入 2022-1900 = 122 年
  • month 的值域为 0~11,0 代表 1 月,11 表代表 12 月
  • date 的值域在 1~31 之间,min 和 sec 的值域在 0~59 之间

# Date 类小结

一番演示下来,可以看到除了其 API 不好用之外,其实 Date 对象有几个严重的问题:它不能转换时区,除了 toGMTString() 可以按 GMT+0:00 输出外,Date 总是以当前计算机系统的默认时区为基础进行输出。

另外,Date 对象没有提供时间相关运算的 API,例如对日期和时间进行加减、计算相差的天数等

# Calendar 基本使用

Calendar 可以用于获取并设置年、月、日、时、分、秒,它和 Date 比,主要多了一个可以做简单的日期和时间运算的功能。

我们还是先演示下其基本用法:

Calendar c = Calendar.getInstance();   //创建Calendar实例
int y = c.get(Calendar.YEAR);    //获取年份
int m = c.get(Calendar.MONTH) + 1;    //获取月份
int d = c.get(Calendar.DAY_OF_MONTH);    //天数
int w = c.get(Calendar.DAY_OF_WEEK);    //星期几
int hh = c.get(Calendar.HOUR_OF_DAY);    //小时
int mm = c.get(Calendar.MINUTE);    //分钟
int ss = c.get(Calendar.SECOND);    //秒数
int ms = c.get(Calendar.MILLISECOND);  //毫秒数
System.out.println(y + "-" + m + "-" + d + " " + w + " " + hh + ":" + mm + ":" + ss + "." + ms);
1
2
3
4
5
6
7
8
9
10

输出:

2022-12-21 4 21:51:21.155
1

这里就不一一说明各个方法了,很多方法看名字就知道其用处,也加了注释。

这里需要注意的:

  • Calendar 只有一种方式获取,即 Calendar.getInstance(),而且一获取到就是当前时间... 其构造方法是 protected,无法 new。
  • 返回的月份仍然要加 1…… 😒
  • DAY_OF_WEEK 返回的星期几,但是其值范围是 1~7 分别表示周日,周一,……,周六。所以 2022-12-21 是星期三,但是输出的 4 (还是令人无语的设计 😶)

# 设置 Calendar

由于 Calendar 只有一种方式获取,如果我们想要指定时间,怎么做呢?用 set 方法。

Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, 2023); //设置年份
c.set(Calendar.MONTH, 8); //设置月份,注意8表示9月.... 
c.set(Calendar.DATE, 2);  //设置天数


//设置时分秒
c.set(Calendar.HOUR_OF_DAY, 21); 
c.set(Calendar.MINUTE, 30); 
c.set(Calendar.SECOND, 45); 
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(c.getTime()));    //2023-09-02 21:30:45

//一步到位:
c.set(2022,11,22,7,48,00);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

其他注意事项:

  • 设置小时,如果使用 HOUR_OF_DAY 设置的是 24 小时制,使用 HOUR 表示的是 12 小时制。
  • 也可以一次性设置完所有字段:c.set(2019, 10, 20, 8, 15, 0);
  • 设置毫秒时,注意毫秒的范围是 0-999 (1 秒 = 1000 毫秒)。如果超过 999 会怎么样呢?就会自动转为秒。。。。 例如 c.set(Calendar.MILLISECOND, 2000);,就会增加 2 秒。set 其他字段同理

# Calendar.getTime()

直接打印 Calendar 对象,其输出并不是时间,而是其内部的一些属性,例如:

java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Shanghai"...............
1

所以我们可以通过 Calendar 的 getTime 方法返回一个 Date 对象,并打印。

# 重置 Calendar

如果想要重置 Calendar 呢?可以用 clear 方法,这样 Calendar 是从 1970-1-1 00:00:00 开始

    Calendar c = Calendar.getInstance();
    c.clear();
    System.out.println(c.getTime());//Thu Jan 01 00:00:00 CST 1970
1
2
3

# 对日期进行加减

Calendar 可以对日期进行简单的加减

Calendar c = Calendar.getInstance();
c.set(2022,11,22,7,48,00);
System.out.println(sdf.format(c.getTime()));  //2022-12-22 07:48:00

c.add(Calendar.DAY_OF_MONTH, 5);    //加5天
c.add(Calendar.SECOND, -1);    //减一秒
System.out.println(sdf.format(c.getTime())); //2022-12-27 07:47:59
1
2
3
4
5
6
7

# 比较 Calendar 对象

可以用 compareTo 方法比较两个 Calendar 对象。小于返回-1,相等(年月日时分秒和毫秒都相等)则返回 0,大于则返回 1

    Calendar c = Calendar.getInstance();
    Calendar c2 = Calendar.getInstance();
    System.out.println(c.compareTo(c2)); //-1
1
2
3

由于代码运行需要一定的时间,所以如果是不同的创建语句,创建出来的对象基本上毫秒数是不同的。

# TimeZone 类

和 Calendar 和 Date 相比,TimeZone 提供了时区转换的功能。

# TimeZone基本概念

    TimeZone tzDefault = TimeZone.getDefault(); //当前时区
    TimeZone tzGMT9 = TimeZone.getTimeZone("GMT+09:00");  //GMT + 9:00 时区
    TimeZone tzNewYork = TimeZone.getTimeZone("America/New_York"); //纽约时区

    System.out.println(tzDefault.getID());    //Asia/Shanghai
    System.out.println(tzGMT9.getID());    //GMT+09:00
    System.out.println(tzNewYork.getID());    //America/New_York
1
2
3
4
5
6
7

时区的唯一标识是以字符串表示的 ID,我们获取指定 TimeZone 对象也是以这个 ID 为参数获取,GMT+09:00、Asia/Shanghai 都是有效的时区 ID。

要列出系统支持的所有 ID,可以用 TimeZone.getAvailableIDs(),

String str[] = TimeZone.getAvailableIDs();
System.out.println(str.length);    //2022年12月22日运行的时候,是628个
for (int i = 0; i < str.length; i++) {
  System.out.println(str[i]);
}
1
2
3
4
5

# 根据时区转换时间

举个例子,将北京时间转为纽约时间

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    Calendar c = Calendar.getInstance();

    c.clear();
    c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
    c.set(2022, 11,22,7,57,00);
    System.out.println("北京时间: " + sdf.format(c.getTime()));
    //北京时间: 2022-12-22 07:57:00

    sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
    System.out.println("纽约时间: " + sdf.format(c.getTime()));
    //纽约时间: 2022-12-21 18:57:00
1
2
3
4
5
6
7
8
9
10
11
12

说明下时区转换的步骤:

  1. 获取 Calendar 实例,清除所有字段并设置时间
  2. 创建 SimpleDateFormat 并设定目标时区
  3. 通过 SimpleDateFormat 显示转换后的时间

# SimpleDateFormat

我们可以用 SimpleDateFormat 来控制 Date 类型的打印格式:

Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 
System.out.println(sdf.format(date));    //format返回的是一个String类型
1
2
3

这里的 yyyy-MM-dd HH:mm:ss 分别指年份、月份、日期、小时、分钟和秒数。编译和运行:

2022-12-21 21:23:17
1

SimpleDateFormat 的参数的更多说明,可以看文档:SimpleDateFormat (Java SE 12 & JDK 12 ) (opens new window)

也可以使用 SimpleDateFormat 来转换字符串为 Date 对象:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateStr = "2022-05-21 10:59:27";
Date date = sdf.parse(dateStr);
1
2
3

需要注意的是,SimpleDateFormat 是线程不安全的。

# 小结

Date 类常用方法:

  • 构造方法 Date(); Date(int year, int month, int date); Date(int year, int month, int date, int hrs, int min) Date(int year, int month, int date, int hrs, int min, int sec) Date(long date) //毫秒数,可以通过 Date.parse()来获取毫秒 Date(String s) //s - 日期的字符串表示形式,和 Date.parse(String s)中 s 的格式相同

  • 常用方法

    date.getYear() 返回年份,注意得加上 1900 date.getMonth() 返回月份,注意 0 表示 1 月,1 表示 2 月…… date.getDate() 返回天数,范围是 0~31 date.toString() 返回时间的字符串,默认是西方的格式 date.toGMTString() 返回 GMT 时区的时间 date.toLocaleString() 返回当地时间 Date.parse(String s) 获取时间的毫秒数

Calendar 类常用方法:

  • Calendar c = Calendar.getInstance(); //唯一创建 Calendar 实例的方法

  • 常用方法

    c.getTime() 返回 Date 对象 c.get(Calendar.YEAR); //获取年份 c.get(Calendar.MONTH) + 1; //获取月份,注意 0 表示 1 月…… c.get(Calendar.DAY_OF_MONTH); //获取天数 c.get(Calendar.DAY_OF_WEEK); //获取星期几,注意 1 表示星期日,2 表示星期一... c.get(Calendar.HOUR_OF_DAY); //获取小时 c.get(Calendar.MINUTE); //获取分钟 c.get(Calendar.SECOND); //秒数 c.get(Calendar.MILLISECOND); //毫秒数

  • 设置 Calendar c.set(2022,11,22,7,48,00); c.set(Calendar.YEAR, 2023); c.set(Calendar.MONTH, 8); c.set(Calendar.DATE, 2); c.set(Calendar.HOUR_OF_DAY, 21); c.set(Calendar.MINUTE, 30); c.set(Calendar.SECOND, 45); c.clear(); 重置为 1970-1-1 0 点 0 分,可用于初始化

  • 加减 c.add(Calendar.DAY_OF_MONTH, 5); //加 5 天 c.add(Calendar.SECOND, -1); //减一秒

  • 比较:c.compareTo(c2)

TimeZone :可用于转换时区,根据 SimpleDateFormat 格式化输出。构造方法:

  • TimeZone.getDefault(); //当前时区
  • TimeZone.getTimeZone(时区 ID),例如"GMT+09:00" "America/New_York"
  • TimeZone.getAvailableIDs() 获取所有时区 ID

SimpleDateFormat,用法示例:

  • new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date)
  • new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(String s) 返回一个 Date 对象
  • sdf.setTimeZone(TimeZone 对象) 设置时区
上次更新: 2024/10/1 16:19:31
Java 中的时间
LocalDate、LocalTime 和 LocalDateTime

← Java 中的时间 LocalDate、LocalTime 和 LocalDateTime→

最近更新
01
2025 年 4 月记
04-30
02
山西大同 “订婚强奸案” 将会给整个社会带来的影响有多严重? - 知乎 转载
04-26
03
一个小技巧,让电子书阅读体验翻倍!
04-18
更多文章>
Theme by Vdoing | Copyright © 2022-2025 | 粤 ICP 备 2022067627 号 -1 | 粤公网安备 44011302003646 号 | 点击查看十年之约
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式