java字符串转utc时间_详解Java⽇期与时间修改
最近在家办⼯接到的⼀项⼯作是和时区有关的,据⽤户反馈,由于美国的 Puerto Rico 州不使⽤夏令时,在其他州施⾏夏令时时,这个州的⽤户选不到适合⾃⼰的时区,导致时间⽆法正确显⽰。最终笔者为软件添加了太平洋标准时区解决了这个问题。
程序员培训机构去到极客时间时区、夏令时、标准时间...⽇期和时间是计算机处理的重要数据,在绝⼤多数软件程序中,我们都要和⽇期和时间打交道。本篇⽂章我们将系统地学习 Java 对⽇期和时间的处理。(本⽂参考了 「链接」廖雪峰 Java 教程-⽇期和时间(点击链接查看) ⽂章中的资料,事实上,笔者并不认为本⽂⽐廖⼤佬的⽂章更好,有时间的读者可以直接阅读原教程。)
⼀、时区
地球⼈都知道,我们地球是⾃西向东⾃转的,所以东边会⽐西边早看到太阳,东边的时间也总⽐西边的快。如果全球采⽤统⼀的时间,⽐如都⽤北京时间,会产⽣什么问题呢?
当正午⼗⼆点的太阳照射到北京时,⾝处地球另⼀⾯的纽约还是漆⿊⼀⽚。对于纽约来说,⽇常作息时间就成了晚上九点开始上班,因为那时太阳刚刚升起;所有纽约⼈都上班到第⼆天早上六点下班,因为那时太阳刚刚落下。
虽然对于长期居住在⼀个地⽅的⼈来说,他可以适应⾃⼰本地的作息时间,但当他去其他地⽅旅游或是与其他地⽅的⼈交流时,就必须查询当地的作息时间,这会带来很⼤的不便。
于是,在 1879 年,加拿⼤铁路⼯程师弗莱明⾸次提出全世界按统⼀标准划分“时区”。1884 年华盛顿
⼦午线国际会议正式通过采纳这种时区划分,称为世界标准时制度。
时区划分的初衷是 尽量使中午贴近太阳上中天的时间,从此以后,各地的时间经过换算,都能统⼀地早上六点起床,中午⼗⼆点午餐,晚上六点下班。
全球共分为 24 个时区,所以每个时区占 15˚ 经度。理论时区 以能被 15 整除的经线为中⼼,向东西两侧延伸 7.5˚。国际规定经过英国格林威治天⽂台的那⼀条经线为 0˚ 经线,这条经线也被称作 本初⼦午线。选择格林威治既是因为当初“⽇不落帝国”的强⼤,也是由于格林威治常年提供准确的航海观测数据,19 世纪晚期,72% 的世界贸易都依靠以格林威治作为本初⼦午线的航海图表。
为了避开国界线,有的时区的形状并不规则,⽽是⽐较⼤的国家以国家内部⾏政分界线为时区界线,这是 实际时区,也称为 法定时区。
⾝处地球的不同地区,时间可能是不同的,所以光靠时间我们⽆法确定⼀个时刻,要确定⼀个时刻必须要带上时区。
表⽰时区有两种常见的写法,最常见的是 GMT,它的全称是 Greenwich Mean Time,意思是格林威治标准时间,世界各地根据东西偏移量计算时区。⽐如,北京位于东⼋区,记做 GMT+8,纽约位于西五区,记做 GMT-5。
还有⼀种写法是 UTC,它的全称是 Coordinated Universal Time,意思是协调世界时,如果时间以 UTC 表⽰,则在时间后⾯直接加上⼀个“Z”(不加空格),“Z”是协调世界时中 0 时区的标志。⽐如,“09:30 UTC” 写作 “09:30Z” 或是 “0930Z”。“14:45:15 UTC” 写作 “14:45:15Z” 或 “144515Z”。因为在北约⾳标字母中⽤ “Zulu” 表⽰ “Z”,所以 UTC 时间也被称做祖鲁时间。
GMT 和 UTC 基本⼀样,只不过 UTC 使⽤更加精确的原⼦钟计时,每隔⼏年会有⼀个闰秒。但我们⽆需关注两者的差别,计算机在联⽹时会⾃动与时间服务器同步时间。
计算不同时区的时间差很简单,我们平时常⽤的北京时间位于东⼋区,即:GMT+8,它的值是在 GMT 的基础上增加了 8 ⼩时,纽约位于西五区,即:GMT-5,它的值是在 GMT 的基础上减少了 5 ⼩时。所以北京时间通常⽐纽约时间快 13 个⼩时。
我们现在知道,每往西越过⼀个时区,时间便提前⼀⼩时。据此我们来思考⼀个有趣的问题:如果我们⼀直往西,以每⼩时⼀个时区的速度前进,时间是否会静⽌呢?
1.⽐如我们从北京出发,此时时间是 2020-2-11 8:00 GMT+8
2.当我们花费⼀个⼩时,⾛到东七区时,时间是 2020-2-11 8:00 GMT+7
3.当我们⾛到本初⼦午线时,时间是 2020-2-11 8:00 GMT
4.当我们⾛到西五区时,时间是 2020-2-11 8:00 GMT-5
......
我们都知道地球是个球体,当我们绕地球⼀圈回到北京时,如果时间还是 2020-2-11 8:00 GMT+8,岂不是时间真的静⽌了?进⼀步思考,如果我们以半⼩时⼀个时区的速度向西前进,岂不是时间还会倒流?
常识告诉我们,时间是不可能静⽌也不可能倒流的。那么这⾥的问题出在哪⾥呢?问题就出在东西时区的交界处。上⽂说到,地球分为 24个时区,包括标准时区、东⼀区~东⼗⼆区、西⼀区~西⼗⼆区。实际上,东⼗⼆区和西⼗⼆区是同⼀时区。
从 0˚ 经线开始,每往西跨⼀个时区时间便减少 1 ⼩时,每往东跨⼀个时区便增加 1 ⼩时。如此⼀来,到了另⼀端 180˚ 经线时,就会有24 ⼩时的落差,为了平衡这⼀落差,⼈们规定由西向东越过此线⽇期需减少⼀天,由东向西越过此线时⽇期需增加⼀天。故⽽这⼀条线被称之为 国际⽇期变更线,也叫 换⽇线,它位于本初⼦午线的另⼀⾯。和时区界限类似,为了避开国界线,换⽇线并不与 180˚ 经线重合,换⽇线实际上是不规则的。
如果我们接着⾛下去:
5.当我们⾛到东 / 西⼗⼆区时,时间是 2020-2-11 8:00 GMT±12
6.我们越过国际换⽇线,⽇期增加⼀天,时间是 2020-2-12 8:00 GMT±12
7.当我们⾛到东⼗⼀区时,时间是 2020-2-12 8:00 GMT+11
8.当我们回到北京时,时间是 2020-2-12 8:00 GMT+8
此时,我们的环球之旅刚好⽤了 24 ⼩时。
再来看⼀下如果我们以每半⼩时⼀个时区的速度向西⾏⾛,时间为什么不会逆流:
1.我们还是从北京出发,此时时间是 2020-2-11 8:00 GMT+8
2.当我们花费半⼩时,⾛到东七区时,时间是 2020-2-11 7:30 GMT+7
3.当我们⾛到本初⼦午线时,时间是 2020-2-11 4:00 GMT
4.当我们⾛到西五区时,时间是 2020-2-11 1:30 GMT-5
5.当我们⾛到东 / 西⼗⼆区时,时间是 2020-2-10 22:00 GMT±12
6.我们越过国际换⽇线,⽇期增加⼀天,时间是 2020-2-11 22:00 GMT±12
7.当我们⾛到东⼗⼀区时,时间是 2020-2-11 21:30 GMT+11
8.当我们回到北京时,时间是 2020-2-11 20:00 GMT+8
此时,我们的环球之旅刚好⽤了 12 ⼩时。
⼆、夏令时
由于夏季和冬季⽩昼时间不⼀致,部分国家施⾏了夏令时制度,⽬的是让⼈们根据⽩昼时间来调整作息。
夏令时:在夏天开始的时候,把时间往后拨 1 ⼩时,夏天结束的时候,再把时间往前拨 1 ⼩时。
施⾏夏令时使得⼈们可以尽量在⽩天⼯作,从⽽减少照明,节省电能。但夏令时也带来了很多的不便,如夏令时开始和结束时,⼈们不得不调整睡眠时间;夏令时也使得时间计算变得复杂,在夏令时结束的当天,某些时间会出现两次,容易造成交通、⽣产、会议安排等时间的混乱。中国曾经施⾏过⼀段时间夏令时,在 1992 年就被废除了,⽽美国⼤部分地区现在还在使⽤夏令时。
美国使⽤夏令时时,纽约时间按照西四区计算,即:GMT-4。这段时间北京时间⽐纽约时间快 12 个⼩时,夏令时结束后,纽约时间⼜恢复到西五区 GMT-5。
由于各国规定有所差异,所以夏令时计算⾮常复杂。当我们需要计算夏令时时,应尽量使⽤ Java 库提供的类,避免⾃⼰计算夏令时。三、旧 API
Java 标准库提供了两套关于时间和⽇期的 API:
旧 API:位于 java.util 包中,⾥⾯主要有 Date、Calendar、TimeZone 类
新 API:位于 java.time 包中,⾥⾯主要有 LocalDateTime、ZonedDateTime、ZoneId 类
有两套 API 的原因是旧 API 在设计时没有考虑好时区问题,常量设计也有些不合理,导致使⽤起来不够⽅便。新 API 很好地解决了这些问题。我们在开发时,除⾮维护⽼代码,其他时候都应该尽量使⽤新 API。
3.1. Date
Date 类⽤于存储⽇期和时间,查看其源码可以发现,它保存了⼀个 long 类型的时间戳。时间戳是指格林威治时间从 1970 年 1 ⽉ 1 ⽇零点到此刻经历的秒数或毫秒数。
Date 的基本⽤法如下:
Date 在使⽤时有⼏个缺点:
每次获取年份、⽉份都需要转换
只能获取当前时区的时间,⽆法设置时区
⽆法加减⽇期和时间
⽆法计算某个⽉的第⼏个星期⼏
3.2. SimpleDateFormat
默认输出的时间字符串的格式通常不能满⾜我们的要求,所以我们需要⽤ SimpleDateFormat 来格式化输出,它使⽤⼀些预定义的字符串表⽰格式化,较常⽤的字符串有:
y:年
M:⽉
d:⽇
H:⼩时
m:分钟
s:秒
S:毫秒
a:上午 / 下午
E:星期
z:时区
附:Java 官⽹⽂档中给出的预定义字符串表格
SimpleDateFormat 的使⽤:
这⾥的时区信息输出为 CST,表⽰ China Standard Time,也就是中国标准时间。
SimpleDateFormat 会根据预定义字符的长度打印不同长度的信息。以 M 为例:
M:输出 2
MM:输出 02
MMM:输出 2⽉
MMMM:输出 ⼆⽉
如果预定义字符串的长度短于需要输出的信息,这时 Java 会输出 能包含全部信息的最短字符串,也就是说 Java 不会丢弃任何信息,如上例中只⽤了⼀个 y,仍然输出了 2020,并不会只输出⼀个 2。
我们来发挥⼀下极客精神,探索⼀下预定义字符串过长 Java 会怎么处理:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。