Java时区切换时的需要注意
前言
Java中的时间操作,也许大家都很熟悉,Date、Calendar、SimpleDateFormat等。但或许我们都只是会调用常见接口方法。今天解决的bug,关于TimeZone,即时区。
经常有人发现时间不对,比如相差8个小时等等,其真实原因便是TimeZone。只有正确合理的运用TimeZone,才能保证系统时间无论何时都是准确的。
影响TimeZone的因素:
- 操作系统的时区设置。
- 数据传输时时区设置。
第一个原因其实是根本原因,当数据在不同操作系统间流转时,就有可能因为操作系统的差异造成时间偏差,而JVM默认情况下获取的就是操作系统的时区设置。因此在项目中最好事先设置好时区,例如:
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
那么一旦时区设置不同导致时间有偏差怎么办?如何转化呢?
用SimpleDateFormat的话,如下:
public static void main(String[] args) {
Date date = new Date(1359641834000L);// 2013-1-31 22:17:14
String dateStr = "2013-1-31 22:17:14";
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
try {
Date dateTmp = dateFormat.parse(dateStr);
System.out.println(dateTmp);
} catch (ParseException e) {
e.printStackTrace();
}
String dateStrTmp = dateFormat.format(date);
System.out.println(dateStrTmp);
}
运行结果:
Fri Feb 01 06:17:14 CST 2013
2013-01-31 14:17:14
我们发现同一时间,字符串和日期运行出来的结果并不相同,那么我们应该怎么理解呢?一切都要以当前操作系统的时间为基准。我的操作系统是"Asia/Shanghai",即GMT+8的北京时间,那么执行日期转字符串的format方法时,由于日期生成时默认是操作系统时区,因此2013-1-31 22:17:14是北京时间,那么推算到GMT时区,自然是要减8个小时的;而执行字符串转日期的parse方法时,由于字符串本身没有时区的概念,因此2013-1-31 22:17:14就是指GMT(UTC)时间【ps:所有字符串都看做是GMT时间】,那么当转化为日期时要加上默认时区,即"Asia/Shanghai",因此要加上8个小时。
用Calendar的话,如下:
public static void main(String[] args) {
Date date = new Date(1359641834000L);// 2013-1-31 22:17:14
System.out.println(date);
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(TimeZone.getTimeZone("GMT"));
// 或者可以 Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
calendar.setTime(date);
System.out.println(calendar.get(Calendar.HOUR_OF_DAY) + ":" + calendar.get(Calendar.MINUTE));
}
运行结果:
Thu Jan 31 22:17:14 CST 2013 14:17
Calendar不涉及到日期与字符串的转化,因此不像SimpleDateFormat那么复杂,与日期转字符串的思路类似。但是需要注意的是,设置完时区后,我们不能用calendar.getTime()来直接获取Date日期,因此此时的日期与一开始setTime时是相同值,要想获取某时区的时间,正确的做法是用calendar.get()方法,那么我们怎么获得Date类型的日期呢?
正确的做法如下:
public static void main(String[] args) {
Date date = new Date(1359641834000L);
System.out.println(date);
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(TimeZone.getTimeZone("GMT"));
// 或者可以 Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
calendar.setTime(date);
Calendar calendar2 = Calendar.getInstance();
calendar2.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), calendar.get(Calendar.SECOND));
System.out.println(calendar2.getTime());
}
运行结果:
Thu Jan 31 22:17:14 CST 2013
Thu Jan 31 14:17:14 CST 2013
完美通用转换方法
其实上面两个转换方法都要受到操作系统的时区设置影响,如果软件在不同操作系统运行,仍然会有时间误差,那么怎么才能统一呢?
public static void main(String[] args) {
Date date = new Date(1359641834000L);
System.out.println(date);
date = changeTimeZone(date, TimeZone.getTimeZone("Asia/Shanghai"), TimeZone.getTimeZone("GMT"));
System.out.println(date);
}
/**
* 获取更改时区后的日期
* @param date 日期
* @param oldZone 旧时区对象
* @param newZone 新时区对象
* @return 日期
*/
public static Date changeTimeZone(Date date, TimeZone oldZone, TimeZone newZone) {
Date dateTmp = null;
if (date != null) {
int timeOffset = oldZone.getRawOffset() - newZone.getRawOffset();
dateTmp = new Date(date.getTime() - timeOffset);
}
return dateTmp;
}
运行结果:
Thu Jan 31 22:17:14 CST 2013
Thu Jan 31 14:17:14 CST 2013
通过以上可以看出时区确实有不少需要我们注意和专研的地方,其实这并不是什么高深的东西,也是java日期里的基础,盲目学习各种开源框架并不能成为真正的高手,框架也是基于jdk的基础上开发而来的,不懂jdk的基本知识,想真正提高到架构师的级别是非常苦难的,因此基础很重要,掌握jdk基本功确实是成为“大侠”的前提条件,共同努力吧!
Java时区切换时的需要注意的更多相关文章
- 让多个Fragment 切换时不重新实例化、FragmentTabHost切换Fragment时避免UI重新加载
http://www.tuicool.com/articles/FJ7VBb FragmentTabHost切换Fragment时避免UI重新加载 不过,初次实现时发现有个缺陷,每次FragmentT ...
- 时区切换导致quartz定时任务没有触发问题
时区切换对Quartz的cron表达式有影响,切换的1小时内停止触发定时任务,导致sla没有定时清空内存计数,误发限流. 美国夏令时PST切换到冬令时PDT,会有时间跳变.不带时区跳变的,会出现时间重 ...
- Java虚拟机运行时数据区
运行时数据区程序计数器Java虚拟机栈本地方法栈Java堆(GC堆)方法区运行时常量池 运行时数据区 Java虚拟机在运行Java程序时,会将它所管理的内存划分为若干个内存区域.这些数据区域有各自的用 ...
- Android 如何去掉手机中横竖屏切换时的转屏动画?
前言 欢迎大家我分享和推荐好用的代码段~~ 声明 欢迎转载,但请保留文章原始出处: CSDN:http://www.csdn.net ...
- 让多个Fragment 切换时不重新实例化
转自:http://www.yrom.net/blog/2013/03/10/fragment-switch-not-restart/ 让多个Fragment 切换时不重新实例化 在项目中需要进行Fr ...
- 关于Java虚拟机运行时数据区域的总结
Java虚拟机运行时数据区域 程序计数器(Program Counter) 程序计数器作为一个概念模型,这个是用来指示下一条需要执行的字节码指令在哪. Java的多线程实际上是通过线程轮转做到的,如果 ...
- Java时区问题
Java时区相关 时间格式 UTC是以原子时计时,更加精准,适应现代社会的精确计时.不过一般使用不需要精确到秒时,视为等同.GMT是前世界标准时,UTC是现世界标准时.每年格林尼治天文台会发调时信息, ...
- 面试常问的 Java 虚拟机运行时数据区
写在前面 本文描述的有关于 JVM 的运行时数据区是基于 HotSpot 虚拟机. 概述 JVM 在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以 ...
- Java 虚拟机运行时数据区
写在前面 本文描述的有关于 JVM 的运行时数据区是基于 HotSpot 虚拟机. 概述 JVM 在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以 ...
随机推荐
- 390-基于Zynq UltraScale+ MPSoC的单板嵌入式计算机
基于Zynq UltraScale+ MPSoC的单板嵌入式计算机 概述:Aldec TySOM-3-ZU7EV,将Xilinx Zynq UltraScale+ ZU7EV MPSoC以及DDR4 ...
- win10 护眼
- Sass--传一个带值的参数
在 Sass 的混合宏中,还可以给混合宏的参数传一个默认值,例如: @mixin border-radius($radius: 3px) { -webkit-border-radius: $radiu ...
- 前端每日实战:76# 视频演示如何用纯 CSS 创作一组单元素办公用品(内含2个视频)
效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/oMgmwB 可交互视频 此视频是可 ...
- 一次Linux服务器空间满的随笔解决记录
昨天突然无法上传文件到服务器上的,FTP工具总是到99%就卡住了.查了一下说可能是服务器满了. 赶紧用 df -h 命令查看空间使用情况.果然100%了. 想想上次查询才不到50%,怎么突然就满了了呢 ...
- boost Filesystem
The library Boost.Filesystem makes it easy to work with files and directories. Paths Paths can be bu ...
- python学习笔记(二)列表操作
列表及列表操作: 列表是最常用的数据类型之一,列表也叫数组,列表定义,使用[]即可:列表里面可以再套列表,一个里面套一个列表,叫二维数组:一个里面套一个列表,里面的列表再套一个列表,这个叫三位数组,套 ...
- 别人的双11 & 程序员的双11~
双11,致敬所有的程序员欧巴! 愿代码的世界,只有爱,没有伤害!! 点此参加阿里云双十一拼团活动:https://m.aliyun.com/act/team1111/ 阅读原文
- 存储系统设计——NVMe SSD性能影响因素一探究竟
目录1 存储介质的变革 2 NVME SSD成为主流 2.1 NAND FLASH介质发展 2.2 软件层面看SSD——多队列技术 2.3 深入理解SSD硬件 3 影响NVME SSD的性能因素 3. ...
- 生成100个 "20180520" 这样的时间字符串 写入txt文件
主要想记录一下 . 写NSString 到txt . 数组的去重 . 数组的截取 . 数组分割 代码如下: NSString *year = @"2018"; NSArray *m ...