Java 日期时间类全面解析

news2025/6/9 8:52:00

Java 日期时间类全面解析:从传统到现代的演进

一、发展历程概览

二、传统日期类(Java 8前)

1. java.util.Date - 日期表示类
Date now = new Date(); // 当前日期时间
System.out.println(now); // Wed May 15 09:30:45 CST 2023

// 特定时间创建
Date specificDate = new Date(121, 4, 15); // 2021-05-15 (已弃用)

​主要问题​​:

  • 年份从1900开始计数
  • 月份0-11(实际需+1)
  • 线程不安全
  • 时区处理混乱
2. java.util.Calendar - 日期操作类
Calendar cal = Calendar.getInstance();
cal.set(2023, Calendar.MAY, 15); // 2023-05-15

// 日期计算
cal.add(Calendar.DAY_OF_MONTH, 7); // 加7天

// 获取值
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH) + 1; // 月份需+1

​缺点​​:

  • API设计臃肿
  • 可变对象(线程不安全)
  • 仍存在月份偏移问题
3. java.text.SimpleDateFormat - 日期格式化
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String formatted = sdf.format(new Date()); // 2023-05-15 09:30:45

// 解析日期
Date parsedDate = sdf.parse("2023-05-15 12:00:00");

​致命缺陷​​:

  • ​非线程安全​​(必须在方法内创建或使用ThreadLocal)

三、现代日期时间API(Java 8+)

java.time包提供了全新的日期时间处理API:

1. 核心类对比表
类名描述示例值
LocalDate只包含日期2023-05-15
LocalTime只包含时间09:30:45
LocalDateTime日期+时间2023-05-15T09:30:45
ZonedDateTime带时区的日期时间2023-05-15T09:30:45+08:00[Asia/Shanghai]
Instant时间戳(Unix时间)1684114245
Period日期间隔(年/月/日)P1Y2M3D
Duration时间间隔(秒/毫秒)PT8H30M
2. 基础使用示例
// 获取当前日期
LocalDate today = LocalDate.now();

// 创建特定日期
LocalDate birthday = LocalDate.of(1990, Month.DECEMBER, 25);

// 日期计算
LocalDate nextWeek = today.plusWeeks(1);
LocalDate previousMonth = today.minusMonths(1);

// 日期比较
boolean isAfter = today.isAfter(birthday);
boolean isLeapYear = today.isLeapYear();
3. 时间操作
LocalTime nowTime = LocalTime.now();
LocalTime meetingTime = LocalTime.of(14, 30); // 14:30

// 时间加减
LocalTime lunchTime = nowTime.plusHours(1).plusMinutes(30);

// 时间判断
if (nowTime.isBefore(LocalTime.NOON)) {
    System.out.println("上午好!");
}
4. 日期时间组合
LocalDateTime meetingDateTime = LocalDateTime.of(
    2023, Month.MAY, 15, 14, 30);
    
// 转换为时区时间
ZonedDateTime shanghaiMeeting = meetingDateTime.atZone(ZoneId.of("Asia/Shanghai"));

// 转换为其他时区
ZonedDateTime newYorkMeeting = shanghaiMeeting.withZoneSameInstant(
    ZoneId.of("America/New_York"));
5. 时间间隔计算
// 日期间隔(年/月/日)
Period period = Period.between(
    LocalDate.of(2020, 1, 1), 
    LocalDate.now()
);
System.out.println(period.getYears() + "年" + 
                  period.getMonths() + "月");

// 时间间隔(精确时间)
Duration duration = Duration.between(
    LocalTime.of(9, 0), 
    LocalTime.now()
);
System.out.println(duration.toMinutes() + "分钟");

四、格式化与解析

1. DateTimeFormatter - 替代SimpleDateFormat
DateTimeFormatter formatter = DateTimeFormatter
    .ofPattern("yyyy-MM-dd HH:mm:ss")
    .withZone(ZoneId.systemDefault());

// 格式化
String formatted = LocalDateTime.now().format(formatter);

// 解析
LocalDateTime parsed = LocalDateTime.parse("2023-05-15 14:30:00", formatter);
2. 预定义格式器
// ISO标准格式
String isoFormat = LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);

// 本地化格式
DateTimeFormatter localizedFormatter = DateTimeFormatter
    .ofLocalizedDateTime(FormatStyle.MEDIUM)
    .withLocale(Locale.CHINA);

String chineseFormat = LocalDateTime.now().format(localizedFormatter);

五、与传统类的转换

// Date 转 Instant
Date legacyDate = new Date();
Instant instant = legacyDate.toInstant();

// Instant 转 Date
Date newDate = Date.from(Instant.now());

// Calendar 转 ZonedDateTime
Calendar calendar = Calendar.getInstance();
ZonedDateTime zdt = ZonedDateTime.ofInstant(
    calendar.toInstant(), 
    calendar.getTimeZone().toZoneId()
);

六、最佳实践指南

  1. ​版本选择​​:

    • Java 8+项目:​​始终使用java.time​
    • 旧项目兼容:使用Joda-Time(第三方库)
  2. ​时区处理原则​​:

    // 明确时区而非依赖系统默认
    ZonedDateTime zonedNow = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
    
    // UTC时间优先存储
    Instant utcInstant = Instant.now();
  3. ​避免使用枚举值​​:

    // 推荐
    LocalDate date = LocalDate.of(2023, Month.MAY, 15);
    
    // 不推荐(可能因月份偏移引发错误)
    LocalDate date = LocalDate.of(2023, 5, 15); 
  4. ​线程安全实践​​:

    // DateTimeFormatter线程安全可共享
    public static final DateTimeFormatter GLOBAL_FORMATTER = 
        DateTimeFormatter.ISO_LOCAL_DATE;
    
    // SimpleDateFormat必须每个线程独立实例
    private static final ThreadLocal<SimpleDateFormat> threadLocalSdf = 
        ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));

七、经典问题解决方案

1. 工作日计算
LocalDate start = LocalDate.of(2023, 1, 1);
LocalDate end = LocalDate.of(2023, 12, 31);

long workDays = Stream.iterate(start, date -> date.plusDays(1))
    .limit(ChronoUnit.DAYS.between(start, end))
    .filter(date -> date.getDayOfWeek() != DayOfWeek.SATURDAY)
    .filter(date -> date.getDayOfWeek() != DayOfWeek.SUNDAY)
    .count();
2. 夏令时处理
ZoneId zone = ZoneId.of("America/New_York");
ZonedDateTime springTime = ZonedDateTime.of(2023, 3, 12, 2, 30, 0, 0, zone);

// 自动处理时间跳变(会调整为03:30)
System.out.println(springTime); // 2023-03-12T03:30-04:00[America/New_York]
3. 精确时间计算
Instant start = Instant.now();
// 执行操作...
Instant end = Instant.now();

Duration elapsed = Duration.between(start, end);
System.out.printf("操作耗时: %d毫秒", elapsed.toMillis());

八、Joda-Time(老项目备用方案)

// 引入依赖
implementation 'joda-time:joda-time:2.12.5'

// 使用示例
DateTime now = new DateTime();
DateTime nextWeek = now.plusWeeks(1);
DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MM-dd");
String formatted = fmt.print(now);

总结思考

  1. ​演进本质​​:

    • 从​​可变对象​​ → ​​不可变对象​​(线程安全)
    • 从​​过程式操作​​ → ​​流畅API​
    • 从​​隐含规则​​ → ​​显式表达​
  2. ​选择策略​​:

    场景推荐方案
    新项目java.time
    Android项目java.time + ThreeTenABP
    Java 7及以下Joda-Time
    简单日期操作LocalDate/LocalTime
    全球时间系统Instant/ZonedDateTime
  3. ​设计启示​​:

    • ​清晰性​​:消除月份偏移等隐含规则
    • ​类型安全​​:专用类型处理不同时间概念
    • ​领域驱动​​:方法命名直击业务语义(plusDays()、isAfter())

​最终建议​​:所有新项目应优先使用java.time API,老项目逐步迁移。掌握现代日期时间API,是构建健壮时间敏感型应用的基石。

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

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

相关文章

【工具-Wireshark 抓包工具】

工具-Wireshark 抓包工具 ■ Wireshark 抓包工具■ 通过IP指定查看■■ ■ Wireshark 抓包工具 抓包工具】win 10 / win 11&#xff1a;WireShark 下载、安装、使用 Wireshark下载 阿里云镜像 ■ 通过IP指定查看 ■ ■

设备驱动与文件系统:06 目录与文件

磁盘使用的最后一层抽象&#xff1a;文件系统 今天我们讲第31讲&#xff0c;这一讲将完成磁盘对磁盘使用的最后一层抽象。对此板使用最后一层抽象&#xff0c;抽象出来的是什么呢&#xff1f; 实际上我们使用过磁盘&#xff0c;大家应该有这样的认识&#xff0c;最后不管这个磁…

Linux 系统中的算法技巧与性能优化

引言​ Linux 系统以其开源、稳定和高度可定制的特性&#xff0c;在服务器端、嵌入式设备以及开发环境中得到了极为广泛的应用。对于开发者而言&#xff0c;不仅要掌握在 Linux 环境下实现各类算法的方法&#xff0c;更要知晓如何利用系统特性对算法进行优化&#xff0c;以提升…

【C++系列】模板类型特例化

1. C模板类型特例化介绍 ​​定义​​&#xff1a;模板类型特例化&#xff08;Template Specialization&#xff09;是C中为模板的特定类型提供定制实现的机制&#xff0c;允许开发者对通用模板无法处理的特殊类型进行优化或特殊处理。 ​​产生标准​​&#xff1a; C98/03…

K8S认证|CKS题库+答案| 7. Dockerfile 检测

目录 7. Dockerfile 检测 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、修改 Dockerfile 3&#xff09;、 修改 deployment.yaml 7. Dockerfile 检测 免费获取并激活 CKA_v1.31_模拟系统 题目 您必须在以…

基于Scala实现Flink的三种基本时间窗口操作

目录 代码结构 代码解析 (1) 主程序入口 (2) 窗口联结&#xff08;Window Join&#xff09; (3) 间隔联结&#xff08;Interval Join&#xff09; (4) 窗口同组联结&#xff08;CoGroup&#xff09; (5) 执行任务 代码优化 (1) 时间戳分配 (2) 窗口大小 (3) 输出格式…

c++对halcon的动态链接库dll封装及调用(细细讲)

七个部分(是个大工程) 一,halcon封装函数导出cpp的内容介绍 二,c++中对halcon环境的配置 三,在配置环境下验证halcon代码 四,dll项目创建+环境配置 五,编辑dll及导出 六,调用打包好的动态链接库的配置 七,进行测试 一,halcon的封装及导出cpp的介绍 1,我这里…

【优选算法】分治

一&#xff1a;颜色分类 class Solution { public:void sortColors(vector<int>& nums) {// 三指针法int n nums.size();int left -1, right n, i 0;while(i < right){if(nums[i] 0) swap(nums[left], nums[i]);else if(nums[i] 2) swap(nums[--right], num…

【图片识别改名】如何批量将图片按图片上文字重命名?自动批量识别图片文字并命名,基于图片文字内容改名,WPF和京东ocr识别的解决方案

应用场景 在日常工作和生活中&#xff0c;我们经常会遇到需要对大量图片进行重命名的情况。例如&#xff0c;设计师可能需要根据图片内容为设计素材命名&#xff0c;文档管理人员可能需要根据扫描文档中的文字对图片进行分类命名。传统的手动重命名方式效率低下且容易出错&…

RabbitMQ 的高可用性

RabbitMQ 是比较有代表性的&#xff0c;因为是基于主从&#xff08;非分布式&#xff09;做高可用的RabbitMQ 有三种模式&#xff1a;单机模式、普通集群模式、镜像集群模式。 单机模式 单机模式,生产几乎不用。 普通集群模式&#xff08;无高可用性&#xff09; 普通集群模…

AI架构师修炼之道

1 AI时代的架构革命 与传统软件开发和软件架构师相比&#xff0c;AI架构师面临着三重范式转换&#xff1a; 1.1 技术维度&#xff0c;需处理异构算力调度与模型生命周期管理的复杂性&#xff1b; 1.2 系统维度&#xff0c;需平衡实时性与资源约束的矛盾&#xff1b; 1.3 价…

iview组件库:当后台返回到的数据与使用官网组件指定的字段不匹配时,进行修改某个属性名再将response数据渲染到页面上的处理

1、需求导入 当存在前端需要的数据的字段渲染到表格或者是一些公共的表格组件展示数据时的某个字段名与后台返回的字段不一致时&#xff0c;那么需要前端进行稍加处理&#xff0c;而不能直接this.list res.data;这样数据是渲染不出来的。 2、后台返回的数据类型 Datalist(pn) …

服务器 | Centos 9 系统中,如何部署SpringBoot后端项目?

系列文章目录 虚拟机 | Ubuntu 安装流程以及界面太小问题解决 虚拟机 | Ubuntu图形化系统&#xff1a; open-vm-tools安装失败以及实现文件拖放 虚拟机 | Ubuntu操作系统&#xff1a;su和sudo理解及如何处理忘记root密码 文章目录 系列文章目录前言一、环境介绍二、 使用syst…

(2025)Windows修改JupyterNotebook的字体,使用JetBrains Mono

(JetBrains Mono字体未下载就配置,这种情况我不知道能不能行,没做过实验,因为我电脑已经下载了,不可能删了那么多字体做实验,我的建议是下载JetBrains Mono字体,当你使用VsCode配置里面的JetBrains字体也很有用) 首先参考该文章下载字体到电脑上 VSCode 修改字体为JetBrains …

小番茄C盘清理:专业高效的电脑磁盘清理工具

在使用电脑的过程中&#xff0c;我们常常会遇到系统盘空间不足、磁盘碎片过多、垃圾文件堆积等问题&#xff0c;这些问题不仅会导致电脑运行缓慢&#xff0c;还可能引发系统崩溃。为了解决这些问题&#xff0c;小番茄C盘清理应运而生。它是一款专业的C盘清理软件&#xff0c;能…

AUTOSAR实战教程--标准协议栈实现DoIP转DoCAN的方法

目录 软件架构 关键知识点 第一:PDUR的缓存作用 第二:CANTP的组包拆包功能 第三:流控帧的意义 配置过程 步骤0:ECUC模块中PDU创建 步骤1:SoAD模块维持不变 步骤2:DoIP模块为Gateway功能添加Connection ​步骤3:DoIP模块为Gateway新增LA/TA/SA ​步骤4:PDUR模…

【MySQL系列】MySQL 导出表数据到文件

博客目录 一、使用 SELECT INTO OUTFILE 语句基本语法参数详解注意事项实际示例 二、使用 mysqldump 工具基本语法常用选项实际示例 三、使用 MySQL Workbench 导出导出步骤高级选项 四、其他导出方法1. 使用 mysql 命令行客户端2. 使用 LOAD DATA INFILE 的逆向操作3. 使用编程…

vue3:十五、管理员管理-页面搭建

一、页面效果 实现管理员页面,完成管理员对应角色的中文名称显示,实现搜索栏,表格基本增删改查,分页等功能 二、修改问题 1、修改搜索框传递参数问题 (1)问题图示 如下图,之前搜索后,传递的数据不直接是一个value值,而是如下图的格式 查询可知这里传递的数据定义的是…

基于51单片机的红外防盗及万年历仿真

目录 具体实现功能 设计介绍 资料内容 全部内容 资料获取 具体实现功能 具体功能&#xff1a; &#xff08;1&#xff09;实时显示年、月、日、时、分、秒、星期信息&#xff1b; &#xff08;2&#xff09;红外传感器&#xff08;仿真中用按键模拟&#xff09;检测是否有…

【飞腾AI加固服务器】全国产化飞腾+昇腾310+PCIe Switch的AI大模型服务器解决方案

以下是全国产化飞腾AI加固服务器采用飞腾昇腾PCIe Switch解决方案&#xff1a; &#x1f5a5;️ 一、硬件架构亮点 ‌国产算力双擎‌ ‌飞腾处理器‌&#xff1a;搭载飞腾FT2000/64核服务器级CPU&#xff08;主频1.8-2.2GHz&#xff09;&#xff0c;支持高并发任务与复杂计算&a…