java日期时间转日期_Java时间和日期指南

java日期时间转日期

长期以来,正确处理日期,时间,时区,夏令时,and年等一直是我的烦恼。 本文并不是一个全面的指南时域,请参阅日期和时间在Java中 -更详细,但略有下降,ekhem,日期。 它仍然是相关的,但是没有涵盖Java 8中的java.time 。我想介绍每个初级Java开发人员都应该意识到的绝对最低要求。

事件何时发生?

除了哲学和量子物理学,我们还可以将时间视为一维度量标准,即实数值。 随着时间的流逝,该值将不断增长。 如果一个事件接连发生,我们将为该事件分配更多时间。 同时发生的两个事件具有相同的时间值。 出于实际原因,在计算机系统中,我们将时间存储为离散整数,这主要是因为计算机时钟离散地滴答。 因此,我们可以将时间存储为整数值。 按照惯例,我们将time = 0分配给1970年1月1日,但是在Java中,此值每毫秒递增一次,而不是像UNIX time那样每秒递增。 历史上在UNIX时间中使用32位带符号整数将导致2038年问题 。 因此,Java将时间存储在64位整数中,即使您将其增加一千次也足够了。 话虽这么说,但用Java存储时间的最简单但有效的方法是…… long原始语言:

long timestamp = System.currentTimeMillis();

long存在的问题是,它太普遍了,以至于使用它来存储时间会破坏类型系统。 它可以是ID,可以是哈希值,可以是任何东西。 而且long没有与时域相关的任何有意义的方法。 包裹的第一个办法long在更有意义的对象是java.util.Date因为Java 1.0中称为:

Date now = new Date();

Date类具有很多缺陷:

  1. 它不代表…日期。 认真地讲,正式日期是“ […]由数字[…]指定的月份或年份中的日期” [1],而在Java中,它表示没有任何特定日历(天/月/年)的时间点。
  2. 它的toString()具有误导性,在系统时区中显示日历日期和时间。 不仅误导了成千上万的开发人员以为Date附加了时区。 此外,它显示时间,但日期应仅表示日期,而不是小时。
  3. 它有20多个不推荐使用的方法,包括getYear()parse(String)和许多构造函数。 之所以不建议使用这些方法,是因为它们使您相信Date表示date
  4. java.sql.Date扩展了java.util.Date ,实际上更加准确,因为它确实表示日历日期 (SQL中的DATE )。 但是,这缩小了基类Date的功能,从而违反了Liskov替换原则 。 不相信我吗 java.util.Date.toInstant()可以正常工作,但是java.sql.Date.toInstant()无条件地失败,并带有UnsupportedOperationException ……
  5. 最糟糕的是, Date可变的

有没有想过为什么您的团队中老旧且脾气暴躁的开发人员对不变性如此兴奋? 想象一下一段代码,它将任何一分钟添加到Date 。 简单吧?

Date addOneMinute(Date in) {in.setTime(in.getTime() + 1_000 * 60);return in;
}

看起来不错吧? 所有测试用例都通过了,因为在测试代码后,究竟谁会验证输入参数是否完整?

Date now = new Date();
System.out.println(now);
System.out.println(addOneMinute(now));
System.out.println(now);

输出可能如下所示:

Tue Jul 26 22:59:22 CEST 2016
Tue Jul 26 23:00:22 CEST 2016
Tue Jul 26 23:00:22 CEST 2016

您是否注意到, now值在一分钟后实际上已更改了? 当您有一个使用Date并返回Date的函数时,您将永远不会期望它修改其参数! 这就像具有一个接受xy数字并重新调整它们的总和的函数一样。 如果您发现x在加法过程中被某种方式修改,则所有假设都将被破坏。 顺便说一下,这就是java.lang.Integer不可变的原因。 或String 。 或BigDecimal

这不是人为的例子。 想象一个带有单个方法的ScheduledTask类:

class ScheduledTask {Date getNextRunTime();
}

如果我说:

ScheduledTask task = //...
task.getNextRunTime().setTime(new Date());

更改返回的Date是否对下一次运行时间有效? 还是ScheduledTask返回了您可以自由修改的内部状态的副本? 也许我们会让ScheduledTask处于某种不一致的状态? 如果Date是不可变的,就不会出现这样的问题。

有趣的是,如果您将Java与JavaScript混淆,那么每个Java开发人员都会大怒。 但是,请猜测一下, JavaScript中的Date具有与java.util.Date完全相同的缺陷,并且似乎是复制粘贴的不良示例。 JavaScript中的Date是可变的,具有误导性的toString()并且不支持任何时区。

Date一个很好的替代方法是java.time.Instant 。 它恰如其名地做到了:及时存储时间。 Instant没有日期或日历相关的方法,它的toString()在UTC时区使用熟悉的ISO格式(稍后会详细介绍),最重要的是:它是不可变的。 如果您想记住特定事件何时发生, Instant是使用纯Java所能获得的最好的结果:

Instant now = Instant.now();
Instant later = now.plusSeconds(60);

请注意, Instant没有plusMinutes()plusHours()等。 分钟,小时和天是与日历系统相关的概念,而“ Instant在地理和文化上均不可知。

具有

有时您确实需要即时的人为表示。 这包括月份,星期几,当前时间等。 但这是一个主要的复杂问题:日期和时间因国家和地区而异。 Instant是简单且通用的,但对人类不是很有用,它只是一个数字。 如果您具有与日历相关的业务逻辑,例如:

  • …必须在办公时间内发生…
  • 最多一天
  • ……两个工作日……
  • …有效期长达一年…

那么您必须使用某些日历系统。 java.time.ZonedDateTime是绝对糟糕的java.util.Calendar的最佳替代方案。 实际上, java.util.DateCalendar在设计上已被破坏,以至于它们在JDK 9中被完全弃用 。 只能通过提供时区ZonedDateTimeInstant创建ZonedDateTime 。 否则,将使用您无法控制的默认系统时区。 在不提供显式ZoneId情况下以任何方式将Instant转换为ZonedDateTime可能是一个错误:

Instant now = Instant.now();
System.out.println(now);ZonedDateTime dateTime = ZonedDateTime.ofInstant(now,ZoneId.of("Europe/Warsaw"));System.out.println(dateTime);

输出如下:

2016-08-05T07:00:44.057Z
2016-08-05T09:00:44.057+02:00[Europe/Warsaw]

请注意,“ Instant (为方便起见)以UTC格式显示日期,而ZonedDateTime使用提供的ZoneId (夏季+2小时,以后更多)。

日历误解

关于时间和日历有许多误解和神话。 例如,有些人认为两个位置之间的时差始终是恒定的。 至少有两个原因不成立。 首先是夏令时,又称夏令时:

LocalDate localDate = LocalDate.of(2016, Month.AUGUST, 5);
LocalTime localTime = LocalTime.of(10, 21);
LocalDateTime local = LocalDateTime.of(localDate, localTime);
ZonedDateTime warsaw = ZonedDateTime.of(local, ZoneId.of("Europe/Warsaw"));ZonedDateTime sydney = warsaw.withZoneSameInstant(ZoneId.of("Australia/Sydney"));System.out.println(warsaw);
System.out.println(sydney);

输出显示华沙和悉尼之间的时差恰好是8小时:

2016-08-05T10:21+02:00[Europe/Warsaw]
2016-08-05T18:21+10:00[Australia/Sydney]

还是? 将8月更改为2月,相差为10小时:

2016-02-05T10:21+01:00[Europe/Warsaw]
2016-02-05T20:21+11:00[Australia/Sydney]

这是因为华沙在2月(冬季)不进行夏令时,而在悉尼则是夏季,因此他们使用DST(+1小时)。 反之亦然。 为了使事情变得更加复杂,切换到DST的时间有所不同,并且总是在当地时间的晚上,因此必须有一个国家已经切换但另一个没有切换的时间,例如10月:

2016-10-05T10:21+02:00[Europe/Warsaw]
2016-10-05T19:21+11:00[Australia/Sydney]

相差9小时。 时间偏移不同的另一个原因是政治上的:

LocalDate localDate = LocalDate.of(2014, Month.FEBRUARY, 5);
LocalTime localTime = LocalTime.of(10, 21);
LocalDateTime local = LocalDateTime.of(localDate, localTime);
ZonedDateTime warsaw = ZonedDateTime.of(local, ZoneId.of("Europe/Warsaw"));ZonedDateTime moscow = warsaw.withZoneSameInstant(ZoneId.of("Europe/Moscow"));System.out.println(warsaw);
System.out.println(moscow);

2014年2月5日华沙与莫斯科之间的时差为3小时:

2014-02-05T10:21+01:00[Europe/Warsaw]
2014-02-05T13:21+04:00[Europe/Moscow]

但是一年后的同一天的差异是2小时:

2015-02-05T10:21+01:00[Europe/Warsaw]
2015-02-05T12:21+03:00[Europe/Moscow]

那是因为俄罗斯疯狂地改变了他们的DST政策和时区。

关于日期的另一个常见误解是一天是24小时。 这又与夏时制有关:

LocalDate localDate = LocalDate.of(2017, Month.MARCH, 26);
LocalTime localTime = LocalTime.of(1, 0);
ZonedDateTime warsaw = ZonedDateTime.of(localDate, localTime, ZoneId.of("Europe/Warsaw"));ZonedDateTime oneDayLater = warsaw.plusDays(1);Duration duration = Duration.between(warsaw, oneDayLater);
System.out.println(duration);

您知道吗,2017年3月26日凌晨1点与27点之间的差是……23小时( PT23H )。 但是,如果您将时区更改为Australia/Sydney您会在24小时内熟悉,因为那天悉尼没有什么特别的事情发生。 悉尼那个特别的日子恰好是2017年4月2日:

LocalDate localDate = LocalDate.of(2017, Month.APRIL, 2);
LocalTime localTime = LocalTime.of(1, 0);
ZonedDateTime warsaw = ZonedDateTime.of(localDate, localTime, ZoneId.of("Australia/Sydney"));

结果是一天等于…25小时。 但不在距悉尼以北一千公里的布里斯班( "Australia/Brisbane" )中,这里没有DST。 为什么所有这些都很重要? 当您与客户达成协议时,假设某件商品需要花费一天而不是24小时的时间,这实际上可能会在某天产生很大的变化。 您必须非常精确,否则系统将每年两次变得不一致。 而且不要让我一leap而就。

在这里要学习的课程是,每次输入日历域时,都必须考虑时区。 有一些使用默认系统时区的便捷方法,但是在云环境中,您可能无法对此进行控制。 默认字符编码也是如此,但是情况有所不同。

储存和传输时间

默认情况下,您应该以时间戳( long值)或ISO 8601的形式存储和发送时间,这基本上是Instant.toString()根据文档进行的操作。 最好使用long值,因为它更紧凑,除非您需要使用某些文本编码(例如JSON)来使用更具可读性的格式。 时区不可知还long因此您不假装发送/存储的时区具有任何意义。 这既适用于传输时间,又适用于将其存储在数据库中。

在某些情况下,您可能希望发送完整的日历信息,包括时区。 例如,当您构建一个聊天应用程序时,如果您的朋友居住在不同的时区,您可能想告诉客户发送消息的本地时间是什么。 否则,您会知道它是在您的时间上午10点发送的,但是您朋友所在的时间是几点呢? 另一个例子是机票预订网站。 您想告诉客户何时飞机起飞并到达当地时间,而只有服务器知道起飞和到达目的地的确切时区。

当地时间和日期

有时,您希望表达没有特定时区的日期或时间。 例如我的生日是:

//1985-12-25
LocalDate.of(1985, Month.DECEMBER, 25)

无论我身在何处,我都会那天庆祝我的生日。 这意味着聚会将从大约开始:

//20:00
LocalTime.of(20, 0, 0)

与时区无关。 我什至可以说我今年的生日聚会正好在:

//2016-12-25T20:00
LocalDateTime party = LocalDateTime.of(LocalDate.of(2016, Month.DECEMBER, 25),LocalTime.of(20, 0, 0)
);

但是,只要我不为您提供位置,您就不会知道我所居住的时区,因此实际的开始时间是什么。 在没有给出时区的情况下将LocalDateTime转换为InstantZonedDateTime (这两者都指向精确的时间点)是不可能的(或非常愚蠢的)。 因此,当地时间很有用,但实际上并不能代表任何时刻。

测试中

我只是弄清楚了陷阱的表面,并指出了约会可能带来的问题。 例如,我们没有涵盖leap年,which年可能会成为严重的错误来源。 在测试日期时,我发现基于属性的测试非常有用:

import spock.lang.Specification
import spock.lang.Unrollimport java.time.*class PlusMinusMonthSpec extends Specification {static final LocalDate START_DATE =LocalDate.of(2016, Month.JANUARY, 1)@Unrolldef '#date +/- 1 month gives back the same date'() {expect:date == date.plusMonths(1).minusMonths(1)where:date << (0..365).collect {day -> START_DATE.plusDays(day)}}}

此测试可确保在2016年的任何日期加上或减去一个月会返回相同的日期。 很简单吧? 该测试失败了几天:

date == date.plusMonths(1).minusMonths(1)
|    |  |    |             |
|    |  |    2016-02-29    2016-01-29
|    |  2016-01-30
|    false
2016-01-30date == date.plusMonths(1).minusMonths(1)
|    |  |    |             |
|    |  |    2016-02-29    2016-01-29
|    |  2016-01-31
|    false
2016-01-31date == date.plusMonths(1).minusMonths(1)
|    |  |    |             |
|    |  |    2016-04-30    2016-03-30
|    |  2016-03-31
|    false
2016-03-31...

years年会引起各种问题,并破坏数学定律。 另一个类似的示例是,向日期添加两个月并不总是等于两次添加一个月。

摘要

我们再一次勉强刮伤了表面。 如果我只想从本文中学到一件事,请注意时区!

翻译自: https://www.javacodegeeks.com/2016/08/guide-time-date-java.html

java日期时间转日期

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

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

相关文章

linux过滤端口抓包_Linux抓包工具tcpdump使用总结,WireShark的过滤用法

tcpdump与WireShark是Linux下的两个常用&#xff0c;功能强大的抓包工具&#xff0c;下面列出这两个工具的简单用法。tcpdump用法tcpdump用法&#xff1a;sudo tcpdump -i ens33 src 192.168.0.19 port 80 -xx -Xs 0 -w test.capsudo tcpdump -i ens33 src port 80 -xx -Xs 0 -…

C++ 11 深度学习(十一)final和override

1. final C 中增加了 final 关键字来限制某个类不能被继承&#xff0c;或者某个虚函数不能被重写&#xff0c;和 Jave 的 final 关键字的功能是类似的。如果使用 final 修饰函数&#xff0c;只能修饰虚函数&#xff0c;并且要把final关键字放到类或者函数的后面。 1.1 修饰函数…

交流伺服系统设计指南_交流设计

交流伺服系统设计指南软件设计至关重要。 它是应用程序的基础。 就像蓝图一样&#xff0c;它为所有背景的聚会提供了一个通用平台。 它有助于理解&#xff0c;协作和发展。 设计不应仅视为开发的要素。 它不应该仅仅存在于开发人员的脑海中&#xff0c;否则团队将发现它几乎无…

【前缀和与差分】

前缀和 前缀和的作用&#xff1a;快速计算数组中某一段区间内的总和 1.需要两个额外的数组&#xff0c;来存储原始数据的数组 和 计算过前缀的数组。其原理为前缀和的数组中每个元素用来保存前i个原数组中的和&#xff0c;下一个元素更新就采用s[i] s[i] - 1 a [i] 来持续更…

allergro音乐术语什么意思_rit(这是音乐术语)什么意思?

是渐慢的意思常用的音乐表情术语&#xff1a;速度标记largo——广板lento——慢板adagio——柔板grave——壮板andante——行板andantino——小行板moderato——中板allegretto——小快板allegro——快板vivo——快速有生气vivace——快速有生气presto——急板常用的音乐表情术…

英文连词_连词我们…讨厌

英文连词最近&#xff0c;我写了与实现相关的名称&#xff0c;并提供了一些示例&#xff0c;这些示例由于方法名称与主体之间的紧密关系而导致方法名称不正确。 有一会儿&#xff0c;我们有以下代码&#xff1a; boolean isComplexOrUnreadableWithTests() { return (complex…

Ubuntu系统手动安装英伟达驱动程序

屏蔽开源驱动nouveau 安装过程会询问是否屏蔽&#xff0c;手动屏蔽也有多种操作方式&#xff0c; sudo gedit /etc/modprobe.d/blacklist.conf 加参数到最底下回车另起一行内容为 blacklist nouveau options nouveau modeset0 保存再终端更新内核命令 sudo update-initr…

workbench拓扑优化教程_workbenchds拓扑优化分析.ppt

workbenchds拓扑优化分析形状优化基础 指定Shape Optimization 将执行形状或拓扑优化 Shape Optimization是一个优化问题,其结构能量在减少结构体积的基础上的最小化 另一种观点就是Shape Optimization尽量得到关于体积比率的最好刚度. Shape Optimization尽可能的找寻可以在对…

maven 父maven_Maven神秘化

maven 父maven由于我的Android开发的背景下&#xff0c;我比较习惯到Gradle &#xff0c;而不是Maven的 。 尽管我知道Gradle基于Maven&#xff0c;但我从未调查过幕后发生的事情。 在过去的一周中&#xff0c;我一直在尝试了解细节并找出Maven的不同组成部分。 什么是Maven M…

【WebRTC---序篇】(一)为什么要使用WebRTC

1.1.1自研直播客户端架构 一个最简单的直播客户端至少应该包括音视频采集模块,音视频编码模块,网络传输模块,音视频解码模块和音视频渲染模块五大部分。如下图所示 1.1.2拆分音视频模块 在实际开发中,音频和视频处理完全是独立的。如下图所示,经过细分后,音频采集与视频…

python实现lenet_吴裕雄 python 神经网络TensorFlow实现LeNet模型处理手写数字识别MNIST数据集...

importtensorflow as tftf.reset_default_graph()#配置神经网络的参数INPUT_NODE 784OUTPUT_NODE 10IMAGE_SIZE 28NUM_CHANNELS 1NUM_LABELS 10#第一层卷积层的尺寸和深度CONV1_DEEP 32CONV1_SIZE 5#第二层卷积层的尺寸和深度CONV2_DEEP 64CONV2_SIZE 5#全连接层的节点个数F…

DFS(深度搜索最简单的应用)

全排列数字 #include<iostream>using namespace std;const int N 10;int n 3; //最终输出 int path[N]; //记录当前使用过的数 int st[N];void dfs(int u) {if (u n){for (int i 0; i < n; i)printf("%d ", path[i]);puts("");return;}for (…

lucene学习笔记_学习Lucene

lucene学习笔记我目前正在与一个团队合作&#xff0c;开始一个基于Lucene的新项目。 虽然大多数时候我会争论使用Solr还是Elasticsearch而不是简单的Lucene&#xff0c;但这是一个有意识的决定。 在这篇文章中&#xff0c;我正在整理一些学习Lucene的资源–希望您对他们有所帮助…

websocket没准备好如何解决_那些很重要,但是不常用的技术,websocket

目录1. 为什么会有websocket2. websocket协议格式3. 协议具体实现一、为什么需要 WebSocket&#xff1f;初次接触 WebSocket 的人&#xff0c;都会问同样的问题&#xff1a;我们已经有了 HTTP 协议&#xff0c;为什么还需要另一个协议&#xff1f;它能带来什么好处&#xff1f;…

DFS深搜与BFS广搜专题

一般搜索算法的流程框架 DFS和BFS与一般搜索流程的关系 如果一般搜索算法流程4使用的是stack栈结构(先进后出&#xff0c;后进先出)那么就会越搜越深。即&#xff0c;DFS&#xff0c;DFS只保存当前一条路径&#xff0c;其目的是枚举出所有可能性。反之&#xff0c;如果流程4使…

cloud foundry_使用“另类” Cloud Foundry Gradle插件无需停机

cloud foundry我一直在尝试编写用于将应用程序部署到Cloud Foundry的gradle插件 &#xff0c;并在上一篇文章中写了有关此插件的文章 。 现在&#xff0c;我通过使用两种方法支持将无停机时间部署到Cloud Foundry中来增强此插件&#xff1a; 自动驾驶风格部署和更常用的蓝绿色风…

lisp文字上标源码_创建文本/标注样式源码 - AutoLISP/Visual LISP 编程技术 - CAD论坛 - 明经CAD社区 - Powered by Discuz!...

本帖最后由 zhengxiansz 于 2014-4-27 11:27 编辑GU_xl你好&#xff01;请帮我看一下这个创建文本/标注样式源码。第一次输入IT1命令时没有报错的提示。如果重复输入IT1命令时就会提示该名称已被使用&#xff0c;是否重新定义&#xff1f;请问有什么方法可以解决吗&#xff1f;…

从前有座山,山里有座庙:递归之法

递归描述 递归调用是函数内部调用自身的过程&#xff0c;递归必须要有结束条件&#xff0c;否则会进入无限递归状态。无法停止。 我们称这个条件为&#xff08;递归基&#xff09; 递归原理 递归包括&#xff08;递推&#xff09;和&#xff08;回归&#xff09;&#xff0c;…

你只是看起来很努力_我的方法在这方面看起来很大吗?

你只是看起来很努力以下Java方法的大小是多少&#xff1f; public Collection getDescription() {SystemLibrary systemLib registry.get(SystemLibrary.class);Analysis analysis systemLib.getCurrentAnalysis(registry);return getDescription(analysis);}这个不起眼的方…

0xFFFFFF的问题

这个有两个结果&#xff1a;16777215和-1 如果是单纯的16 进制数&#xff0c;那么转换为10 进制数为16777215。相信这个转换结果很好理解&#xff1a;15*16^015*16^1...15*16^5。j即&#xff08;int型所能表示的最大值&#xff09; 第二种情况就是 0xFFFFFF 如果是在计算机中…