当前位置: 首页 > news >正文

为什么建议使用你 LocalDateTime ,而不是 Date

为什么建议使用你 LocalDateTime ,而不是 Date?

在项目开发过程中经常遇到时间处理,但是你真的用对了吗,理解阿里巴巴开发手册中禁用static修饰SimpleDateFormat吗

通过阅读本篇文章你将了解到:
 

  • 为什么需要LocalDate、LocalTime、LocalDateTime【java8新提供的类】

  • java8新的时间API的使用方式,包括创建、格式化、解析、计算、修改
     

为什么需要LocalDate、LocalTime、LocalDateTime
 

  • Date如果不格式化,打印出的日期可读性差

Tue Sep 10 09:34:04 CST 2019  
  • 使用SimpleDateFormat对时间进行格式化,但SimpleDateFormat是线程不安全的SimpleDateFormat的format方法最终调用代码:

private StringBuffer format(Date date, StringBuffer toAppendTo,  FieldDelegate delegate) {  // Convert input date to time field list  calendar.setTime(date);  boolean useDateFormatSymbols = useDateFormatSymbols();  for (int i = 0; i < compiledPattern.length; ) {  int tag = compiledPattern[i] >>> 8;  int count = compiledPattern[i++] & 0xff;  if (count == 255) {  count = compiledPattern[i++] << 16;  count |= compiledPattern[i++];  }  switch (tag) {  case TAG_QUOTE_ASCII_CHAR:  toAppendTo.append((char)count);  break;  case TAG_QUOTE_CHARS:  toAppendTo.append(compiledPattern, i, count);  i += count;  break;  default:  subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);  break;  }  }  return toAppendTo;  }  

calendar是共享变量,并且这个共享变量没有做线程安全控制。当多个线程同时使用相同的SimpleDateFormat对象【如用static修饰的SimpleDateFormat】调用format方法时,多个线程会同时调用calendar.setTime方法,可能一个线程刚设置好time值另外的一个线程马上把设置的time值给修改了导致返回的格式化时间可能是错误的。

在多并发情况下使用SimpleDateFormat需格外注意SimpleDateFormat除了format是线程不安全以外,parse方法也是线程不安全的。parse方法实际调用alb.establish(calendar).getTime()方法来解析,alb.establish(calendar)方法里主要完成了
 

  • 重置日期对象cal的属性值

  • 使用calb中中属性设置cal

  • 返回设置好的cal对象
     

但是这三步不是原子操作

多线程并发如何保证线程安全 - 避免线程之间共享一个SimpleDateFormat对象,每个线程使用时都创建一次SimpleDateFormat对象 => 创建和销毁对象的开销大 - 对使用format和parse方法的地方进行加锁 => 线程阻塞性能差 - 使用ThreadLocal保证每个线程最多只创建一次SimpleDateFormat对象 => 较好的方法
 

  • Date对时间处理比较麻烦,比如想获取某年、某月、某星期,以及n天以后的时间,如果用Date来处理的话真是太难了,你可能会说Date类不是有getYear、getMonth这些方法吗,获取年月日很Easy,但都被弃用了啊

Come On 一起使用java8全新的日期和时间API


LocalDate

只会获取年月日

  • 创建LocalDate

//获取当前年月日  
LocalDate localDate = LocalDate.now();  
//构造指定的年月日  
LocalDate localDate1 = LocalDate.of(2019, 9, 10);  
  • 获取年、月、日、星期几

int year = localDate.getYear();  
int year1 = localDate.get(ChronoField.YEAR);  
Month month = localDate.getMonth();  
int month1 = localDate.get(ChronoField.MONTH_OF_YEAR);  
int day = localDate.getDayOfMonth();  
int day1 = localDate.get(ChronoField.DAY_OF_MONTH);  
DayOfWeek dayOfWeek = localDate.getDayOfWeek();  
int dayOfWeek1 = localDate.get(ChronoField.DAY_OF_WEEK);  

LocalTime

只会获取几点几分几秒

  • 创建LocalTime

 LocalTime localTime = LocalTime.of(13, 51, 10);  LocalTime localTime1 = LocalTime.now();  
  • 获取时分秒

//获取小时  
int hour = localTime.getHour();  
int hour1 = localTime.get(ChronoField.HOUR_OF_DAY);  
//获取分  
int minute = localTime.getMinute();  
int minute1 = localTime.get(ChronoField.MINUTE_OF_HOUR);  
//获取秒  
int second = localTime.getSecond();  
int second1 = localTime.get(ChronoField.SECOND_OF_MINUTE);  

LocalDateTime

获取年月日时分秒,等于LocalDate+LocalTime

  • 创建LocalDateTime

LocalDateTime localDateTime = LocalDateTime.now();  
LocalDateTime localDateTime1 = LocalDateTime.of(2019, Month.SEPTEMBER, 10, 14, 46, 56);  
LocalDateTime localDateTime2 = LocalDateTime.of(localDate, localTime);  
LocalDateTime localDateTime3 = localDate.atTime(localTime);  
LocalDateTime localDateTime4 = localTime.atDate(localDate);  
  • 获取LocalDate

LocalDate localDate2 = localDateTime.toLocalDate();  
  • 获取LocalTime

LocalTime localTime2 = localDateTime.toLocalTime();  

Instant

获取秒数

  • 创建Instant对象

Instant instant = Instant.now();  
  • 获取秒数

long currentSecond = instant.getEpochSecond();  
  • 获取毫秒数

long currentMilli = instant.toEpochMilli();  

个人觉得如果只是为了获取秒数或者毫秒数,使用System.currentTimeMillis()来得更为方便

修改LocalDate、LocalTime、LocalDateTime、Instant

LocalDate、LocalTime、LocalDateTime、Instant为不可变对象,修改这些对象对象会返回一个副本

  • 增加、减少年数、月数、天数等 以

LocalDateTime  

为例

LocalDateTime localDateTime = LocalDateTime.of(2019, Month.SEPTEMBER, 10,  14, 46, 56);  
//增加一年  
localDateTime = localDateTime.plusYears(1);  
localDateTime = localDateTime.plus(1, ChronoUnit.YEARS);  
//减少一个月  
localDateTime = localDateTime.minusMonths(1);  
localDateTime = localDateTime.minus(1, ChronoUnit.MONTHS);  
  • 通过

with  

修改某些值

//修改年为2019  
localDateTime = localDateTime.withYear(2020);  
//修改为2022  
localDateTime = localDateTime.with(ChronoField.YEAR, 2022);  

还可以修改月、日

时间计算
 

比如有些时候想知道这个月的最后一天是几号、下个周末是几号,通过提供的时间和日期API可以很快得到答案
 

LocalDate localDate = LocalDate.now();  
LocalDate localDate1 = localDate.with(firstDayOfYear());  


比如通过firstDayOfYear()返回了当前日期的第一天日期,还有很多方法这里不在举例说明
 

格式化时间

LocalDate localDate = LocalDate.of(2019, 9, 10);  
String s1 = localDate.format(DateTimeFormatter.BASIC_ISO_DATE);  
String s2 = localDate.format(DateTimeFormatter.ISO_LOCAL_DATE);  
//自定义格式化  
DateTimeFormatter dateTimeFormatter =   DateTimeFormatter.ofPattern("dd/MM/yyyy");  
String s3 = localDate.format(dateTimeFormatter);  

DateTimeFormatter默认提供了多种格式化方式,如果默认提供的不能满足要求,可以通过DateTimeFormatter的ofPattern方法创建自定义格式化方式
 

解析时间

LocalDate localDate1 = LocalDate.parse("20190910", DateTimeFormatter.BASIC_ISO_DATE);  
LocalDate localDate2 = LocalDate.parse("2019-09-10", DateTimeFormatter.ISO_LOCAL_DATE);  

和SimpleDateFormat相比,DateTimeFormatter是线程安全的

小结

LocalDateTimeDate有的我都有,Date没有的我也有,日期选择请Pick Me

SpringBoot中应用LocalDateTime

  • 将LocalDateTime字段以时间戳的方式返回给前端 添加日期转化类

public class LocalDateTimeConverter extends JsonSerializer<LocalDateTime> {  @Override  public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {  gen.writeNumber(value.toInstant(ZoneOffset.of("+8")).toEpochMilli());  }  
}  

并在

LocalDateTime  

字段上添加

@JsonSerialize(using = LocalDateTimeConverter.class)  

注解,如下:

@JsonSerialize(using = LocalDateTimeConverter.class)  
protected LocalDateTime gmtModified;  
  • 将LocalDateTime字段以指定格式化日期的方式返回给前端 在

LocalDateTime  

字段上添加

@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss")  

注解即可,如下:

@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss")  
protected LocalDateTime gmtModified;  
  • 对前端传入的日期进行格式化 在

LocalDateTime  

字段上添加

@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")  

注解即可,如下:

@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")  
protected LocalDateTime gmtModified;  

相关文章:

为什么建议使用你 LocalDateTime ,而不是 Date

为什么建议使用你 LocalDateTime &#xff0c;而不是 Date&#xff1f; 在项目开发过程中经常遇到时间处理&#xff0c;但是你真的用对了吗&#xff0c;理解阿里巴巴开发手册中禁用static修饰SimpleDateFormat吗 通过阅读本篇文章你将了解到&#xff1a; 为什么需要LocalDate…...

【大数据】HADOOP-YARN容量调度器Spark作业实战

目录需求配置多队列的容量调度器验证队列资源需求 default 队列占总内存的40%&#xff0c;最大资源容量占总资源的60% ops 队列占总内存的60%&#xff0c;最大资源容量占总资源的80% 配置多队列的容量调度器 在yarn-site.xml里面配置使用容量调度器 <!-- 使用容量调度器…...

平面及其方程

一、曲面和交线的定义 空间解析几何中&#xff0c;任何曲面或曲线都看作点的几何轨迹。在这样的意义下&#xff0c;如果曲面SSS与三元方程&#xff1a; F(x,y,z)0(1)F(x,y,z)0\tag{1} F(x,y,z)0(1) 有下述关系&#xff1a; 曲面 SSS 上任一点的坐标都满足方程(1)(1)(1)不在曲…...

7 配置的封装

概述 IPC设备通常有三种配置信息:一是默认配置,存储了设备所有配置项的默认值,默认配置是只读的,不能修改;二是用户配置,存储了用户修改过的所有配置项;三是私有配置,存储了程序内部使用的一些配置项,比如:固件升级的URL、固件升级标志位等。恢复出厂设置的操作,实际…...

03_Docker 入门

03_Docker 入门 文章目录03_Docker 入门3.1 确保 Docker 已经就绪3.2 运行我们的第一个容器3.3 使用第一个容器3.4 容器命名3.5 重新启动已经停止的容器3.6 附着到容器上3.7 创建守护式容器3.8 容器内部都在干些什么3.9 Docker 日志驱动3.10 查看容器内的进程3.11 Docker 统计信…...

Python 为什么要 if __name__ == “__main__“:

各位读者&#xff0c;你们知道以下两个Python文件有什么区别吗&#xff1f; main1.py def main():output Helloprint(output)if __name__ "__main__":main()main2.py output Hello print(output)当我们直接运行 main1.py 与 main2.py 的时候&#xff0c;程序都…...

455. 分发饼干、376. 摆动序列、53. 最大子数组和

455.分发饼干 题目描述&#xff1a; 假设你是一位很棒的家长&#xff0c;想要给你的孩子们一些小饼干。但是&#xff0c;每个孩子最多只能给一块饼干。 对每个孩子 i&#xff0c;都有一个胃口值 g[i]&#xff0c;这是能让孩子们满足胃口的饼干的最小尺寸&#xff1b;并且每块…...

基于Springbot+微信小程序的购药平台的设计与实现

基于Springbot微信小程序的购药平台的设计与实现 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、…...

aws lambda rust的sdk和自定义运行时

rust的aws sdk 参考资料 https://docs.aws.amazon.com/sdk-for-rust/latest/dg/getting-started.htmlhttps://awslabs.github.io/aws-sdk-rust/https://github.com/awslabs/aws-sdk-rusthttps://github.com/awsdocs/aws-doc-sdk-examples/tree/main/rust_dev_preview rus sd…...

[安装之3] 笔记本加装固态和内存条教程(超详细)

由于笔记本是几年前买的了&#xff0c;当时是4000&#xff0c;现在用起来感到卡顿&#xff0c;启动、运行速度特别慢&#xff0c;就决定换个固态硬盘&#xff0c;加个内存条&#xff0c;再给笔记本续命几年。先说一下加固态硬盘SSD的好处&#xff1a;1.启动快 2.读取延迟小 3.写…...

极客时间左耳听风-高效学习

左耳听风——高效学习篇 P95 | 高效学习&#xff1a;端正学习态度 本人真实⬇️⬇️⬇️⬇️ “ 大部分人都认为自己爱学习&#xff0c;但是&#xff1a; 他们都是只有意识没有行动&#xff0c;他们是动力不足的人。 他们都不知道自己该学什么&#xff0c;他们缺乏方向和目标。…...

MSR寄存器访问

1.介绍 MSR是CPU的一组64位寄存器&#xff0c;每个MSR都有它的地址值&#xff08;如下图所示&#xff09;&#xff0c;可以分别通过RDMSR 和WRMSR 两条指令进行读和写的操作。 如图中为8个P-state寄存器&#xff0c;地址分别为0xC001 0064 ~ 0xC001 006B&#xff0c;每个寄存…...

ArcGIS:模型构建器实现批量按掩膜提取影像

用研究区域的矢量数据来裁剪栅格数据集时&#xff0c;一般我们使用ArcGIS中的【按掩膜提取工具】。如果需要裁剪的栅格数据太多&#xff0c;处理起来非常的麻烦&#xff0c;虽然ArcGIS中有批处理的功能&#xff0c;但是还是需要手动选择输入输出数据。 如下图&#xff0c;鼠标…...

算法刷题打卡第94天: 找出给定方程的正整数解

找出给定方程的正整数解 难度&#xff1a;中等 给你一个函数 f(x, y) 和一个目标结果 z&#xff0c;函数公式未知&#xff0c;请你计算方程 f(x,y) z 所有可能的正整数 数对 x 和 y。满足条件的结果数对可以按任意顺序返回。 尽管函数的具体式子未知&#xff0c;但它是单调…...

浅析SAS协议(1):基本介绍

文章目录概述SAS协议发展历程SAS技术特性SAS设备拓扑SAS phySAS地址SAS设备类型SAS协议分层参考链接概述 SAS&#xff0c;全称Serial Attached SCSI&#xff0c;即串行连结SCSI&#xff0c;是一种采用了串行总线的高速互连技术。通过物理上使用串行总线连结&#xff0c;在链路…...

93.【Vue-细刷-02】

Vue-02(十六)、基本列表渲染 (v-for)1.使用v-for遍历数组2.使用v-for遍历对象3.使用v-for遍历字符串(十七)、列表过滤 (filter())1.⭐JS中Change属性的原生状态⭐2.使用watch监听实现3.const {xxx} this 在Vue的作用⭐⭐4.JS箭头函数参数的简写⭐5.使用computed进行计算实现(最…...

Allegro负片层不显示反盘的原因和解决办法

Allegro负片层不显示反盘的原因和解决办法 在用Allegro做PCB设计的时候,负片设计是较为常用的一种方式,有时会出现打开负片层却看不到反盘的情况,如下图 L2层是负片层 L2层仍然只能看到盘 如何才能看到反盘显示的效果,具体操作如下 首先确定L2层层叠里面设置的是负片...

ACM数论 裴蜀定理(贝祖定理)

一.内容定义 「裴蜀定理」&#xff0c;又称贝祖定理&#xff08;Bzouts lemma&#xff09;。是一个关于最大公约数的定理。其内容定义为&#xff1a;对于不全为零的任意整数 a 和 b&#xff0c;记二者的最大公约数为 g 即 gcd(a,b) g&#xff0c;则对于任意整数 x 和 y 都一定…...

基础篇—CSS Position(定位)解析

CSS Position(定位) position 属性指定了元素的定位类型。 position 属性的五个值: relativefixedabsolutesticky元素可以使用的顶部,底部,左侧和右侧属性定位。然而,这些属性无法工作,除非是先设定position属性。他们也有不同的工作方式,这取决于定位方法。 1、static…...

正则表达式与grep

基本正则表达式BRE集合 匹配字符匹配次数位置锚定 符号作用^尖角号&#xff0c;用于模式的最正常&#xff0c;如“^haha”&#xff0c;匹配以haha单词开头的行$美元符&#xff0c;用于模式的最右侧&#xff0c;如“haha$”&#xff0c;表示haha单词结尾的行^$组合符&#xff…...

RestClient

什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端&#xff0c;它允许HTTP与Elasticsearch 集群通信&#xff0c;而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级&#xff…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

postgresql|数据库|只读用户的创建和删除(备忘)

CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...

Netty从入门到进阶(二)

二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架&#xff0c;用于…...

CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝

目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为&#xff1a;一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

关于uniapp展示PDF的解决方案

在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项&#xff1a; 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库&#xff1a; npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...

SQL Server 触发器调用存储过程实现发送 HTTP 请求

文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...

Kubernetes 节点自动伸缩(Cluster Autoscaler)原理与实践

在 Kubernetes 集群中&#xff0c;如何在保障应用高可用的同时有效地管理资源&#xff0c;一直是运维人员和开发者关注的重点。随着微服务架构的普及&#xff0c;集群内各个服务的负载波动日趋明显&#xff0c;传统的手动扩缩容方式已无法满足实时性和弹性需求。 Cluster Auto…...