日期和时间的格式化编码
字母 | 描述 | 示例 |
---|---|---|
G | 纪元标记 | AD |
y | 四位年份 | 2001 |
M | 月份 | July or 07 |
d | 一个月的日期 | 10 |
h | A.M./P.M. (1~12)格式小时 | 12 |
H | 一天中的小时 (0~23) | 22 |
m | 分钟数 | 30 |
s | 秒数 | 55 |
S | 毫秒数 | 234 |
E | 星期几 | Tuesday |
D | 一年中的日子 | 360 |
F | 一个月中第几周的周几 | 2 (second Wed. in July) |
w | 一年中第几周 | 40 |
W | 一个月中第几周 | 1 |
a | A.M./P.M. 标记 | PM |
k | 一天中的小时(1~24) | 24 |
K | A.M./P.M. (0~11)格式小时 | 10 |
z | 时区 | Eastern Standard Time |
' | 文字定界符 | Delimiter |
" | 单引号 | ` |
Date
java.util 包提供了 Date 类来封装当前的日期和时间。
获取时间
Date类提供了两个构造方法,无参构造方法返回当前时间,有参构造方法需要提供一个参数,该参数是从1970年1月1日返回的毫秒值。
// 无参构造方法
// 返回当前时间 CST格式
Date date1 = new Date();
System.out.println(date1); // Fri Dec 22 10:24:12 CST 2023
Thread.sleep(1000);
Date date2 = new Date();
System.out.println(date2); // Fri Dec 22 10:24:12 CST 2023
// 返回自1970年1月1日经历的毫秒数
long currentTimeMillis = System.currentTimeMillis();
System.out.println(currentTimeMillis); // 1703211853991
// 有参构造方法
Date date = new Date(currentTimeMillis);
System.out.println(date); // Fri Dec 22 10:29:19 CST 2023
日期比较
Date类提供了compareTo、equals、before、after方法用来进行日期的比较。
// 比较两个日期
int i = date1.compareTo(date2);
System.out.println(i); // -1
boolean before = date1.before(date2);
System.out.println(before); // true
boolean after = date1.after(date2);
System.out.println(after); // false
boolean equals = date1.equals(date2);
System.out.println(equals); // false
格式化日期
使用SimpleDateFormat进行日期的格式化,可以把Date类型的日期转换为指定格式的String类型。
// 使用SimpleDateFormat格式化日期
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
String format1 = format.format(date1);
System.out.println(format1); // 2023-12-22
String dateString = "2023-12-23";
Date date3 = format.parse(dateString);
System.out.println(date3); // Sat Dec 23 00:00:00 CST 2023
format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format2 = format.format(date2);
System.out.println(format2); // 2023-12-22 10:29:19
dateString = "2023-12-23 10:24:56";
Date date4 = format.parse(dateString);
System.out.println(date4); // Sat Dec 23 10:24:56 CST 2023
获取当前日期的信息
int year = date1.getYear(); // 123 年
int month = date1.getMonth(); // 11 月
int datee = date1.getDate(); // 22 日
int hours = date1.getHours(); // 10 时
int minutes = date1.getMinutes(); // 29 分
int seconds = date1.getSeconds(); // 19 秒
int day = date1.getDay(); // 5 星期
Date类提供了一系列的get方法,方便我们获取信息,但是年、月怎么都不对,在源码中,getYear()方法 减去了1900,getMonth() 也是如此,返回了一个0-11的值,同时注释也提示建议使用Calendar类中相关方法,说明该方法已经过期了。
/**
* Returns a value that is the result of subtracting 1900 from the
* year that contains or begins with the instant in time represented
* by this <code>Date</code> object, as interpreted in the local
* time zone.
*
* @return the year represented by this date, minus 1900.
* @see java.util.Calendar
* @deprecated As of JDK version 1.1,
* replaced by <code>Calendar.get(Calendar.YEAR) - 1900</code>.
*/
@Deprecated
public int getYear() {
return normalize().getYear() - 1900;
}
Calendar
Calendar类是 java.util 包中的一个抽象类,用于对日期和时间进行操作和格式化。它是Java中的日历类,可以用来获取和设置日期和时间的各个部分,以及执行一些常见的日期和时间操作,如计算两个日期之间的差值、比较日期的大小等。
Calendar类对象字段类型
常量 | 描述 |
---|---|
Calendar.YEAR | 年份 |
Calendar.MONTH | 月份 |
Calendar.DATE | 日期 |
Calendar.DAY_OF_MONTH | 日期,和上面的字段意义完全相同 |
Calendar.HOUR | 12小时制的小时 |
Calendar.HOUR_OF_DAY | 24小时制的小时 |
Calendar.MINUTE | 分钟 |
Calendar.SECOND | 秒 |
Calendar.DAY_OF_WEEK | 星期几 |
获取时间
通过调用 getInstance() 方法来获取默认时区和区域设置的 Calendar 对象,调用getTime() 就能获取当前时间。
Calendar calendar = Calendar.getInstance();
Date now = calendar.getTime();
System.out.println(now); // Fri Dec 22 10:57:31 CST 2023
获取当前日期的信息
通过调用 get() 提供上面表格中的常量作为参数,就能获取对应信息。
int year = calendar.get(Calendar.YEAR); // 2023 年
int month = calendar.get(Calendar.MONTH) + 1; // 12 月
int date = calendar.get(Calendar.DATE); // 22 日
int hour = calendar.get(Calendar.HOUR_OF_DAY); // 10 时
int minute = calendar.get(Calendar.MINUTE); // 57 分
int second = calendar.get(Calendar.SECOND); // 31 秒
int day = calendar.get(Calendar.DAY_OF_WEEK); // 6 星期 这个与Date类是不同的:1代表星期日、2代表星期1、3代表星期二,以此类推。
设置指定日期
set
调用 set(int field,int value) 利用字段类型设置指定时间。
// 设置指定日期
calendar.set(Calendar.YEAR, 2023);
calendar.set(Calendar.MONTH, Calendar.DECEMBER);
calendar.set(Calendar.DAY_OF_MONTH, 23);
calendar.set(Calendar.HOUR_OF_DAY, 11);
calendar.set(Calendar.MINUTE, 8);
calendar.set(Calendar.SECOND, 45);
Date date1 = calendar.getTime();
System.out.println(date1); // Sat Dec 23 11:08:45 CST 2023
这里的月份可以使用Calendar提供的的常量,也是可以使用 0-11,月份从0开始。
add
调用 add(int field,int value),用于将当前日期加上指定日期。
// 加上指定日期
calendar.add(Calendar.MONTH,-1);
calendar.add(Calendar.DATE,5);
Date date2 = calendar.getTime();
System.out.println(date2); // Tue Nov 28 11:08:45 CST 2023
获取月的第一天和最后一天
Calendar calendar = Calendar.getInstance();
// 获取当前时间
Date now = calendar.getTime();
System.out.println(now); // Fri Dec 22 11:29:34 CST 2023
// 设置当月的第一天
calendar.set(Calendar.DAY_OF_MONTH,1);
Date firstDay = calendar.getTime();
System.out.println(firstDay); // Fri Dec 01 11:29:34 CST 2023
// 设置月份为下个月 当前时间为下个月第一天
calendar.add(Calendar.MONTH,1);
// 天数-1
calendar.add(Calendar.DATE,-1);
Date lastDay = calendar.getTime();
System.out.println(lastDay); // Sun Dec 31 11:29:34 CST 2023
获取月的天数
Calendar提供 getActualMaximum(int field) 返回当前日期,给定字段的最大值,,可以指定获取最大值的字段,如Calendar.DAY_OF_MONTH、Calendar.YEAR等。
// 获取指定月的天数
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR,2024);
calendar.set(Calendar.MONTH, Calendar.FEBRUARY); // 设置月份为二月
int daysInMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
System.out.println(daysInMonth); // 29
获取当前周的周一和周日
Calendar calendar = Calendar.getInstance();
// 获取当前时间
Date now = calendar.getTime();
System.out.println(now); // Fri Dec 22 11:34:37 CST 2023
// 设置为周一
calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
Date firstDayOfWeek = calendar.getTime();
System.out.println(firstDayOfWeek); // Mon Dec 18 11:34:37 CST 2023
// 周日
calendar.add(Calendar.DAY_OF_WEEK, 6);
Date lastDayOfWeek = calendar.getTime();
System.out.println(lastDayOfWeek); // Sun Dec 24 11:34:37 CST 2023
判断是否是闰年
GregorianCalendar是Calendar类的一个具体实现。使用 isLeapYear() 直接判断是否闰年。
// 判断是否是闰年
int year = 2023;
GregorianCalendar gregorianCalendar = new GregorianCalendar();
// 测试当前年份是否为闰年
if(gregorianCalendar.isLeapYear(year)) {
System.out.println("当前年份是闰年");
}
else {
System.out.println("当前年份不是闰年");
}
Java8特性-日期时间
Java8 新增的日期类主要有三个:
- LocalDate:表示日期(年月日)
- LocalTime:表示时间(时分秒)
- LocalDateTime:表示时间+ 日期 (年月日时分秒),是Java8最常用的日期类
在旧版的 Java 中,日期时间 API 存在诸多问题,其中有:
-
非线程安全 − java.util.Date 是非线程安全的,所有的日期类都是可变的,这是Java日期类最大的问题之一。
-
设计很差 − Java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义。java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。
-
时区处理麻烦 − 日期类并不提供国际化,没有时区支持,因此Java引入了java.util.Calendar和java.util.TimeZone类,但他们同样存在上述所有的问题。
Java 8 在 java.time 包下提供了很多新的 API。以下为两个比较重要的 API:
-
Local(本地) − 简化了日期时间的处理,没有时区的问题。
-
Zoned(时区) − 通过制定的时区处理日期时间。
新的java.time包涵盖了所有处理日期,时间,日期/时间,时区,时刻(instants),过程(during)与时钟(clock)的操作。
获取时间
// 获取当前日期
LocalDate localDate = LocalDate.now();
System.out.println(localDate); // 2023-12-22
// 获取当前时间
LocalTime localTime = LocalTime.now();
System.out.println(localTime); // 14:41:35.629
// 获取当前日期时间
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime); // 2023-12-22T14:41:35.629
// LocalDate和LocalTime创建LocalDateTime
LocalDateTime time = LocalDateTime.of(localDate, localTime);
System.out.println(time); // 2023-12-22T14:41:35.629
格式化日期
使用 DateTimeFormatter 重置时间格式。
// 日期格式化
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime localDateTime1 = LocalDateTime.now();
System.out.println(localDateTime); // 2023-12-22T14:57:48.179
String dateTimeStr1 = localDateTime.format(dateTimeFormatter);
System.out.println(dateTimeStr); // 2023-12-22 14:57:48
String dateTimeStr2 = "2023-12-22 15:03:22";
LocalDateTime localDateTime2 = LocalDateTime.parse(dateTimeStr2,dateTimeFormatter);
System.out.println(localDateTime2); // 2023-12-22T15:03:22
获取当前日期的信息
// 获取当前信息
LocalDateTime now = LocalDateTime.now();
System.out.println(now); // 2023-12-22T15:10:46.551
int year = now.getYear(); // 2023
int month = now.getMonthValue(); // 12
int day = now.getDayOfMonth(); // 22
int hour = now.getHour(); // 15
int minute = now.getMinute(); // 10
int second = now.getSecond(); // 46
int dayOfYear = now.getDayOfYear(); // 356
int dayOfWeek = now.getDayOfWeek().getValue(); // 5
获取指定日期
TemporalAdjusters 类是Java 8引入的日期时间库中的一个类,它提供了一系列静态方法,用于执行复杂的日期时间操作。
// 获取指定日期
LocalDateTime now = LocalDateTime.now();
System.out.println(now); // 2023-12-22T15:32:45.055
// 获取当月第一天
LocalDateTime firstDayOfMonth = now.with(TemporalAdjusters.firstDayOfMonth());
System.out.println(firstDayOfMonth); // 2023-12-01T15:32:45.055
// 获取当月最后一天
LocalDateTime lastDayOfMonth = now.with(TemporalAdjusters.lastDayOfMonth());
System.out.println(lastDayOfMonth); // 2023-12-31T15:32:45.055
// 获取当年第一天
LocalDateTime firstDayOfYear = now.with(TemporalAdjusters.firstDayOfYear());
System.out.println(firstDayOfYear); // 2023-01-01T15:32:45.055
// 获取当年最后一天
LocalDateTime lastDayOfYear = now.with(TemporalAdjusters.lastDayOfYear());
System.out.println(lastDayOfYear); // 2023-12-31T15:32:45.055
// 获取下一年的第一天
LocalDateTime firstDayOfNextYear = now.with(TemporalAdjusters.firstDayOfNextYear());
System.out.println(firstDayOfNextYear); // 2024-01-01T15:32:45.055
// 获取当月第一个周一
LocalDateTime firstMondayOfMonth = now.with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY));
System.out.println(firstMondayOfMonth); // 2023-12-04T15:32:45.055
// 获取当月最后一个周日
LocalDateTime lastSundayOfMonth = now.with(TemporalAdjusters.lastInMonth(DayOfWeek.SUNDAY));
System.out.println(lastSundayOfMonth); // 2023-12-31T15:32:45.055
日期计算
使用 plus(long amountToAdd , TemporalUnit unit) 可以计算指定时间后的日期。
ChronoUnit是TemporalUnit的实现类,提供了一系列枚举值。
LocalDateTime now = LocalDateTime.now();
System.out.println(now); // 2023-12-22T15:44:06.356
// 计算1天后的日期
LocalDateTime oneDayAfter = now.plus(1, ChronoUnit.DAYS);
System.out.println(oneDayAfter); // 2024-12-22T15:44:06.356
// 计算1周后的日期
LocalDateTime oneWeekAfter = now.plus(1, ChronoUnit.WEEKS);
System.out.println(oneWeekAfter); // 2024-01-22T15:44:06.356
// 计算1月后的日期
LocalDateTime oneMonthAfter = now.plus(1, ChronoUnit.MONTHS);
System.out.println(oneMonthAfter); // 2023-12-29T15:44:06.356
// 计算1年后的日期
LocalDateTime oneYearAfter = now.plus(1, ChronoUnit.YEARS);
System.out.println(oneYearAfter); // 2023-12-23T15:44:06.356
或者使用指定日期偏移方法完成计算:
LocalDateTime now = LocalDateTime.now();
System.out.println(now); // 2023-12-22T16:11:11.056
LocalDateTime oneDayAfter = now.plusDays(1); // 给当前时间加一天 2023-12-23T16:11:11.056
LocalDateTime oneDayAgo = now.minusDays(1); // 给当前时间减一天 2023-12-21T16:11:11.056
LocalDateTime oneWeekAfter = now.plusWeeks(1); // 给当前时间加一周 2023-12-29T16:11:11.056
LocalDateTime onwWeekAgo = now.minusWeeks(1); // 给当前时间减一周 2023-12-15T16:11:11.056
LocalDateTime oneMonthAfter = now.plusMonths(1); // 给当前时间加一月 2024-01-22T16:11:11.056
LocalDateTime oneMonthAgo = now.minusMonths(1); // 给当前时间减一月 2023-11-22T16:11:11.056
LocalDateTime oneYearAfter = now.plusYears(1); // 给当前时间加一年 2024-12-22T16:11:11.056
LocalDateTime oneYearAgo = now.minusYears(1); // 给当前时间减一年 2022-12-22T16:11:11.056
LocalDateTime oneHourAfter = now.plusHours(1); // 给当前时间加一小时 2023-12-22T17:11:11.056
LocalDateTime oneHourAgo = now.minusHours(1); // 给当前时间减一小时 2023-12-22T15:11:11.056
LocalDateTime oneMinuteAfter = now.plusMinutes(1); // 给当前时间加一分钟 2023-12-22T16:12:11.056
LocalDateTime oneMinuteAgo = now.minusMinutes(1); // 给当前时间减一分钟 2023-12-22T16:10:11.056
LocalDateTime oneSecondAfter = now.plusSeconds(1); // 给当前时间加一秒 2023-12-22T16:11:12.056
LocalDateTime oneSecondAgo = now.minusSeconds(1); // 给当前时间减一秒 2023-12-22T16:11:10.056
计算两个日期间隔多少年、多少月、多少天
Java8引入了Period-计算两个日期间隔的类,使用between方法返回两个日期之间的差。
// 计算两个日期间隔多少天、多少月、多少年
LocalDate date1 = LocalDate.parse("2023-02-20");
LocalDate date2 = LocalDate.parse("2023-12-30");
Period between = Period.between(date1, date2);
System.out.println(date1 + "与" + date2 + "相差 " + between.getYears() + "年 " + between.getMonths() + "月 " + between.getDays() + "天");
// 2023-02-20与2023-12-30相差 0年 10月 10天
计算两个日期间隔多少天
long day1 = ChronoUnit.DAYS.between(date1, date2);
System.out.println(date1 + "与" + date2 + "相差 " + day1 + "天");
// 2023-02-20与2023-12-30相差 313天
long day2 =date2.toEpochDay() - date1.toEpochDay();
System.out.println(date1 + "与" + date2 + "相差 " + day2 + "天");
// 2023-02-20与2023-12-30相差 313天
总结
Date、Calendar和LocalDateTime在Java中都是用于处理日期和时间的类,但它们之间存在一些区别。
- Date:这是Java 1.0提供的一个类,用于表示特定的时间点。它包含年、月、日、时、分、秒、毫秒的信息。然而,Date类在某些方面存在一些问题,例如它的线程安全性和对时区的处理方式。
- Calendar:这是Java 1.1提供的一个类,用于处理日期和时间。它提供了一种灵活的方式来表示和操作日期和时间。Calendar类是基于Calendar类的,它提供了一种基于特定时区的日期和时间计算方式。
- LocalDateTime:这是Java 8引入的一个新的日期和时间API的一部分,用于表示没有时区的日期和时间。LocalDateTime类提供了一种简单的方式来表示和操作日期和时间,并且它是线程安全的。
总的来说,Date、Calendar和LocalDateTime的主要区别在于它们的使用场景和功能。Date主要用于表示特定的时间点,Calendar主要用于处理日期和时间的计算和操作,而LocalDateTime则主要用于表示没有时区的日期和时间。