Calendar日期处理
Calendar相比于Date多了可以对时间运算的功能,也可以通过getTime方法把Calendar转化为Date
import java.util.Calendar;
import java.util.Date;
public class TestDate {
public static void main(String[] args) {
// 获取Calendar实例
Calendar cal = Calendar.getInstance();
// 获取年、月、日、时、分、秒
System.out.println(cal.get(Calendar.YEAR));
System.out.println(cal.get(Calendar.MONTH));
System.out.println(cal.get(Calendar.DAY_OF_MONTH));// 一月中的第几天
System.out.println(cal.get(Calendar.HOUR_OF_DAY)); //时间(24小时制)
System.out.println(cal.get(Calendar.MINUTE));
System.out.println(cal.get(Calendar.SECOND));
/**
Calendar.YEAR: 年
Calendar.MONTH: 月(从0开始计算,因此输出显示时候要+1)
Calendar.DAY_OF_YEAR: 一年中的第几天
Calendar.DAY_OF_MONTH: 一月中的第几天
Calendar.DAY_OF_WEEK: 一周中的第几天
Calendar.HOUR: 时间(12小时制)
Calendar.HOUR_OF_DAY: 时间(24小时制)
Calendar.MINUTE: 分钟
Calendar.SECOND: 秒*/
// 把Calendar转化为Date
Date date = cal.getTime();
}
}
Date时间处理
一、新建一个表示"此刻"的日期,打印出来
Date rightNow = new Date();
System.out.println("当前时刻:" + rightNow);
System.out.println("当前年份:" + rightNow.getYear());
System.out.println("当前月份:" + rightNow.getMonth());
//输出结果
当前时刻:Fri Jan 06 11:06:44 GMT+08:00 2023
当前年份:123
当前月份:0
二、构造一个指定年、月、日的时间
Date rightNow = new Date(2023, 1, 1);
连构造函数都被弃用了
你或者想说,可以使用SimpleDateFormat
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/");
LocalDateTime
自 Java8开始, JDK中其实就增加了一系列表示日期和时间的新类,最典型的就是 LocalDateTime。它的出现就是为了替换 JDK版本中的 Date。
一、首先感受一下其用法:
LocalDateTime rightNow = LocalDateTime.now();
System.out.println("当前时刻:" + rightNow);
System.out.println("当前年份:" + rightNow.getYear());
System.out.println("当前月份:" + rightNow.getMonth());
System.out.println("当前日份:" + rightNow.getDayOfMonth());
System.out.println("当前时:" + rightNow.getHour());
System.out.println("当前分:" + rightNow.getMinute());
System.out.println("当前秒:" + rightNow.getSecond());
//输出结果
当前时刻:2023-01-06T11:14:32.180
当前年份:2023
当前月份:JANUARY
当前日份:6
当前时:11
当前分:14
当前秒:32
二、构造一个指定年、月、日的时间:
LocalDateTime before = LocalDateTime.of(2020, 12, 1, 0, 0, 0);
//结果
2020-12-01T00:00
三、修改日期
LocalDateTime now = LocalDateTime.now();
// 减少三个月
LocalDateTime minusMonths = now.minusMonths(3);
//增加三个月
LocalDateTime plusMonths = now.plusMonths(3);
// 修改年份到2030
LocalDateTime withYear = now.withYear(2030);
// 修改小时到20:00
LocalDateTime withHour = now.withHour(20);
四、格式化日期
LocalDateTime rightNow = LocalDateTime.now();
String result1 = rightNow.format(DateTimeFormatter.ISO_DATE);
String result2 = rightNow.format(DateTimeFormatter.BASIC_ISO_DATE);
String result3 = rightNow.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
System.out.println("格式化后的日期(基本样式一举例):" + result1);
System.out.println("格式化后的日期(基本样式二举例): " + result2);
System.out.println("格式化后的日期(自定义样式举例):" + result3);
//输出结果
格式化后的日期(基本样式一举例):2023-01-06
格式化后的日期(基本样式二举例): 20230106
格式化后的日期(自定义样式举例):2023/01/06
五、时间反解析
给你一个陌生的字符串,你可以按照你需要的格式把时间给反解出来
LocalDateTime time = LocalDateTime.parse("2022--01--01 11:21", DateTimeFormatter.ofPattern("yyyy--MM--dd HH:mm"));
System.out.println("字符串反解析后的时间为:" + time);
//输出结果
字符串反解析后的时间为:2022-01-01T11:21
六、获取毫秒数
//获取秒数
Long second = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
//获取毫秒数
Long milliSecond = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
七、LocalDateTime与String互转
//时间转字符串格式化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
String dateTime = LocalDateTime.now(ZoneOffset.of("+8")).format(formatter);
//字符串转时间
String dateTimeStr = "2018-07-28 14:11:15";
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime dateTime = LocalDateTime.parse(dateTimeStr, df);
零零散散举了这么些例子,我想 LocalDateTime怎么地也不输 Date吧!
Date与LocalDate、LocalDateTime的区别
-
Date 类:
- java.util.Date 是 Java 早期提供的日期和时间类,从 JDK 1.0 就存在。它同时包含日期和时间信息,使用一个长整型数值表示自 1970 年 1 月 1 日 00:00:00 GMT(格林尼治标准时间)起至今的毫秒数。Date 类存在一些问题,例如它不是线程安全的,而且设计上有些缺陷,因此在 Java 8 后推荐使用新的日期时间类。
-
LocalDate 类:
- java.time.LocalDate 是 Java 8 引入的日期类,用于表示日期(年、月、日),不包含时间信息。它提供了丰富的方法来操作日期,例如获取年、月、日,进行日期比较和计算等。LocalDate 是不可变的(immutable),类似于 String,操作 LocalDate 时不会修改原始对象,而是返回一个新的对象。
-
LocalDateTime 类:
- java.time.LocalDateTime 是 Java 8 引入的日期时间类,用于表示日期和时间,但不包含时区信息。它与 LocalDate 类似,但额外包含了时间部分(时、分、秒、毫秒)。LocalDateTime 也是不可变的,可以进行日期时间的各种操作,如格式化、加减时间等。
- 主要区别
-
精度与范围
- Date:存储的是自Unix纪元以来的毫秒数,因此它的精度是到毫秒级别。
- LocalDate:只表示日期,没有时间信息,精度到天。
- LocalDateTime:同时表示日期和时间,精度同样是到纳秒级别。
-
时区
- Date:虽然实际存储的是UTC时间戳,但是由于其设计原因,在显示和解析时可能会受到默认时区的影响。
- LocalDate和LocalDateTime:都不包含时区信息,代表的是本地日期和时间。
-
可变性
- Date:是可变的,可以通过方法修改其内部值。
- LocalDate和LocalDateTime:都是不可变的,每次更改都会返回一个新的实例。
-
易用性与安全性
- Date:使用起来较为繁琐,且容易出现并发问题,因为很多操作不是线程安全的。
- LocalDate和LocalDateTime:具有更好的API设计,易于理解和使用,同时由于不可变性,更有利于编写线程安全的代码。
线程安全性问题
其实上面讲来讲去只讲了两者在用法上的差别,这其实倒还好,并不致命,可是接下来要讨论的线程安全性问题才是致命的!
其实以前我们惯用的 Date时间类是可变类,这就意味着在多线程环境下对共享 Date变量进行操作时,必须由程序员自己来保证线程安全!否则极有可能翻车。
而自 Java8开始推出的 LocalDateTime却是线程安全的,开发人员不用再考虑并发问题,这点我们从 LocalDateTime的官方源码中即可看出:
/**
*
* @implSpec
* This class is immutable and thread-safe. //这个类是线程安全的
*
* @since 1.8
*/
public final class LocalDateTime
implements Temporal, TemporalAdjuster, ChronoLocalDateTime<LocalDate>, Serializable {
...
}
日期格式化的选择
大家除了惯用 Date来表示时间之外,还有一个用于和 Date连用的 SimpleDateFormat 时间格式化类大家可能也戒不掉了!
SimpleDateFormat最主要的致命问题也是在于它本身并不线程安全,这在它的源码注释里已然告知过了:
/*
* Date formats are not synchronized. //日期格式不同步。
* It is recommended to create separate format instances for each thread.
* If multiple threads access a format concurrently, it must be synchronized
* externally.
*
* @see java.util.Calendar
* @see java.util.TimeZone
* @see DateFormat
* @see DateFormatSymbols
* @author Mark Davis, Chen-Lieh Huang, Alan Liu
*/
public class SimpleDateFormat extends DateFormat {
...
}
那取而代之,我们现在改用什么呢?其实在前文已经用到啦,那就是了 DateTimeFormatter了,他也是线程安全的:
/*
* @implSpec
* This class is immutable and thread-safe. //这个类是线程安全的
*
* @since 1.8
*/
public final class DateTimeFormatter {
...
}
小结
Date或者 SimpleDateFormat是老版日期时间类,Java8提供了新版的Ap-iLocalDateTime它的出现就是为了替换 JDK版本中的 Date。在Java 8及之后的版本中,推荐尽量使用java.time.LocalDateTime来处理日期和时间,避免使用过时的java.util.Date类。如果在不同的API之间频繁进行转换,可以借助Java 8提供的日期时间API,使得操作更加直观和简洁。
java属性类型对应关系:
属性类型 -- Api
Date -- new Date();
DateTime -- LocalDateTime
两者之间的转换关系:
将 java.util.Date 转换为 java.time.LocalDateTime:
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
public class Main {
public static void main(String[] args) {
// 创建一个 java.util.Date 对象
Date utilDate = new Date();
// 将 java.util.Date 转换为 java.time.LocalDateTime
LocalDateTime localDateTime = utilDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
System.out.println("java.util.Date: " + utilDate);
System.out.println("java.time.LocalDateTime: " + localDateTime);
}
}
将 java.time.LocalDateTime 转换为 java.util.Date:
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
public class Main {
public static void main(String[] args) {
// 创建一个 java.time.LocalDateTime 对象
LocalDateTime localDateTime = LocalDateTime.now();
// 将 java.time.LocalDateTime 转换为 java.util.Date
Date utilDate = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
System.out.println("java.time.LocalDateTime: " + localDateTime);
System.out.println("java.util.Date: " + utilDate);
}
}
在上面的代码示例中,我们使用了Date.from()方法将java.time.LocalDateTime转换为java.util.Date,以及使用java.util.Date的toInstant()方法将其转换为java.time.LocalDateTime。需要注意的是,在这些转换过程中,时区的信息也被考虑进去了。