1. 怎样理解时区
- 全球一共有 24 个时区,英国格林尼治是 0 时区,北京是东八区
- 0 时区的时间也称为 GMT + 0 时间,GMT 是格林尼治标准时间
- 北京时间就是 GMT + 8:00
2. 怎样理解时刻和纪元时
- 所有计算机系统内部都用一个整数表示时刻,这个整数是距离 格林尼治标准时间:1970 年 1 月 1 日 0 时 0 分 0 秒 的毫秒数。之所以用这个时间,更多的是历史原因
- 格林尼治标准时间 1970 年 1 月 1 日 0 时 0 分 0 秒也被称为 Epoch Time(纪元时)
- 对于 1970 年以前的时间,使用负数表示
3. 怎样理解年历
- 中国有公历和农历之分。公历和农历都是年历,不同的年历,一年有多少月,每月有多少天,甚至一天有多少小时,这些可能都是不一样的
- 公历有闰年,闰年 2 月是 29 天,而其他年份则是 28 天;其他月份,有的是 30 天,有的是 31 天
- 农历有闰月,比如闰 7 月,一年就会有两个 7 月,一共 13 个月
- Java API 的设计思想是支持国际化的,支持多种年历,但没有直接支持中国的农历
- 时刻是一个绝对时间,对时刻的解读则是相对的,与年历和时区相关
4. Java API 中关于日期和时间的主要的类有哪些
- 日期和时间是一个比较复杂的概念,Java 8 之前的设计有一些不足
- 业界有一个广泛使用的第三方类库 Joda-Time,Java 8 受 Joda-Time 影响,重新设计了日期和时间 API,新增了一个包
java.time
- 虽然 Java 8 之前的 API 有一些不足,但依然是被大量使用的。关于 Java 8 的 API,它使用了 Lambda 表达式
- 主要的类
Date
: 表示时刻,即绝对时间,与年月日无关Calendar
: 表示年历,是一个抽象类,其中表示公历的子类是GregorianCalendar
DateFormat
: 表示格式化,作用是将日期和时间与字符串进行互相转换,也是一个抽象类,其中最常用的子类是SimpleDateFormat
TimeZone
: 表示时区,也是一个抽象类Locale
: 表示国家(或地区)和语言
5. 怎样理解 Date
System.currentTimeMillis()
返回当前时刻距离纪元时的毫秒数Date
中的大部分方法都已经过时了
6. 怎样获取当前的默认时区
1 | TimeZone tz = TimeZone.getDefault(); |
7. 怎样获取任意给定时区的实例
1 | TimeZone tz = TimeZone.getTimeZone("US/Eastern"); //获取美国东部时区 |
8. 怎样理解 Locale
Locale
主要有国家(或地区)和语言两个参数,每个参数都有一个代码CN
: 中国内地,TW
: 中国台湾地区,US
: 美国zh
: 中文语言,en
: 英文语言
9. 怎样获取计算机默认语言
1 | Locale locale = Locale.getDefault(); |
10. 怎样理解 Calendar
getInstance()
方法会根据TimeZone
和Locale
创建对应的Calendar
子类对象。在中文系统中,子类一般是表示公历的GregorianCalendar
- 这种隐藏对象创建细节的方式,是计算机程序中一种常见的设计模式,叫工厂方法设计模式
Calendar
做了一项非常繁琐的工作,根据TimeZone
和Locale
,在绝对时间毫秒数和日历字段之间自动进行转换,且对不同日历字段的修改进行自动同步更新
11. 怎样理解 SimpleDateFormat
SimpleDateFormat
是DateFormat
的子类。相比DateFormat
它的一个主要不同是,它可以接受一个自定义的模式(pattern)作为参数,这个模式规定了Date
的字符串形式Demo:
1
2
3
4
5
6
7
8Calendar calendar = Calendar.getInstance();
calendar.set(2016, 08, 15, 14, 15, 20); //2016-08-15 14:15:20
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 E HH时mm分ss秒");
//E 表示星期几;HH 表示 24 小时制的小时数,用两位数表示;hh 表示 12 小时制的小时数;a 表示是上午还是下午;SSS 表示三位的毫秒数
System.out.println(sdf.format(calendar.getTime());
输出:
2016年08月15日,星期一,14时15分20秒
12. 怎样理解 Java 8 之前的日期与时间相关 API 的局限性
Date
中的过时方法Date
中的方法参数与常识不符合,过时方法标记容易被忽略,产生误用- 比如,
Date
构造方法中的year
表示的是与 1900 年的差,month
是从 0 开始的
Calendar
操作比较繁琐- 一方面,一些简单的操作都需要多次方法调用,很臃肿
- 另一方面,
Calendar
难以进行比较复杂的日期操作,比如,计算两个日期之间有多少个月;根据生日计算年龄;计算下个月的第一个周一等
DateFormat
的线程安全性DateFormat/SimpleDateFormat
是线程不安全的,即多个线程同时使用一个DateFormat
实例的时候会有问题- 因为
DateFormat
内部使用了一个Calendar
实例对象,多线程同时调用的时候,这个Calendar
实例的状态可能就会紊乱
13. 怎样解决 DateFormat
、SimpleDateFormat
的线程安全问题
- 每次使用
DateFormat/SimpleDateFormat
都新建一个对象 - 使用线程同步
- 使用
ThreadLocal
- 使用 Joda-Time 或 Java 8 的 API,它们是线程安全的