`
san_yun
  • 浏览: 2597144 次
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

Java中的Date和时区转换

    博客分类:
  • date
阅读更多
1.Date中保存的是什么
在java中,只要我们执行
Date date = new Date();
就可以得到当前时间。如:
Date date = new Date();
System.out.println(date);
 输出结果是:
Thu Aug 24 10:15:29 CST 2017
也就是我执行上述代码的时刻:2017年8月24日10点15分29秒。是不是Date对象里存了年月日时分秒呢?不是的,Date对象里存的只是一个long型的变量,其值为自1970年1月1日0点至Date对象所记录时刻经过的毫秒数,调用Date对象getTime()方法就可以返回这个毫秒数,如下代码:
Date date = new Date();
System.out.println(date + ", " + date.getTime());
 输出如下:
Thu Aug 24 10:48:05 CST 2017, 1503542885955
即上述程序执行的时刻是2017年8月24日10点48分05秒,该时刻距离1970年1月1日0点经过了1503542885955毫秒。反过来说,输出的年月日时分秒其实是根据这个毫秒数来反算出来的。
 
2.时区
全球分为24个时区,相邻时区时间相差1个小时。比如北京处于东八时区,东京处于东九时区,北京时间比东京时间晚1个小时,而英国伦敦时间比北京晚7个小时(英国采用夏令时时,8月英国处于夏令时)。比如此刻北京时间是2017年8月24日11:17:10,则东京时间是2017年8月24日12:17:10,伦敦时间是2017年8月24日4:17:10。
 
既然Date里存放的是当前时刻距1970年1月1日0点时刻的毫秒数,如果此刻在伦敦、北京、东京有三个程序员同时执行如下语句:
 
Date date = new Date();
 那这三个date对象里存的毫秒数是相同的吗?还是北京的比东京的小3600000(北京时间比东京时间晚1小时,1小时为3600秒即3600000毫秒)?答案是,这3个Date里的毫秒数是完全一样的。确切的说,Date对象里存的是自格林威治时间( GMT)1970年1月1日0点至Date对象所表示时刻所经过的毫秒数。所以,如果某一时刻遍布于世界各地的程序员同时执行new Date语句,这些Date对象所存的毫秒数是完全一样的。也就是说,Date里存放的毫秒数是与时区无关的
 
继续上述例子,如果上述3个程序员调用那一刻的时间是北京时间2017年8月24日11:17:10,他们继续调用
System.out.println(date);
 那么北京的程序员将会打印出2017年8月24日11:17:10,而东京的程序员会打印出2017年8月24日12:17:10,伦敦的程序员会打印出2017年8月24日4:17:10。既然Date对象只存了一个毫秒数,为什么这3个毫秒数完全相同的Date对象,可以打印出不同的时间呢?这是因为Sysytem.out.println函数在打印时间时,会取操作系统当前所设置的时区,然后根据这个时区将同毫秒数解释成该时区的时间。当然我们也可以手动设置时区,以将同一个Date对象按不同的时区输出。可以做如下实验验证:
Date date = new Date(1503544630000L);  // 对应的北京时间是2017-08-24 11:17:10
 
SimpleDateFormat bjSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");     // 北京
bjSdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));  // 设置北京时区
 
SimpleDateFormat tokyoSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  // 东京
tokyoSdf.setTimeZone(TimeZone.getTimeZone("Asia/Tokyo"));  // 设置东京时区
 
SimpleDateFormat londonSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 伦敦
londonSdf.setTimeZone(TimeZone.getTimeZone("Europe/London"));  // 设置伦敦时区
 
System.out.println("毫秒数:" + date.getTime() + ", 北京时间:" + bjSdf.format(date));
System.out.println("毫秒数:" + date.getTime() + ", 东京时间:" + tokyoSdf.format(date));
System.out.println("毫秒数:" + date.getTime() + ", 伦敦时间:" + londonSdf.format(date));
 输出为:
毫秒数:1503544630000, 北京时间:2017-08-24 11:17:10
毫秒数:1503544630000, 东京时间:2017-08-24 12:17:10
毫秒数:1503544630000, 伦敦时间:2017-08-24 04:17:10
 
可以看出,同一个Date对象,按不同的时区来格式化,将得到不同时区的时间。由此可见,Date对象里保存的毫秒数和具体输出的时间(即年月日时分秒)是模型和视图的关系,而时区(即Timezone)则决定了将同一个模型展示成什么样的视图。
 
3.从字符串中读取时间
有时我们会遇到从一个字符串中读取时间的要求,即从字符串中解析时间并得到一个Date对象,比如将"2017-8-24 11:17:10"解析为一个Date对象。现在问题来了,这个时间到底指的是北京时间的2017年8月24日11:17:10,还是东京时间的2017年8月24日11:17:10?如果指的是北京时间,那么这个时间对应的东京时间2017年8月24日12:17:10;如果指的是东京时间,那么这个时间对应的北京时间就是2017年8月24日10:17:10。因此,只说年月日时分秒而不说是哪个时区的,是有歧义的,没有歧义的做法是,给出一个时间字符串,同时指明这是哪个时区的时间。
从字符串中解析时间的正确作法是:指定时区来解析。示例如下:
String timeStr = "2017-8-24 11:17:10"; // 字面时间  
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai")); // 设置北京时区  
Date d = sdf.parse(timeStr);  
System.out.println(sdf.format(d) + ", " + d.getTime());</code>  
 输出为:
2017-08-24 11:17:10, 1503544630000,
 
将一个时间字符串按不同时区来解释,得到的Date对象的值是不同的。验证如下:
String timeStr = "2017-8-24 11:17:10"; // 字面时间
SimpleDateFormat bjSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
bjSdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
Date bjDate = bjSdf.parse(timeStr);  // 解析
System.out.println("字面时间: " + timeStr +",按北京时间来解释:" + bjSdf.format(bjDate) + ", " + bjDate.getTime());
 
SimpleDateFormat tokyoSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  // 东京
tokyoSdf.setTimeZone(TimeZone.getTimeZone("Asia/Tokyo"));  // 设置东京时区
Date tokyoDate = tokyoSdf.parse(timeStr); // 解析
System.out.println("字面时间: " + timeStr +",按东京时间来解释:"  + tokyoSdf.format(tokyoDate) + ", " + tokyoDate.getTime());
 输出为:
字面时间: 2017-8-24 11:17:10,按北京时间来解释:2017-08-24 11:17:10, 1503544630000
字面时间: 2017-8-24 11:17:10,按东京时间来解释:2017-08-24 11:17:10, 1503541030000
可以看出,对于"2017-8-24 11:17:10"这个字符串,按北京时间来解释得到Date对象的毫秒数是
1503544630000;而按东京时间来解释得到的毫秒数是1503541030000,前者正好比后者大于3600000毫秒即1个小时,正好是北京时间和东京时间的时差。这很好理解,北京时间2017-08-24 11:17:10对应的毫秒数是1503544630000,而东京时间2017-08-24 11:17:10对应的北京时间其实是2017-08-24 10:17:10(因为北京时间比东京时间晚1个小时),北京时间2017-08-24 10:17:10自然比北京时间2017-08-24 11:17:10少3600000毫秒。
 
4.将字符串表示的时间转换成另一个时区的时间字符串
综合以上分析,如果给定一个时间字符串,并告诉你这是某个时区的时间,要将它转换为另一个时区的时间并输出,正确的做法是:
1.将字符串按原时区转换成Date对象;
2.将Date对象格式化成目标时区的时间。
比如,将北京时间"2017-8-24 11:17:10"输出成东京时间,代码为:
String timeStr = "2017-8-24 11:17:10"; // 字面时间
SimpleDateFormat bjSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
bjSdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
Date date = bjSdf.parse(timeStr);  // 将字符串时间按北京时间解析成Date对象
 
SimpleDateFormat tokyoSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  // 东京
tokyoSdf.setTimeZone(TimeZone.getTimeZone("Asia/Tokyo"));  // 设置东京时区
System.out.println("北京时间: " + timeStr +"对应的东京时间为:"  + tokyoSdf.format(date));
 
原文:https://blog.csdn.net/halfclear/article/details/77573956
分享到:
评论

相关推荐

    java 时区转换工具包

    2. 解析指定时间 public static ZonedDateTime parse(String date,String dateFormat,int offset) 3. 获取某一天的零点 public static ZonedDateTime getTodayZonedDayBegin(int offset) 4. 指定某一天的零点 public...

    Java时区转换及Date类实现原理解析

    主要介绍了Java时区转换及Date类实现原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    java编程中String类型时间转化成Date类型

    java编程中String类型时间转化成Date类型

    Java的日期时间处理类讲解代码( Date 、Calendar、SimpleDateFormat、LocalDateTime)

    本源码资源提供了Java中的日期时间处理类相关内容,包括日期、时间和时区的操作方法和示例。它涵盖了Java编程中常用的日期时间处理需求以及如何使用日期时间类来解决这些问题。 适用人群 本源码资源适用于具备一定...

    JAVA 微信 rfc3339标准格式的时间转换

    最近开发微信收付通项目,简单记录一下时间类的...// 代码中的TimeZone.getTimeZone() 你可以选填时区 DateTime dt1 = new DateTime(new Date(),DateTimeZone.forTimeZone(TimeZone.getTimeZone(Asia/Shanghai))); //

    Java日期格式化及其使用例子

    SimpleDateFormat、 从字符串到日期类型的转换、获取系统时期和时间、转换成SQL格式后更新到数据库的用法

    java_时间日期管理的几乎所有标准代码_时区_时间日期格式的转换加减和比较_判断特殊日期

    将日期字符串转换为Date对象 将date-----&gt;String 将Date对象转换为指定格式的字符串 格式化日期的标准字符串 return当天的年月日 return当天的时分秒 return当天的年月日时分秒 获取星期几 日期中某个月份的第几周 ...

    JavaScript 脚本将当地时间转换成其它时区

    要做到这一点,必须进行各种时间计算才能将当地时间转换为目的时间。本文将解释如何进行这些计算。 第一步: 事情的第一步是获得当地时间。在JavaScript中,这无疑可以通过初始化一个Data()对象来轻松完成。 // ...

    JavaBusinessCalendar:Java 中的业务日历实现

    Java 中的业务日历实现 这个 api 基于 JBPM 商业日历。 用法 ###BusinessCalendar bc = BusinessCalendar(properties); 日历属性文件的属性位置请参见示例属性文件。 ###bc.isHoliday(日期); 日历日期 - 如果...

    Oracle_Database_11g完全参考手册.part3/3

     使用Java、JDBC和XMIL开发数据库应用程序  使用Oracle实时应用群集(RAC)优化可用性和可扩展性 内容提要 《Oracle Database 11g完全参考手册》全面详细地介绍了Oracle Database 11g的强大功能,阐述了如何使用...

    Oracle_Database_11g完全参考手册.part2/3

     使用Java、JDBC和XMIL开发数据库应用程序  使用Oracle实时应用群集(RAC)优化可用性和可扩展性 内容提要 《Oracle Database 11g完全参考手册》全面详细地介绍了Oracle Database 11g的强大功能,阐述了如何使用...

    java8源码-wx_order:wx_order

    类注释和方法注释 /** * @Auther: ${USER} * @Date: ${DATE} ${HOUR}:${MINUTE} * @Description: //TODO * @version: V1.0 */ @Data是lombok包的注解 断言的简单使用 单元测试Junit4 BeanUtils.copyProperties 可以...

    mysql官方中文参考手册

    11.3.1. DATETIME、DATE和TIMESTAMP类型 11.3.2. TIME类型 11.3.3. YEAR类型 11.3.4. Y2K事宜和日期类型 11.4. String类型 11.4.1. CHAR和VARCHAR类型 11.4.2. BINARY和VARBINARY类型 11.4.3. BLOB和TEXT类型 11.4.4...

    MySQL 5.1中文手冊

    11.3.1. DATETIME、DATE和TIMESTAMP类型 11.3.2. TIME类型 11.3.3. YEAR类型 11.3.4. Y2K事宜和日期类型 11.4. String类型 11.4.1. CHAR和VARCHAR类型 11.4.2. BINARY和VARBINARY类型 11.4.3. BLOB和TEXT类型 11.4.4...

    MYSQL中文手册

    11.3.1. DATETIME、DATE和TIMESTAMP类型 11.3.2. TIME类型 11.3.3. YEAR类型 11.3.4. Y2K事宜和日期类型 11.4. String类型 11.4.1. CHAR和VARCHAR类型 11.4.2. BINARY和VARBINARY类型 11.4.3. BLOB和TEXT类型...

    MySQL 5.1参考手册

    11.3.1. DATETIME、DATE和TIMESTAMP类型 11.3.2. TIME类型 11.3.3. YEAR类型 11.3.4. Y2K事宜和日期类型 11.4. String类型 11.4.1. CHAR和VARCHAR类型 11.4.2. BINARY和VARBINARY类型 11.4.3. BLOB和TEXT类型 11.4.4...

    MySQL 5.1参考手册中文版

    11.3.1. DATETIME、DATE和TIMESTAMP类型 11.3.2. TIME类型 11.3.3. YEAR类型 11.3.4. Y2K事宜和日期类型 11.4. String类型 11.4.1. CHAR和VARCHAR类型 11.4.2. BINARY和VARBINARY类型 11.4.3. BLOB和TEXT类型 ...

    MySQL5.1参考手册官方简体中文版

    11.3.1. DATETIME、DATE和TIMESTAMP类型 11.3.2. TIME类型 11.3.3. YEAR类型 11.3.4. Y2K事宜和日期类型 11.4. String类型 11.4.1. CHAR和VARCHAR类型 11.4.2. BINARY和VARBINARY类型 11.4.3. BLOB和TEXT类型 11.4.4...

    Oracle9i的init.ora参数中文说明

    说明: (如果值为 TRUE) 当在隐式转换中丢失数据时返回错误的参数。 值范围: FALSE | TRUE 默认值: TRUE nls_numeric_characters: 说明: 指定将用作组分隔符和小数位的字符。组分隔符就是用来分隔整数位组 (如千, ...

Global site tag (gtag.js) - Google Analytics