java 统一处理时区_Java时区处理初学者指南

java 统一处理时区

基本时间观念

大多数Web应用程序必须支持不同的时区,而正确处理时区绝非易事。 更糟糕的是,您必须确保各种编程语言(例如,前端JavaScript,中间件中的Java和作为数据存储库的MongoDB)之间的时间戳统一。 这篇文章旨在解释绝对时间和相对时间的基本概念。

时代

纪元是绝对的时间基准。 大多数编程语言(例如Java,JavaScript,Python)使用Unix纪元(1970年1月1日午夜)表示给定的时间戳,即自固定时间点引用以来经过的毫秒数。

相对数字时间戳

相对数字时间戳表示为从纪元开始经过的毫秒数。

时区

协调世界时(UTC)是最常见的时间标准。 UTC时区(等效于GMT )表示所有其他时区涉及的时间参考(通过正/负偏移量)。

UTC时区通常称为Zulu时间(Z)或UTC + 0。 日本时区是UTC + 9,而檀香山时区是UTC-10。 在Unix时代(1970年1月1日UTC时区),东京为1970年1月1日,檀香山为1969年12月31日14:00。

ISO 8601

ISO 8601是最广泛的日期/时间表示标准,它使用以下日期/时间格式:

时区 符号
世界标准时间 1970-01-01T00:00:00.000 + 00:00
UTC祖鲁时间 1970-01-01T00:00:00.000 + Z
时雄 1970-01-01T00:00:00.000 + 09:00
火奴鲁鲁 1969-12-31T14:00:00.000-10:00

Java时间基础

java.util.Date

java.util.Date绝对是最常见的时间相关类。 它表示一个固定的时间点,表示为自历元以来经过的相对毫秒数。 java.util.Date是与时区无关的 ,除了toString方法使用本地时区生成String表示形式。

java.util.Calendar

java.util.Calendar既是日期/时间工厂,也是时区感知定时实例。 它是最不友好的Java API类之一,我们可以在以下示例中进行演示:

@Test
public void testTimeZonesWithCalendar() throws ParseException {assertEquals(0L, newCalendarInstanceMillis("GMT").getTimeInMillis());assertEquals(TimeUnit.HOURS.toMillis(-9), newCalendarInstanceMillis("Japan").getTimeInMillis());assertEquals(TimeUnit.HOURS.toMillis(10), newCalendarInstanceMillis("Pacific/Honolulu").getTimeInMillis());Calendar epoch = newCalendarInstanceMillis("GMT");epoch.setTimeZone(TimeZone.getTimeZone("Japan"));assertEquals(TimeUnit.HOURS.toMillis(-9), epoch.getTimeInMillis());
}private Calendar newCalendarInstance(String timeZoneId) {Calendar calendar = new GregorianCalendar();calendar.set(Calendar.YEAR, 1970);calendar.set(Calendar.MONTH, 0);calendar.set(Calendar.DAY_OF_MONTH, 1);calendar.set(Calendar.HOUR_OF_DAY, 0);calendar.set(Calendar.MINUTE, 0);calendar.set(Calendar.SECOND, 0);calendar.set(Calendar.MILLISECOND, 0);calendar.setTimeZone(TimeZone.getTimeZone(timeZoneId));return calendar;
}

在Unix时代(UTC时区),东京时间提前了9个小时,而檀香山却落后了10个小时。

更改日历时区会在偏移时区偏移时保留实际时间。 相对时间戳随日历时区偏移量而变化。

Joda-Time和Java 8 Date Time API只是使java.util.Calandar过时,因此您不必再使用此古怪的API。

org.joda.time.DateTime

Joda-Time旨在通过提供以下服务来修复旧版Date / Time API:

  • 不变和可变的日期结构
  • 流利的API
  • 更好地支持ISO 8601标准

使用Joda-Time,这就是我们之前的测试用例的样子:

@Test
public void testTimeZonesWithDateTime() throws ParseException {assertEquals(0L, newDateTimeMillis("GMT").toDate().getTime());assertEquals(TimeUnit.HOURS.toMillis(-9), newDateTimeMillis("Japan").toDate().getTime());assertEquals(TimeUnit.HOURS.toMillis(10), newDateTimeMillis("Pacific/Honolulu").toDate().getTime());DateTime epoch = newDateTimeMillis("GMT");assertEquals("1970-01-01T00:00:00.000Z", epoch.toString());epoch = epoch.toDateTime(DateTimeZone.forID("Japan"));assertEquals(0, epoch.toDate().getTime());assertEquals("1970-01-01T09:00:00.000+09:00", epoch.toString());MutableDateTime mutableDateTime = epoch.toMutableDateTime();mutableDateTime.setChronology(ISOChronology.getInstance().withZone(DateTimeZone.forID("Japan")));assertEquals("1970-01-01T09:00:00.000+09:00", epoch.toString());
}private DateTime newDateTimeMillis(String timeZoneId) {return new DateTime(DateTimeZone.forID(timeZoneId)).withYear(1970).withMonthOfYear(1).withDayOfMonth(1).withTimeAtStartOfDay();
}

DateTime流利的API比java.util.Calendar#set易于使用。 DateTime是不可变的,但是如果适合当前的用例,我们可以轻松地切换到MutableDateTime 。

与我们的Calendar测试用例相比,当更改时区时,相对时间戳不会改变,因此保持相同的原始时间点。

只是人类的时间感知发生了变化( 1970-01-01T00:00:00.000Z1970-01-01T09:00:00.000 + 09:00指向相同的绝对时间)。

相对时间与绝对时间实例

在支持时区时,基本上有两种主要选择:相对时间戳和绝对时间信息。

相对时间戳

时间戳的数字表示形式(自纪元以来的毫秒数)是相对信息。 该值是针对UTC时代给出的,但是您仍然需要一个时区来正确表示特定区域上的实际时间。

它是一个很长的值,是最紧凑的时间表示形式,是交换大量数据时的理想选择。

如果您不知道原始事件的时区,则可能会显示与当前本地时区相对的时间戳,这并不总是可取的。

绝对时间戳

绝对时间戳包含相对时间以及时区信息。 在ISO 8601字符串表示中表示时间戳是很常见的。

与数字形式(64位长)相比,字符串表示的紧凑性较低,它最多可包含25个字符(UTF-8编码为200位)。

ISO 8601在XML文件中非常普遍,因为XML模式使用的是受ISO 8601标准启发的词汇格式 。

当我们想针对原始时区重构时间实例时,绝对时间表示会更加方便。 电子邮件客户端可能希望使用发件人的时区显示电子邮件创建日期,而这只能使用绝对时间戳来实现。

谜题

以下练习旨在说明使用古老的java.text.DateFormat实用程序正确处理符合ISO 8601的日期/时间结构有多么困难。

java.text.SimpleDateFormat

首先,我们将使用以下测试逻辑来测试java.text.SimpleDateFormat解析功能:

/*** DateFormat parsing utility* @param pattern date/time pattern* @param dateTimeString date/time string value* @param expectedNumericTimestamp expected millis since epoch */
private void dateFormatParse(String pattern, String dateTimeString, long expectedNumericTimestamp) {try {Date utcDate = new SimpleDateFormat(pattern).parse(dateTimeString);if(expectedNumericTimestamp != utcDate.getTime()) {LOGGER.warn("Pattern: {}, date: {} actual epoch {} while expected epoch: {}", new Object[]{pattern, dateTimeString, utcDate.getTime(), expectedNumericTimestamp});}} catch (ParseException e) {LOGGER.warn("Pattern: {}, date: {} threw {}", new Object[]{pattern, dateTimeString, e.getClass().getSimpleName()});}
}

用例1

让我们看看各种ISO 8601模式如何针对第一个解析器表现:

dateFormatParse("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "1970-01-01T00:00:00.200Z", 200L);

产生以下结果:

Pattern: yyyy-MM-dd'T'HH:mm:ss.SSS'Z', date: 1970-01-01T00:00:00.200Z actual epoch -7199800 while expected epoch: 200

此模式不符合ISO 8601。 单引号字符是转义序列,因此最后的“ Z”符号不会被视为时间指令(例如Zulu时间)。 解析之后,我们将简单地获取本地时区的Date参考。

该测试是使用我当前的系统默认欧洲/雅典时区运行的,截至撰写本文时,它比UTC提前两个小时。

用例2

根据java.util.SimpleDateFormat文档,以下模式: yyyy-MM-dd'T'HH:mm:ss.SSSZ应该匹配ISO 8601日期/时间字符串值:

dateFormatParse("yyyy-MM-dd'T'HH:mm:ss.SSSZ", "1970-01-01T00:00:00.200Z", 200L);

但是相反,我们得到了以下异常:

Pattern: yyyy-MM-dd'T'HH:mm:ss.SSSZ, date: 1970-01-01T00:00:00.200Z threw ParseException

因此,此模式似乎无法解析Zulu时间UTC字符串值。

用例3

以下模式对显式偏移量非常适用:

dateFormatParse("yyyy-MM-dd'T'HH:mm:ss.SSSZ", "1970-01-01T00:00:00.200+0000", 200L);

用例4

此模式还与其他时区偏移量兼容:

dateFormatParse("yyyy-MM-dd'T'HH:mm:ss.SSSZ", "1970-01-01T00:00:00.200+0100", 200L - 1000 * 60 * 60);

用例5

为了匹配祖鲁语时间符号,我们需要使用以下模式:

dateFormatParse("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", "1970-01-01T00:00:00.200Z", 200L);

用例6

不幸的是,最后一个模式与明确的时区偏移量不兼容:

dateFormatParse("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", "1970-01-01T00:00:00.200+0000", 200L);

最后出现以下异常:

Pattern: yyyy-MM-dd'T'HH:mm:ss.SSSXXX, date: 1970-01-01T00:00:00.200+0000 threw ParseException

org.joda.time.DateTime

java.text.SimpleDateFormat相反, Joda-Time与任何ISO 8601模式兼容。 以下测试用例将用于即将推出的测试用例:

/*** Joda-Time parsing utility* @param dateTimeString date/time string value* @param expectedNumericTimestamp expected millis since epoch*/
private void jodaTimeParse(String dateTimeString, long expectedNumericTimestamp) {Date utcDate = DateTime.parse(dateTimeString).toDate();if(expectedNumericTimestamp != utcDate.getTime()) {LOGGER.warn("date: {} actual epoch {} while expected epoch: {}", new Object[]{dateTimeString, utcDate.getTime(), expectedNumericTimestamp});}
}

Joda-Time与所有标准ISO 8601日期/时间格式兼容:

jodaTimeParse("1970-01-01T00:00:00.200Z", 200L);
jodaTimeParse("1970-01-01T00:00:00.200+0000", 200L);
jodaTimeParse("1970-01-01T00:00:00.200+0100", 200L - 1000 * 60 * 60);

结论

如您所见,古老的Java Date / Time实用程序不易使用。 Joda-Time是更好的选择,提供更好的时间处理功能。

如果您碰巧使用Java 8,则值得切换到Java 8 Date / Time API ,该API是从头开始设计的,但受Joda-Time启发很大。

  • 代码可在GitHub上获得 。

翻译自: https://www.javacodegeeks.com/2014/11/a-beginners-guide-to-java-time-zone-handling.html

java 统一处理时区

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/339030.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

服务器系统装内存条,hp服务器怎么安装内存条 hp服务器内存推荐【图文】

服务器虚拟化增加了在每台惠普服务器上运行工作负载的数量,但是越来越多的计算需求则要求IT人员配备更好的HP服务器配件。因此需要对于HP服务器内存市场行情有一定的了解,而选择合适的HP服务器内存却是一件非常难的事情,今天就跟小编一起来看…

7个C语言小程序让你快速入门程序世界

1、题目:有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?程序分析:可填在百位、十位、个位的数字都是1、2、3、4。组成所有的排列后再去掉不满足条件的排列。程序源代码:#include#…

去重 属性_面试中常问的List去重问题,你都答对了吗?

面试中经常被问到的list如何去重,用来考察你对list数据结构,以及相关方法的掌握,体现你的java基础学的是否牢固。我们大家都知道,set集合的特点就是没有重复的元素。如果集合中的数据类型是基本数据类型,可以直接将lis…

python paramiko模块下载_Python自动化运维实战:使用Python管理网络设备

现在,我们已经知道如何在不同的操作系统中使用和安装Python以及如何使用EVE-NG搭建网络拓扑。在本章中,我们将学习如何使用目前常用的网络自动化库自动完成各种网络任务。Python可以在不同的网络层上与网络设备进行交互。首先,Python可以通过…

cxf添加拦截器_在CXF API和拦截器中添加Gzip压缩

cxf添加拦截器如今&#xff0c;由于我们在响应中发送大量数据&#xff0c;因此必须对API响应执行Gziping。 它节省了网络带宽和交付时间&#xff0c;当然还节省了Internet上的空间。 CXF提供了以多种方式使用Gzip压缩的选项。 蓝图 注解 蓝图&#xff1a; <bean id"…

3月14日dnf服务器维护,DNF体验服3月14日更新介绍 肝深渊送爆肝王称号!

DNF体验服在3月14日更新全新活动&#xff0c;本次活动奖励总体来看还是非常不错的。例如账绑称号、异界气息清除书、锻造炉等超值奖励&#xff0c;下面让我们来看具体的更新内容吧。PS&#xff1a;本次体验服更新内容将会在3月22日更新至正式服中去。艾肯副本相关1、艾肯副本模…

C语言程序判断计算机的CPU大小端

如何判断一台计算机的CPU是大端还是小字端对齐呢&#xff1f;那么首先得了解何为大端&#xff0c;何为小端&#xff0c;明确一下概念。所谓大端模式&#xff0c;是指字数据的高字节存储在低地址中&#xff0c;而字数据的低字节则存放在高地址中。小端格式&#xff1a;与大端存储…

三角形周长最短问题_一道三角形周长最小值问题

昨天早上&#xff0c;在朋友圈里看到有朋友发了一道求三角形周长最小值的问题&#xff0c;扫了一眼&#xff0c;觉得这条题目形容臃肿&#xff0c;颜值不高&#xff0c;估计没啥意思&#xff0c;便未作深究。晚上&#xff0c;又看到有人在朋友圈中发这条题目。同一条题目反复出…

java 性能调优_Java性能调优调查结果(第二部分)

java 性能调优这是系列文章的第二篇&#xff0c;我们将分析2014年10月进行的性能调整调查的结果。如果您尚未阅读第一部分&#xff0c;我们建议从此处开始 。 第二部分将重点监视Java应用程序的性能问题。 特别是&#xff0c;我们尝试回答以下问题&#xff1a; 人们如何发现性…

西门子伺服电机选型手册_记,新入行维修电工大胆拆解伺服电机和编码器的经历...

作为一名底层维修电工&#xff0c;最怕碰到维修外置编码器的伺服电机&#xff0c;我们单位用的是西门子S120的驱动方案&#xff0c;绝大多数使用的都是西门子配套电机&#xff0c;组态简单&#xff0c;也不用我们维修&#xff0c;有问题送到西门子授权维修点维修。只有个别的使…

变频器服务器电路板维修,变频器线路板常见维修方法

(1)驱动电路损坏的原因及检查造成驱动损坏的原因有各种各样的&#xff0c;一般来说出现的问题也无非是U&#xff0c;V&#xff0c;W三相无输出&#xff0c;或者输出不平衡&#xff0c;再或者输出平衡但是在低频的时候抖动&#xff0c;还有启动报警等等。当一台变频器大电容后的…

C语言 | 输出月份的英文

“要成为绝世高手&#xff0c;并非一朝一夕&#xff0c;除非是天生武学奇才&#xff0c;但是这种人…万中无一”——包租婆这道理放在C语言学习上也一并受用。在编程方面有着天赋异禀的人毕竟是少数&#xff0c;我们大多数人想要从C语言小白进阶到高手&#xff0c;需要经历的是…

rac san+oracle_Oracle11g1+RAC+install+for+CentOS5(ASM+to+FC+SAN)_IT168文库

Wp1998gmail.comV2011.3.3.1一&#xff0e;安裝環境1.1網絡示意1.2所需軟件linux.x64_11gR1_clusterware.ziplinux.x64_11gR1_database_1013.ziporacleasmlib-2.0.4-1.el5.x86_64.rpmoracleasm-support-2.1.4-1.el5.x86_64.rpmoracleasm-2.6.18-194.el5-2.0.5-1.el5.x86_64.rpm…

中兴5250交换机配置手册_TSN工业交换机中文说明

全面了解CC-Link协议家族宣布CLPA会员公司赫斯曼推出最新研发支持TSN的工业交换机RSPE35&#xff0c;同时这款TSN交换机与三菱CC-Link IE TSN产品连接配置手册也已发布&#xff0c;并在文中附了下载。文章传送门↓可是&#xff0c;交换机的资料都是日文和英语的&#xff0c;能否…

华为桌面云 服务器可以虚拟多少,【华为桌面云】案例:单服务器环境且只有两块本地SATA盘创建虚拟机非常慢...

【关键词】&#xff1a;单服务器&#xff0c;SATA盘&#xff0c;创建虚拟机慢&#xff0c;创建VM慢【适用版本】&#xff1a;FusionAccess V100R005 /FusionSphere V100R003【问题描述】&#xff1a;某局点工程师反馈&#xff0c;他使用单台RH2288V2服务器搭建测试环境&#xf…

C语言 | 为什么写这三行代码

C语言实现Hello xiaolin#include//头文件 int main()//主函数 程序的入口 { printf("Hello xiaolin!\n");// \n是换行的意思 return 0;}编译运行结果&#xff1a;Hello xiaolin!--------------------------------Process exited after 3.326 seconds with return v…

如何分析堆外内存使用情况_堆上与堆外的内存使用情况

如何分析堆外内存使用情况总览 最近有人问我在Java中使用堆内存的好处和智慧。 面临相同选择的其他人可能会对这些答案感兴趣。 堆外内存没什么特别的。 线程堆栈&#xff0c;应用程序代码&#xff0c;NIO缓冲区都在堆外。 实际上&#xff0c;在C和C 中&#xff0c;您只有非托…

centos 虚拟机glibc升级_分享Centos6.5升级glibc过程

上次看到有同学对Centos系统 glibc升级有点疑问, 不过相对来说glibc升级还是比较简单的, 网上也有很多介绍文章, 这里整理了个安装过程供大家参考下 阅读原文场景需求默认的Centos6.5 glibc版本最高为2.12, 而在进行Nodejs开发时项目所依赖的包往往需要更高版本的glibc库支持, …

windows redis批量删除前缀的key_阿里官方Redis开发规范!

本文主要介绍在使用阿里云Redis的开发规范&#xff0c;从下面几个方面进行说明。键值设计命令使用客户端使用相关工具通过本文的介绍可以减少使用Redis过程带来的问题。一、键值设计1、key名设计可读性和可管理性以业务名(或数据库名)为前缀(防止key冲突)&#xff0c;用冒号分隔…

matchers依赖_Hamcrest Matchers的高级创建

matchers依赖介绍 上一次 &#xff0c;我讨论了Hamcrest Matcher是什么&#xff0c;如何使用以及如何制作。 在本文中&#xff0c;我将解释创建Hamcrest Matchers的更多高级步骤。 首先&#xff0c;我将分享如何使您的匹配器更易于类型安全&#xff0c;然后介绍无状态匹配器的一…