首页 Java java教程 YYYY? yyyy!

YYYY? yyyy!

Nov 17, 2024 pm 02:51 PM

你知道 Java 日期模式中的 'Y' 和 'y' 字符有什么区别吗?在本文中,我们将探讨不正确的日期格式如何导致错误。我们还将推出新的 Java V6122 诊断规则,让您免于突然的时间旅行。

YYYY? yyyy!

介绍

掸去大TODO笔记本上的灰尘后,我们偶然发现了一个特别有趣的案例。该文章的评论者强调了潜在的问题。

评论
顺便说一句,这里有一个主意:Java 中的 SimpleDateFormat 可以带来新年惊喜——用小写字母书写的年份与用大写字母书写的年份不同。在这一年的最后一周,您可能会突然发现自己身处未来,因为 2021 年 12 月 27 日至 2021 年 12 月 31 日的“YYYY”是 2022 年,而不是某些人预期的 2021 年。

让我们来一探究竟。

问题分析

日期格式

如果您忘记了 SimpleDateFormat 是什么,您可以在这里温习一下知识。

为了存储和显示日期,我们经常需要它们遵循特定的模式。 SimpleDateFormat 是一个类,使我们能够根据给定的模式轻松格式化日期。除了格式化之外,SimpleDateFormat还可以解析字符串并将其转换为日期对象。

这就是 Java 所能提供的全部吗?除了 SimpleDateFormat 之外,DateTimeFormatter 类还可以格式化日期。

让我向您展示使用这两个类的示例。

如果我们通过 SimpleDateFormat 格式化日期:

public static void main(String[] args) {
    Date date = new Date("2024/12/31");
    var dateFormatter = new SimpleDateFormat("dd-MM-yyyy");
    System.out.println(dateFormatter.format(date));
}
登录后复制
登录后复制
登录后复制

控制台显示以下内容:

2024年12月31日

这里发生了什么?

我们有日期,我们想以特定格式保存/显示它。为了实现它,我们通过将模式字符串传递给构造函数来创建 SimpleDateFormat 对象。日期的格式完全按照此模式进行。 format 方法返回格式化日期的字符串表示形式。这正是我们想要的。

这里是同样的事情,但是我们使用DateTimeFormatter:

public static void main(String[] args) {
    LocalDate date = LocalDate.of(2024, 12, 31);
    var formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
    System.out.println(formatter.format(date));
}
登录后复制
登录后复制
登录后复制

控制台显示以下内容:

2024年12月31日

相同的步骤和结果,但略有不同:DateTimeFormatter 使我们能够仅格式化由实现 TemporalAccessor 接口的类表示的日期。例如,其中包括 LocalDateLocalDateTimeSimpleDateFormat 仅格式化 Date 类的对象。

让我们回到评论。在日期模式中使用“Y”代替“y”真的会改变结果吗?

看一下代码:

public static void main(String[] args) {
    Date date = new Date("2024/12/31");
    var dateFormatter = new SimpleDateFormat("dd-MM-yyyy");
    System.out.println(dateFormatter.format(date));
}
登录后复制
登录后复制
登录后复制

控制台显示以下内容:

2025年12月31日

哎呀。 DateTimeFormatter 也是一样吗?

代码如下:

public static void main(String[] args) {
    LocalDate date = LocalDate.of(2024, 12, 31);
    var formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
    System.out.println(formatter.format(date));
}
登录后复制
登录后复制
登录后复制

控制台显示以下内容:

2025年12月31日

我们确实旅行到了一年后的未来。是时候看看发生了什么了。

问题本质

我的第一步是查看 SimpleDateFormat 类的文档。下面是表格的一小部分,描述了日期模式如何解释我们感兴趣的字母字符:

Letter Date or Time Component Presentation Examples
y Year Year 1996; 96
Y Week year Year 2009; 09

一年一周?让我解释一下。

周年是基于一年中的周数的一年。它是什么意思以及为什么它很重要?

在某些任务中,一年中周的序号很重要。为了确定一周的序列号,我们需要决定首先考虑哪一周。这是因为从一年到另一年的过渡通常会导致两年之间有几周的时间。那么,我们如何判断本周属于哪一年呢? ISO-8601 标准对此进行了规定。

根据这个标准,一年中的第一周必须满足以下条件:

  • 一周的第一天是星期一;
  • 一年中每周最少有四天。

由此,我们可以推导出一个简单的规则:如果星期四是一月,则一周被认为是一年的第一周。

一个现实生活中的例子可以进一步阐明这一点。

让我们从示例中获取日期,即 31.12.2024。以下是包含我们日期的一周的日历片段(2024 年 12 月至 2025 年 1 月):

Mo Tu We Th Fr Sa Su
30 31 1 2 3 4 5

本周被视为 2025 年的第一周,因为它满足上述条件(一月有 5 天)。因此,如果我们使用“Y”说明符,我们就会得到 2025 年。

你可以猜到,DateTimeFormatter 的情况是完全一样的。

需要注意的是,我们不仅可以穿越到未来,还可以穿越到过去。

我们换个日期吧,2027 年 1 月 1 日。

2027 年的第一周包括 1 月 1 日吗?再次,让我们查阅日历。

以下是包含我们日期的一周的日历片段(2026 年 12 月 - 2027 年 1 月):

Mo Tu We Th Fr Sa Su
28 29 30 31 1 2 3

由于这一周只有 3 天(根据要求第一周应该是 4 天),因此算作 2026 年的最后一周。所以,日期使用“Y”格式化时角色,将向我们展示2026。

这是证据。看一下代码:

public static void main(String[] args) {
    Date date = new Date("2024/12/31");
    var dateFormatter = new SimpleDateFormat("dd-MM-yyyy");
    System.out.println(dateFormatter.format(date));
}
登录后复制
登录后复制
登录后复制

控制台显示以下内容:

2026 年 1 月 1 日

好的,我们已经剖析了这个问题。我们还发现向 PVS-Studio Java 分析器添加专用诊断规则非常有趣。

实际项目中的错误

诊断规则已经写好了,是时候测试一下了。

在分析器的开发过程中,测试阶段之一涉及运行回归测试。我们有一篇关于此过程的文章。简而言之,当我们添加新的诊断规则时,我们会分析大量开源项目,并将新报告与参考报告进行比较。

在此诊断规则的情况下,分析器针对多个项目发出了新的警告。让我们来看看它们。

充气城堡

在这个项目中,诊断规则指向的代码片段是相同的,所以我只展示其中一个。

看一下代码:

public static void main(String[] args) {
    LocalDate date = LocalDate.of(2024, 12, 31);
    var formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
    System.out.println(formatter.format(date));
}
登录后复制
登录后复制
登录后复制

PVS-Studio 警告:

V6122 检测到使用“Y”(周年)模式:它可能打算使用“y”(年)。 SkeinParameters.java 246

首先,我浏览了GitHub。如果这确实是一个错误,开发人员已经发现它并提交了修复怎么办?这正是发生的事情。这是提交的链接,你可以查看一下。模式中的所有“Y”(周年)字符均替换为“y”(年)。

您可能想知道为什么提交是在相对较长的时间之前进行的。让我解释一下。我们的回归测试并不是为了持续控制这个或那个开源项目的质量。任务是查看添加新诊断规则时报告如何变化:旧警告不应消失,不应出现新错误,因为这表明分析仪存在问题。所以,检查的代码必须是相同的。

开放格罗克

现在让我们看一下触发诊断规则的第二个项目。

PVS-Studio 警告:

V6122 检测到使用“Y”(周年)模式:它可能打算使用“y”(年)。 RepositoryInfo.java 77

代码:

public static void main(String[] args) {
    Date date = new Date("2024/12/31");
    var dateFormatter = new SimpleDateFormat("dd-MM-YYYY");
    System.out.println(dateFormatter.format(date));
}
登录后复制

就像之前的项目一样,我冲到提交处看看发生了什么。首先,值得注意的是,由于重构,该字段已移至其派生类 Repository(这里是提交的链接)。我进一步搜索并找到了包含修复程序的提交。日期模式中的“Y”字符已替换为“y”:

public static void main(String[] args) {
    LocalDate date = LocalDate.of(2024, 12, 31);
    var formatter = DateTimeFormatter.ofPattern("dd-MM-YYYY");
    System.out.println(formatter.format(date));
}
登录后复制

所以,这里也是一个错误。

结论

在PVS-Studio,我们欢迎来自社区的任何反馈。在解决 Habr 用户的评论后,我们通过添加一些有用的诊断规则来增强 Java 分析器。因此,如果您有任何想法想与我们分享,我们很乐意在本文的评论部分与您聊天。

顺便说一句,诊断规则已在 10 月 7.33 版本中引入。因此,如果您想尝试我们的分析器,请使用此链接。

仅此而已。让我们把事情总结到这里吧。希望突然的前进(或倒退)一年不会让您措手不及。

以上是YYYY? yyyy!的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

公司安全软件导致应用无法运行?如何排查和解决? 公司安全软件导致应用无法运行?如何排查和解决? Apr 19, 2025 pm 04:51 PM

公司安全软件导致部分应用无法正常运行的排查与解决方法许多公司为了保障内部网络安全,会部署安全软件。...

如何将姓名转换为数字以实现排序并保持群组中的一致性? 如何将姓名转换为数字以实现排序并保持群组中的一致性? Apr 19, 2025 pm 11:30 PM

将姓名转换为数字以实现排序的解决方案在许多应用场景中,用户可能需要在群组中进行排序,尤其是在一个用...

如何使用MapStruct简化系统对接中的字段映射问题? 如何使用MapStruct简化系统对接中的字段映射问题? Apr 19, 2025 pm 06:21 PM

系统对接中的字段映射处理在进行系统对接时,常常会遇到一个棘手的问题:如何将A系统的接口字段有效地映�...

如何优雅地获取实体类变量名构建数据库查询条件? 如何优雅地获取实体类变量名构建数据库查询条件? Apr 19, 2025 pm 11:42 PM

在使用MyBatis-Plus或其他ORM框架进行数据库操作时,经常需要根据实体类的属性名构造查询条件。如果每次都手动...

IntelliJ IDEA是如何在不输出日志的情况下识别Spring Boot项目的端口号的? IntelliJ IDEA是如何在不输出日志的情况下识别Spring Boot项目的端口号的? Apr 19, 2025 pm 11:45 PM

在使用IntelliJIDEAUltimate版本启动Spring...

Java对象如何安全地转换为数组? Java对象如何安全地转换为数组? Apr 19, 2025 pm 11:33 PM

Java对象与数组的转换:深入探讨强制类型转换的风险与正确方法很多Java初学者会遇到将一个对象转换成数组的�...

电商平台SKU和SPU数据库设计:如何兼顾用户自定义属性和无属性商品? 电商平台SKU和SPU数据库设计:如何兼顾用户自定义属性和无属性商品? Apr 19, 2025 pm 11:27 PM

电商平台SKU和SPU表设计详解本文将探讨电商平台中SKU和SPU的数据库设计问题,特别是如何处理用户自定义销售属...

如何利用Redis缓存方案高效实现产品排行榜列表的需求? 如何利用Redis缓存方案高效实现产品排行榜列表的需求? Apr 19, 2025 pm 11:36 PM

Redis缓存方案如何实现产品排行榜列表的需求?在开发过程中,我们常常需要处理排行榜的需求,例如展示一个�...

See all articles