个人怎样做旅游网站,想建网站怎么做,那里做直播网站,哈尔滨整站java日期时间转日期长期以来#xff0c;正确处理日期#xff0c;时间#xff0c;时区#xff0c;夏令时#xff0c;and年等一直是我的烦恼。 本文并不是一个全面的指南时域#xff0c;请参阅日期和时间在Java中 -更详细#xff0c;但略有下降#xff0c;ekhem#xff… 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]而在Java中它表示没有任何特定日历天/月/年的时间点。 它的toString()具有误导性在系统时区中显示日历日期和时间。 不仅误导了成千上万的开发人员以为Date附加了时区。 此外它显示时间但日期应仅表示日期而不是小时。 它有20多个不推荐使用的方法包括getYear() parse(String)和许多构造函数。 之所以不建议使用这些方法是因为它们使您相信Date表示date 。 java.sql.Date扩展了java.util.Date 实际上更加准确因为它确实表示日历日期 SQL中的DATE 。 但是这缩小了基类Date的功能从而违反了Liskov替换原则 。 不相信我吗 java.util.Date.toInstant()可以正常工作但是java.sql.Date.toInstant()无条件地失败并带有UnsupportedOperationException …… 最糟糕的是 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的函数时您将永远不会期望它修改其参数 这就像具有一个接受x和y数字并重新调整它们的总和的函数一样。 如果您发现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.Date和Calendar在设计上已被破坏以至于它们在JDK 9中被完全弃用 。 只能通过提供时区ZonedDateTime从Instant创建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.05702: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:2102:00[Europe/Warsaw]
2016-08-05T18:2110:00[Australia/Sydney] 还是 将8月更改为2月相差为10小时 2016-02-05T10:2101:00[Europe/Warsaw]
2016-02-05T20:2111:00[Australia/Sydney] 这是因为华沙在2月冬季不进行夏令时而在悉尼则是夏季因此他们使用DST1小时。 反之亦然。 为了使事情变得更加复杂切换到DST的时间有所不同并且总是在当地时间的晚上因此必须有一个国家已经切换但另一个没有切换的时间例如10月 2016-10-05T10:2102:00[Europe/Warsaw]
2016-10-05T19:2111: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:2101:00[Europe/Warsaw]
2014-02-05T13:2104:00[Europe/Moscow] 但是一年后的同一天的差异是2小时 2015-02-05T10:2101:00[Europe/Warsaw]
2015-02-05T12:2103: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转换为Instant或ZonedDateTime 这两者都指向精确的时间点是不可能的或非常愚蠢的。 因此当地时间很有用但实际上并不能代表任何时刻。 测试中 我只是弄清楚了陷阱的表面并指出了约会可能带来的问题。 例如我们没有涵盖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.htmljava日期时间转日期