我的编程空间,编程开发者的网络收藏夹
学习永远不晚

深入了解Java.Util.Date详情

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

深入了解Java.Util.Date详情

前言:

很少有类能像java.util.Date那样在堆栈溢出方面引起如此多的类似问题,有四个原因:

  • 日期和时间工作基本上相当复杂,而且充满了拐弯抹角的情况。这是可以管理的,但你确实需要花一些时间来理解它。
  • java.util.Date类在很多方面都很糟糕(详情如下)。
  • 一般来说,开发人员对它的理解很差。
  • 它被库作者严重滥用,进一步加剧了混乱。

了解java.util.Date最重要的事情为:

  • 如果可能的话,你应该避免。使用java.time.*如果可能的话,也可以使用ThreeTen Backport(基本上是旧版本的java.time)或Joda time(如果您还没有使用java 8)。
  • 如果您被迫使用它,请避免使用不推荐使用的成员。近20年来,它们中的大多数都被弃用了,这是有充分理由的。
  • 如果您真的觉得必须使用不推荐的成员,请确保您真正理解他们。
  • Date实例表示时间上的一个瞬间,而不是日期。重要的是,这意味着:
  • 它没有时区。
  • 它没有格式。
  • 它没有日历系统。

现在,关于细节…

Java.Util.Date有什么问题?

java.util.Date(从现在开始就是Date)是一种糟糕的类型,这解释了为什么Java 1.1中有这么多的Date被弃用(但不幸的是,它仍然在使用)。

设计缺陷包括:

  • 它的名字令人误解:它不代表日期,它代表的是时间上的一个瞬间。因此,它应该被称为Instant,就像它的java.time一样等效。
  • 这是非最终结果:这鼓励了java等继承的不当使用。java.sql.Date(表示日期,由于具有相同的短名称,因此也容易混淆)
  • 它是可变的:日期/时间类型是由不可变类型有效建模的自然值。日期是可变的(例如通过setTime方法),这意味着勤奋的开发人员最终会在各地创建防御副本。
  • 它在许多地方隐式使用系统本地时区,包括toString(),这让许多开发人员感到困惑。
  • 它的月份编号是以0为基础的,是从C复制的。这导致了很多很多错误。
  • 它的年份编号是基于1900年的,也是从C中复制的。当然,当Java问世时,我们已经有了这样一个想法,即这对可读性不利?
  • 其方法的名称不明确:getDate()返回月份的第几天,getDay()返回星期几。给这些更具描述性的名字有多难?
  • 它是否支持闰秒是不明确的:“一秒由0到61之间的整数表示;值60和61只在闰秒中出现,甚至仅在实际正确跟踪闰秒的Java实现中出现。”我强烈怀疑大多数开发人员(包括我自己)都做了大量假设,认为getSeconds()的范围实际上在0-59(包括0-59)之间。
  • 没有明显的理由,它是宽大的:“在所有情况下,为这些目的而给出的方法的参数都不需要在指定的范围内;例如,日期可以指定为1月32日,也可以解释为2月1日。”这是否有用?

我可以发现更多的问题,但他们会越来越挑剔。这是一个非常丰富的列表。好的一面是:

  • 它明确地表示一个值:时间上的一个瞬间,没有相关的日历系统、时区或文本格式,精确到毫秒。

不幸的是,开发人员对这一“好方面”的理解也很差。让我们把它打开…

什么是“瞬间”

注意:在这篇文章的其余部分,我忽略了相对论和闰秒。它们对一些人来说非常重要,但对大多数读者来说,它们只会带来更多的困惑。

当我谈论“瞬间”时,我指的是可以用来识别什么时候发生了什么的概念。(这可能发生在将来,但最容易从过去的事情来考虑。)它独立于时区和日历系统,因此多个使用“本地”时间表示的人可以用不同的方式谈论它。

让我们用一个非常具体的例子来说明发生在不使用我们熟悉的时区的地方的事情:尼尔·阿姆斯特朗在月球上行走。月球行走开始于一个特定的时刻——如果来自世界各地的多个人同时观看,他们会(几乎)同时说“我现在可以看到它正在发生”。

如果你在休斯顿的任务控制中心观看,你可能会想到那一刻是“1969年7月20日,CDT晚上9:56:20”。如果你在伦敦观看,你可能会想到那一刻是“1969年7月21日,英国夏令时凌晨3:26:20”。如果你在利雅得观看,你可能会认为那一刻是“1389年7月7日上午5:56:20(+03)”(使用《古拉经》日历)。尽管不同的观察者会在他们的时钟上看到不同的时间,甚至不同的年份,但他们仍然会考虑同一时刻。他们只是在应用不同的时区和日历系统,将即时转换为更人性化的概念。

那么,计算机如何表示实例呢?它们通常在一个特定的瞬间之前或之后存储一定量的时间,而这个瞬间实际上是一个原点。许多系统使用Unix纪元,这是格里高历中以UTC表示的1970年1月1日开始的午夜。这并不意味着纪元本质上是“在”UTC中的——Unix纪元同样可以定义为“1969年12月31日纽约下午7点的那一刻”。

Date类使用“自Unix纪元以来的毫秒数”——这是getTime()返回的值,由Date(long)构造函数或setTime()方法设置。由于月球行走发生在Unix纪元之前,因此该值为负值:实际上是-14159020000

为了演示日期如何与系统时区交互,让我们展示前面提到的三个时区–休斯顿(美国/芝加哥)、伦敦(欧洲/伦敦)和利雅得(亚洲/利雅得)。当我们从历元毫秒值构建日期时,系统时区是什么并不重要,这根本不取决于本地时区。但如果我们使用Date.toString(),它转换为当前默认时区以显示结果。更改默认时区根本不会更改日期值。对象的内部状态完全相同。它仍然表示相同的瞬间,但toString()getMonth()getDate()等方法将受到影响。

下面的示例代码显示:

import java.util.Date;
import java.util.TimeZone;

public class Test {

    public static void main(String[] args) {
        // The default time zone makes no difference when constructing
        // a Date from a milliseconds-since-Unix-epoch value
        Date date = new Date(-14159020000L);

        // Display the instant in three different time zones
        TimeZone.setDefault(TimeZone.getTimeZone("America/Chicago"));
        System.out.println(date);

        TimeZone.setDefault(TimeZone.getTimeZone("Europe/London"));
        System.out.println(date);

        TimeZone.setDefault(TimeZone.getTimeZone("Asia/Riyadh"));
        System.out.println(date);

        // Prove that the instant hasn't changed...
        System.out.println(date.getTime());
    }
}

输出如下:

Sun Jul 20 21:56:20 CDT 1969
Mon Jul 21 03:56:20 GMT 1969
Mon Jul 21 05:56:20 AST 1969
-14159020000

这里的输出中的“GMT”和“AST”缩写非常不幸——java.util.TimeZone并非在所有情况下都具有1970年之前值的正确名称。不过时机已经成熟。

常见问题

如何将Date日期转换为其他时区?

你没有——因为约会没有时区。这是一个瞬间。不要被toString()的输出所愚弄。这会显示默认时区中的瞬间。这不是值的一部分。

如果代码以日期作为输入,则已经发生了从“本地时区”到即时的任何转换。(希望操作正确……)

如果您开始编写一个带有这样签名的方法,那么您并没有帮助自己:

// A method like this is always wrong
Date convertTimeZone(Date input, TimeZone fromZone, TimeZone toZone)

如何将Date日期转换为其他格式?

你没有——因为日期没有格式。不要被toString()的输出所愚弄。始终使用相同的格式,如文档所述。要以特定方式格式化日期,请使用合适的日期格式(可能是SimpleDataFormat)——记住将时区设置为适合您使用的适当区域。

到此这篇关于深入了解Java.Util.Date详情的文章就介绍到这了,更多相关Java.Util.Date 内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

深入了解Java.Util.Date详情

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

一文带你深入了解Node.js(图文详解)

本篇文章通过超多代码和图解来带大家深入解析Node.js,主要内容包括模块化处理、包的基本应用、Express、跨域、操作Mysql数据库等,希望对大家有所帮助!
2023-05-14

深入了解mysql索引

1、索引原理 索引被用来快速找出在一个列上用一特定值的行。没有索引,MySQL不得不首先以第一条记录开始,然后读完整个表直到它找出相关的行。表越大,花费时间越多。对于一个有序字段,可以运用二分查找(Binary Search),这就是为什么
2022-05-14

深入了解mysql长事务

前言: 本篇文章主要介绍MySQL长事务相关内容,比如说我们开启的一个事务,一直没提交或回滚会怎样呢,出现事务等待情况应该如何处理,本篇文章将给你答案。注意:本篇文章并不聚焦于谈论事务隔离级别以及相关特性。而是介绍长事务相关危害以及监控处
2022-05-20

深入了解Android中的AsyncTask

AsyncTask,即异步任务,是Android给我们提供的一个处理异步任务的类。通过此类,可以实现UI线程和后台线程进行通讯,后台线程执行异步任务,并把结果返回给UI线程。 我们知道,Android中只有UI线程,也就是主线程才能进行对
2022-06-06

深入了解Redis的性能

简介 多少次你发现自己在几个月的开发和无数的努力后陷入了毫无性能而言的web应用?多少次你在好奇如果你无法向普通用户传达快与最快的标准,你的客户还应该把你当作专家?多少你听到有关Google和Facebook一些糟糕的对比?让我告诉你,我的
2022-06-04

深入了解Node中的Buffer

最开始的时候 JS 只在浏览器端运行,对于 Unicode 编码的字符串容易处理,但是对于二进制和非 Unicode 编码的字符串处理困难。并且二进制是计算机最底层的数据格式,视频/音频/程序/网络包
2023-05-14

深入Understanding Android ContentProvider详解

1. 什么是ContentProvider也即内容提供者,是对所有数据访问的一层抽象,为数据访问提供了统一的接口。它有以下优点:a. 对数据的抽象,为所有的组件提供统一的访问数据的方式,从而让组件不必关心具体数据的呈现形式(文件or数据库)
2022-06-06

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录