在 Java 8 中 推出了LocalDate、LocalTime、LocalDateTime这个三个时间处理类,以此来弥补之前的日期时间类的不足,简化日期时间的操作。
Java8
日期和时间类包含LocalDate、LocalTime、Instant、Duration以及Period,这些类都包含在java.time包中
在Java8之前,处理日期时间的类是Date、Calendar 。
- java.util.Date和java.util.Calendar类易用性差,不支持时区,而且他们都不是线程安全的;
- 用于格式化日期的类DateFormat被放在java.text包中,它是一个抽象类,所以我们需要实例化一个SimpleDateFormat对象来处理日期格式化,并且DateFormat也是非线程安全,这意味着如果你在多线程程序中调用同一个DateFormat对象,会得到意想不到的结果。
- 对日期的计算方式繁琐,而且容易出错,因为月份是从0开始的,从Calendar中获取的月份需要加一才能表示当前月份。
目前在西瓜视频上免费刊登 Flutter 系列教程,每日更新,欢迎关注接收提醒
【x1】点击查看提示
【x2】各种系列的教程
1 Java8 获取当前的时间数据
LocalDate、LocalDateTime 的now()方法使用的是系统默认时区.
@SpringBootTest
class DemoDateTests {
//日志
private static final Logger LOG = LoggerFactory.getLogger(DemoDateTests.class);
@Test
void test() {
//只获取当前时区的日期
LocalDate localDate = LocalDate.now();
LOG.info("localDate: " + localDate);
//localDate: 2020-09-23
//只获取当前时间
LocalTime localTime = LocalTime.now();
LOG.info("localTime: " + localTime);
//localTime: 23:41:43.991
//获取不前的日期与时间
LocalDateTime localDateTime2 = LocalDateTime.now();
LOG.info("localDateTime2: " + localDateTime2);
//localDateTime2: 2020-09-23T23:41:43.991
}
}
在这里获取到的时间 2020-09-23T23:41:43.991 中间携带一个T指的是UTC时间。
UTC时间,是指零时区的时间,它的全称是Coordinated Universal Time ,即世界协调时间。
另一个常见的缩写是GMT,即格林威治标准时间,格林威治位于 零时区,因此,我们平时说的UTC时间和GMT时间在数值上面都是一样的。
1884 年, 国际经度会议将地球表面按经线等分为24 区,称为时区。即以本初子午线为基准, 东西经度各7.5 度的范围作为零时区,
然后每隔15度为一时区,每个时区相差一小时,北京时区为东八区。
比如:北京时间 2020-09-23 12:00:00 那么 utc 时间就是 2020-09-23 04:00:00;
当然获取到的时间格式可能不是我们想要的,可以结合 DateTimeFormatter来对其进行格式化操作如下:
@Test
void test1() {
//使用静态方法生成此对象
LocalDateTime localDateTime = LocalDateTime.now();
LOG.info("localDateTime: " + localDateTime);
///localDateTime: 2020-09-23T23:47:41.752
//格式化时间
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss");
//格式化后的时间
String formatDate = localDateTime.format(formatter);
LOG.info("格式化之后的时间: " + formatDate);
//格式化之后的时间: 2020-09-23 23:47:41
}
1.1 LocalDate
LocalDate类表示一个具体的日期,但不包含具体时间,也不包含时区信息。可以通过LocalDate的静态方法of()创建一个实例,LocalDate也包含一些方法用来获取年份,月份,天,星期几等。
@Test
void test3() {
//当然你也可以使用当前的时间
//LocalDate localDate = LocalDate.now();
// 初始化一个日期:2020-09-24
LocalDate localDate = LocalDate.of(2020, 9, 24);
int year = localDate.getYear(); // 年份:2020
Month month = localDate.getMonth(); // 月份:SEPTEMBER
int dayOfMonth = localDate.getDayOfMonth(); // 月份中的第几天:24
DayOfWeek dayOfWeek = localDate.getDayOfWeek(); // 一周的第几天:THURSDAY
int length = localDate.lengthOfMonth(); // 月份的天数:30
boolean leapYear = localDate.isLeapYear(); // 是否为闰年:true
}
断点单元测试运行如下
1.2 LocalTime
LocalTime 与 LocalDate 类似,区别在于 LocalDate 不包含具体时间,而 LocalTime 包含具体时间
@Test
void test4() {
//当前的时间
LocalTime localTime = LocalTime.now();
int hour = localTime.getHour(); // 时:07
int minute = localTime.getMinute(); // 分:22
int second = localTime.getSecond(); // 秒:20
}
断点单元测试运行如下
1.3 LocalDateTime
LocalDateTime 类是 LocalDate 和 LocalTime 的结合体,可以通过of()方法直接创建,也可以调用 LocalDate 的 atTime() 方法或 LocalTime 的 atDate() 方法将 LocalDate 或 LocalTime 合并成一个LocalDateTime.
@Test
void test5() {
///通过 of 方法创建 LocalDateTime
LocalDateTime localDateTime = LocalDateTime.of(
2020,//年
Month.JANUARY,//月
4, //日
//时 分 秒
17, 23, 52);
}
可以这样理解 LocalDate 与 LocalTime 向 LocalDateTime 转化,就是将两者合并的过程,如下所示:
@Test
void test6() {
//通过of方法来创建 LocalDate
//参数为年 月 日
LocalDate localDate = LocalDate.of(2020, Month.JANUARY, 4);
//通过of方法来创建 LocalTime
//参数为 时分秒
LocalTime localTime = LocalTime.of(07, 23, 52);
// LocalDate 转 LocalDateTime
LocalDateTime localDateTime = localDate.atTime(localTime);
// LocalTime 转 LocalDateTime
LocalDateTime localDateTime1 = localTime.atDate(localDate);
}
断点单元测试运行如下
当然也可以反过来 LocalDateTime 转为 LocalDate 或者 LocalTime,如下所示:
LocalDate date = localDateTime.toLocalDate();
LocalTime time = localDateTime.toLocalTime();
2 LocalDateTime 与毫秒之间的妙操作
时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数
ZoneId 指地区
ZoneOffset指偏移数据
@Test
void test2() {
//使用静态方法生成此对象
LocalDateTime localDateTime = LocalDateTime.now();
LOG.info("localDateTime: " + localDateTime);
///localDateTime: 2020-09-23T23:49:11.832
//转化为时间戳(秒)
long epochSecond = localDateTime.toEpochSecond(ZoneOffset.of("+8"));
//转化为毫秒
long epochMilli = localDateTime.atZone(ZoneOffset.systemDefault()).toInstant().toEpochMilli();
LOG.info("时间戳为:(秒) " + epochSecond + "; (毫秒): " + epochMilli);
///时间戳为:(秒) 1600876151; (毫秒): 1600876151832
//时间戳(毫秒)转化成LocalDateTime
Instant instant = Instant.ofEpochMilli(epochMilli);
LocalDateTime localDateTime3 = LocalDateTime.ofInstant(instant, ZoneOffset.systemDefault());
//时间戳(秒)转化成LocalDateTime
Instant instant2 = Instant.ofEpochSecond(epochSecond);
LocalDateTime localDateTime4 = LocalDateTime.ofInstant(instant2, ZoneOffset.systemDefault());
}
3 LocalDateTime 与 Date 的妙操作
Instant 类代表的是某个时间,是精确到纳秒的,与我们常使用的System.currentTimeMillis()有些类似,不过Instant可以精确到纳秒(Nano-Second),System.currentTimeMillis()方法只精确到毫秒(Milli-Second)。
如果使用纳秒去表示一个时间则原来使用一位Long类型是不够的,需要占用更多一点的存储空间,实际上其内部是由两个Long字段组成。
需要注意的是 但Instant 代表的是一个时间,并不包括时区的概念。
// Date 转化成 LocalDateTime
public static LocalDateTime dateToLocalDate(Date date) {
//Date转纳秒
Instant instant = date.toInstant();
//获取系统默认的时区
ZoneId zoneId = ZoneId.systemDefault();
//转化
return instant.atZone(zoneId).toLocalDateTime();
}
// LocalDateTime 转化成 Date
public static Date localDateTimeToDate(LocalDateTime localDateTime) {
ZoneId zoneId = ZoneId.systemDefault();
ZonedDateTime zdt = localDateTime.atZone(zoneId);
return Date.from(zdt.toInstant());
}
// Date 毫秒数据 转化成 LocalDateTime
public static LocalDateTime dateToLocalDateMil(Long datemilli) {
//将毫秒数据转化为纳秒
Instant instant = Instant.ofEpochMilli(datemilli);
ZoneId zoneId = ZoneId.systemDefault();
return instant.atZone(zoneId).toLocalDateTime();
}
当然 Instant 也有很多妙操作
Instant 它的内部使用了两个常量,seconds表示从 1970-01-01 00:00:00 开始到现在的秒数,nanos 表示纳秒部分(nanos的值不会超过999,999,999)
Instant除了使用now()方法创建外,还可以通过ofEpochSecond方法创建:
@Test
void test7() {
//参数一为秒,参数二为纳秒,
//这里的代码表示从1970-01-01 00:00:00开始后三分钟的10万纳秒的时刻
Instant instant = Instant.ofEpochSecond(180, 100000);
LOG.info("时间为:" + instant );
}
断点单元测试运行如下
4 Duration 类
在上述的操作中没有提到这个类,Duration的内部实现与Instant类似,也是包含两部分:seconds表示秒,nanos表示纳秒。两者的区别是Instant用于表示一个时间戳(或者说是一个时间点),而Duration表示一个时间段,所以Duration类中不包含now()静态方法。可以通过Duration.between()方法创建Duration对象。
@Test
void test8() {
///开始时间
LocalDateTime from = LocalDateTime.of(2020, Month.JANUARY, 9, 10, 7, 0); // 2017-01-05 10:07:00
//结束时间
LocalDateTime to = LocalDateTime.of(2020, Month.FEBRUARY, 10, 10, 7, 0);
// 表示从 2020-09-05 10:07:00 到 2020-09-05 10:07:00 这段时间
Duration duration = Duration.between(from, to);
long days = duration.toDays(); // 这段时间的总天数
long hours = duration.toHours(); // 这段时间的小时数
long minutes = duration.toMinutes(); // 这段时间的分钟数
long seconds = duration.getSeconds(); // 这段时间的秒数
long milliSeconds = duration.toMillis(); // 这段时间的毫秒数
long nanoSeconds = duration.toNanos(); // 这段时间的纳秒数
LOG.info("时间为:" + duration );
}
断点单元测试运行如下
5 Period 类
Period在概念上与Duration类似,区别在于Period是以年月日来衡量一个时间段,比如1年3个月6天(代码清单 5-1)。
Period对象可以通过构造方法与between()方法创建,值得注意的是,由于Period是以年月日衡量时间段,所以between()方法只能接收LocalDate类型的参数。
//代码清单 5-1
@Test
void test9() {
//1年3个月6天
Period period = Period.of(1, 3, 6);
// 2017-01-05 到 2017-02-05 这段时间
Period period2 = Period.between(
LocalDate.of(2020, 1, 5),
LocalDate.of(2020, 2, 5));
LOG.info("时间为:" + period );
}
断点单元测试运行如下
6 指定日期的前后时间妙操作
//代码清单 6-1
@Test
void test10() {
//使用当前的时间
LocalDate localDate = LocalDate.now();
LocalDate date4 = localDate.plusYears(1); // 增加一年 2021-09-24
LocalDate date5 = localDate.minusMonths(2); // 减少两个月 2021-07-24
LocalDate date6 = localDate.plus(5, ChronoUnit.DAYS); // 增加5天 2021-09-29
LOG.info("时间为:" + date6 );
}
断点单元测试运行如下
7 格式化日期
新的日期API中提供了一个 DateTimeFormatter 类(在上述也有使用到)用于处理日期格式化操作,它被包含在java.time.format包中,Java 8的日期类有一个format()方法用于将日期格式化为字符串,该方法接收处理一个DateTimeFormatter类型参数
//代码清单 7-1
@Test
void test11() {
//使用当前的时间
LocalDateTime dateTime = LocalDateTime.now();
String strDate1 = dateTime.format(DateTimeFormatter.BASIC_ISO_DATE); // 20200924
String strDate2 = dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE); // 2020-09-24
String strDate3 = dateTime.format(DateTimeFormatter.ISO_LOCAL_TIME); // 08:23:31.463
String strDate4 = dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); // 2020-09-24
LOG.info("时间为:" + dateTime );
}
断点单元测试运行如下
将现有的日期字符串解析为 LocalDateTime 、LocalDate、LocalTime 如下代码清单7-2所示。
解析的核心思路为 先定义 格式映射 DateTimeFormatter,然后再调用对应的parse方法
//代码清单 7-2
@Test
void test12() {
String strDate = "2020-09-24";
String strDate2 = "2020-09-24 08:23:31";
LocalDate date = LocalDate.parse(strDate, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
LocalTime time = LocalTime.parse(strDate, DateTimeFormatter.ofPattern(" HH:mm:ss"));
//定义 formatter
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//解析操作
LocalDateTime dateTime = LocalDateTime.parse(strDate2, dateTimeFormatter);
LOG.info("时间为:" + dateTime );
}
断点单元测试运行如下
当然也有公众号了,感兴的伙伴可以关注关注