前言

Java中的时间操作,也许大家都很熟悉,Date、Calendar、SimpleDateFormat等。但或许我们都只是会调用常见接口方法。今天解决的bug,关于TimeZone,即时区。

经常有人发现时间不对,比如相差8个小时等等,其真实原因便是TimeZone。只有正确合理的运用TimeZone,才能保证系统时间无论何时都是准确的。

影响TimeZone的因素:

  1. 操作系统的时区设置。
  2. 数据传输时时区设置。

第一个原因其实是根本原因,当数据在不同操作系统间流转时,就有可能因为操作系统的差异造成时间偏差,而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时区切换时的需要注意的更多相关文章

  1. 让多个Fragment 切换时不重新实例化、FragmentTabHost切换Fragment时避免UI重新加载

    http://www.tuicool.com/articles/FJ7VBb FragmentTabHost切换Fragment时避免UI重新加载 不过,初次实现时发现有个缺陷,每次FragmentT ...

  2. 时区切换导致quartz定时任务没有触发问题

    时区切换对Quartz的cron表达式有影响,切换的1小时内停止触发定时任务,导致sla没有定时清空内存计数,误发限流. 美国夏令时PST切换到冬令时PDT,会有时间跳变.不带时区跳变的,会出现时间重 ...

  3. Java虚拟机运行时数据区

    运行时数据区程序计数器Java虚拟机栈本地方法栈Java堆(GC堆)方法区运行时常量池 运行时数据区 Java虚拟机在运行Java程序时,会将它所管理的内存划分为若干个内存区域.这些数据区域有各自的用 ...

  4. Android 如何去掉手机中横竖屏切换时的转屏动画?

    前言          欢迎大家我分享和推荐好用的代码段~~ 声明          欢迎转载,但请保留文章原始出处:          CSDN:http://www.csdn.net        ...

  5. 让多个Fragment 切换时不重新实例化

    转自:http://www.yrom.net/blog/2013/03/10/fragment-switch-not-restart/ 让多个Fragment 切换时不重新实例化 在项目中需要进行Fr ...

  6. 关于Java虚拟机运行时数据区域的总结

    Java虚拟机运行时数据区域 程序计数器(Program Counter) 程序计数器作为一个概念模型,这个是用来指示下一条需要执行的字节码指令在哪. Java的多线程实际上是通过线程轮转做到的,如果 ...

  7. Java时区问题

    Java时区相关 时间格式 UTC是以原子时计时,更加精准,适应现代社会的精确计时.不过一般使用不需要精确到秒时,视为等同.GMT是前世界标准时,UTC是现世界标准时.每年格林尼治天文台会发调时信息, ...

  8. 面试常问的 Java 虚拟机运行时数据区

    写在前面 本文描述的有关于 JVM 的运行时数据区是基于 HotSpot 虚拟机. 概述 JVM 在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以 ...

  9. Java 虚拟机运行时数据区

    写在前面 本文描述的有关于 JVM 的运行时数据区是基于 HotSpot 虚拟机. 概述 JVM 在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以 ...

随机推荐

  1. python指定cpu使用率,与内存占用率

    python指定cpu使用率,与内存占用率 """ runing.py -c 2 -t 0.01 -m 1000 -c cpu核数,不加-c参数为最大核数 -t cpu运 ...

  2. MongoDB的日志系统

    mongodb中主要有四种日志.分别是系统日志.Journal日志.oplog主从日志.慢查询日志等.这些 日志记录着Mongodb数据库不同方便的踪迹.下面分别介绍这四种日志: 1.系统日志 系统日 ...

  3. No enclosing instance of type TestGson is accessible. Must qualify the allocation with an enclosing instance of type TestGson (e.g. x.new A() where x is an instance of TestGson).

    main方法中实例化内部类报错: public class TestGson { public static void main(String[] args) { Gson gson=new Gson ...

  4. find命令进阶(二):对找到的文件执行操作exec

    以下面的命令为例: find ~ -type f -name 'foo*' -exec ls -l '{}' ';' 分面两部分,第一部分: find ~ -type f -name 'foo*' 即 ...

  5. boost location-independent times

    The class boost::posix_time::ptime defindes a location-independent time. It uses the type boost::gre ...

  6. PHP 利用 curl 发送 post get del put patch 请求

    因为需要在 php 开发中对接其它接口需要用 php curl 去对接其它接口 我把他们封装成函数 希望能对大家有所帮助. 这里面是封装好的会自动把 data 进行转成 json 格式,同时解码成 p ...

  7. JS中数据结构之队列

    队列是一种列表,不同的是队列只能在队尾插入元素,在队首删除元素.队列用于存储按 顺序排列的数据,先进先出. 队列的两种主要操作是:向队列中插入新元素和删除队列中的元素.插入操作也叫做入 队,删除操作也 ...

  8. linux 下启动tomcat 时没有执行权限

    原因: 没有权限 解决 : chmod 777 *.sh Linux下启动tomcat

  9. Tortoise git账号记住密码

    方法一: 本地git仓库目录下,找到 .git/config ,然后打开增加: [credential] helper = store 这样只有该目录下的git操作不用每次输入用户名和密码,换一个目录 ...

  10. NOIp 图论算法专题总结 (2)

    系列索引: NOIp 图论算法专题总结 (1) NOIp 图论算法专题总结 (2) NOIp 图论算法专题总结 (3) 树链剖分 https://oi-wiki.org/graph/heavy-lig ...