JAVA-LocalDateTime时间格式化,转换时间戳和源码分析
LocalDateTime
LocalDateTime作为java8新加的时间类型,也是后面开发中常用的时间类型。
作为时间类型,最关注的点无非是这几个
- 获取当前时间
- 获取指定时间
- 时间格式化
- 时间转时间戳
- 时间戳转时间
- 时间比较
- 时间加减
这些点通过LocalDateTime来操作,都会比较简单
获取当前时间
只需要now一下就可以获取到当前的时间,还是很方便的。
LocalDateTime time = LocalDateTime.now();
再看一下之前的Date类
Date date = new Date();
获取指定时间
这个有比较多的方式
- 通过原来的
date和dateTime类型来生成 - 通过传年月日时分秒生成
LocalDateTime time = LocalDateTime.of(2022,11,30,6,6,6);
原来Date类的方式。比较奇怪,他的年份会+1900,所以2022年就得是122,月份也会+1,所以11月就是10.但是这个方法呢后面会被删除,已经被标记为弃用了,使用Calendar代替。
Date date = new Date(122,10,30,6,6,6);
看一下Calendar的使用。这个年份就正常了,是2022,但是月份还是会+1.
Calendar calendar = Calendar.getInstance();
calendar.set(2022,10,30,6,6,6);
时间格式化
时间格式化都是通过format函数,需要传一个DateTimeFormatter对象进去,我们可以通过DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")来生成自己想要的格式。
DateTimeFormatter类里面也有一些定义好的格式可以直接用,除了下面列出的还有一些其他的,感兴趣可以看一下,不过我觉得都没啥用。
- ISO_DATE_TIME 2011-12-03T10:15:30
- ISO_OFFSET_DATE_TIME 2011-12-03T10:15:30+01:00
- ISO_LOCAL_DATE_TIME 2011-12-03T10:15:30
time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
看一下Date的格式化。这个需要借用SimpleDateFormat类来完成格式化。
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
format.format(date);
时间转时间戳
时间转时间戳分为两种,一种是当你已经有一个LocalDateTime类型的时间了,需要转换成秒或者毫秒的时间戳。
时间转换秒级时间戳
只需要直接用toEpochSecond方法就可以了。
LocalDateTime time = LocalDateTime.now();
time.toEpochSecond(ZoneOffset.ofHours(8));
Date类型没有办法直接获取秒级时间戳,只能获取毫秒级再转秒。
时间转换毫秒级时间戳
转换毫秒需要先转换成instant对象,然后才能转换成毫秒级时间戳。
LocalDateTime time = LocalDateTime.now();
time.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
Date获取毫秒就很简单了。
Date date = new Date();
date.getTime();
字符串转换成时间戳
时间转时间戳分为两种,除了上面的,还有一种是有一个格式化好的字符串,比如2022-12-18 10:00:00这种,但是这个是字符串并不是时间类型。所以要先转换成LocalDateTime类型,然后就可以转换成时间戳了。
其实就是上面格式化的一种反向操作。使用parse方法就可以了。
LocalDateTime.parse("2022-12-18 10:00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
LocalDateTime.parse("2022-12-18", DateTimeFormatter.ofPattern("yyyy-MM-dd"));
Date类型的字符串转时间戳也是通过SimpleDateFormat类来完成。
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = format.parse("2022-12-18 10:00:00")
时间戳转时间
那如果我们现在转换成时间戳以后又想转换成时间呢?也可以通过instant对象来做到。
毫秒时间戳转时间
Instant.ofEpochMilli(1671365543834)是将一个毫秒时间戳转换成instant对象。在通过ofInstant方法就可以将instant对象转换成LocalDateTime对象了。
LocalDateTime.ofInstant(Instant.ofEpochMilli(1671365543834), ZoneOffset.ofHours(8));
Date类
Date date = new Date(1669759566000L);
秒时间戳转时间
Instant.ofEpochSecond(1671365543)是将一个秒时间戳转换成一个instant对象。在通过ofInstant方法就可以将instant对象转换成LocalDateTime对象了。
LocalDateTime.ofInstant(Instant.ofEpochSecond(1671365543), ZoneOffset.ofHours(8));
Date类不支持秒,只能把秒转成毫秒在转时间戳。
时间比较
通过compareTo方法可以进行时间的一个比较大小。如果大于会返回1,小于返回-1.
LocalDateTime time = LocalDateTime.now();
time.compareTo(LocalDateTime.now());
Date也是通过compareTo方法进行比较
Date date = new Date(1669759566000L);
date.compareTo(new Date());
时间加减
如果加上几天,就是plusDays。加几个小时就是plusHours。当然也可以使用plus。
LocalDateTime time = LocalDateTime.now();
time.plusDays(1);
time.plusHours(1);
time.plus(Period.ofDays(1));
如果减去几天就是minusDays.减去几个小时就是minusHours。当然也可以使用minus。
LocalDateTime time = LocalDateTime.now();
time.minusDays(1);
time.minusHours(1);
time.minus(Period.ofDays(1));
Date类不支持时间加减,只能通过Calendar类实现。
Date date = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.DAY_OF_MONTH, 1);
//减去
calendar.add(Calendar.DAY_OF_MONTH, -1);
时间格式在入参出参中的使用
入参的时候需要通过JsonFormat注解来指定需要的是字符串类型和对应的时间格式。
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern="yyyy-MM-dd")
private LocalDate date;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss")
private LocalDateTime time;
出参的时候就很简单了,因为只是返回了一个字符串。
private String time;
格式化时间源码分析
格式化的时候这两个年是不一样的,具体的可以看一下源码。我们来找一下。
首先点进去是LocalDateTime这个类里面
@Override // override for Javadoc and performance
public String format(DateTimeFormatter formatter) {
//判断参数是否空
Objects.requireNonNull(formatter, "formatter");
//真正的执行格式化
return formatter.format(this);
}
接下来点进去,看一下怎么执行的,可以看到又调用了formatTo这个函数,说明主要的格式化代码都在这里面。
public String format(TemporalAccessor temporal) {
//创建了一个32长度的字符串构建器
StringBuilder buf = new StringBuilder(32);
//格式化主要代码
formatTo(temporal, buf);
//转成字符串
return buf.toString();
}
看一下formatTo函数,可以发现主要是调用printerParser这个对象的format方法,那我们这个对象是哪来的呢,是在一开始指定格式化类型的时候来的。不同的格式化类型对应不同的解析器,也就会执行不同的format方法。
public void formatTo(TemporalAccessor temporal, Appendable appendable) {
//判断参数,这里不用管
Objects.requireNonNull(temporal, "temporal");
Objects.requireNonNull(appendable, "appendable");
try {
//创建一个DateTimePrintContext对象
DateTimePrintContext context = new DateTimePrintContext(temporal, this);
//判断,显然我们之前传过来的就是一个StringBuilder
if (appendable instanceof StringBuilder) {
//主要看这个怎么处理 这里有个 printerParser 对象,这个对象是怎么来的呢,其实是上面DateTimeFormatter.ofPattern的时候给创建的。
printerParser.format(context, (StringBuilder) appendable);
} else {
//这里其实就是如果传的不是个StringBuilder,就在创建一个然后执行
// buffer output to avoid writing to appendable in case of error
StringBuilder buf = new StringBuilder(32);
printerParser.format(context, buf);
appendable.append(buf);
}
} catch (IOException ex) {
throw new DateTimeException(ex.getMessage(), ex);
}
}
接下来我们看一下ofPattern这个方法里面是怎样的吧。这里是创建了一个 时间格式化的建造者,然后把我们这个字符串添加进去了。
//这里的字符串就是我们传的 yyyy-MM-dd HH:mm:ss
public static DateTimeFormatter ofPattern(String pattern) {
return new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter();
}
看一下appendPattern里面是怎么把字符串加进去的。
public DateTimeFormatterBuilder appendPattern(String pattern) {
//忽略
Objects.requireNonNull(pattern, "pattern");
//主要的解析逻辑
parsePattern(pattern);
return this;
}
继续追踪到parsePattern方法里面。这个方法代码比较多,这里只关注我们想知道的。其余的有兴趣的可以看一下。
private void parsePattern(String pattern) {
//这里给字符串做循环,注意 pattern = yyyy-MM-dd HH:mm:ss 这个字符串。
for (int pos = 0; pos < pattern.length(); pos++) {
//取出字符 比如第一个就是 y 对应的ASCII码就是121
char cur = pattern.charAt(pos);
//这里就是判断是否是大小写字母了,也就是A-Z或者a-z
if ((cur >= 'A' && cur <= 'Z'

本文详细介绍了Java 8中新引入的时间类型LocalDateTime的使用方法,包括时间的获取、格式化、转换等,并深入分析了时间格式化的源码实现。
&spm=1001.2101.3001.5002&articleId=128140264&d=1&t=3&u=c96b09560f8f4966a7662b6db87036c7)
3252

被折叠的 条评论
为什么被折叠?



