Java标准库有两套处理时间和日期的API:
一套定义在java.util包中,主要有Date、Calendar
一套新的API是在Java 8引入的,定义在java.time包中,主要有LocalDate、LocalTime、LocalDataTime
原因:由于历史遗留原因,旧的API存在很多问题,所以引入了新的API。
Java 8之前的API
Date
java.util.Date是用来表示一个时间和日期的对象。
缺点:
Date总是以当前计算机系统的默认时区为基础进行输出
很难对日期和时间进行加减、计算两个日期相差几天、计算下个星期日的日期等
常用方法:
getYear()返回的年份必须加上1900。
getMonth()返回的月份是011分别表示112月,所以要加1。
getDate()返回的日期范围是1~31,不能加1。
getDay()返回的星期范围是0~6,星期天为0。
为了精确控制时间和日期的格式,可以使用SimpleDateFormat对一个Date进行转换,用预定义的字符串表示格式化:
yyyy:年
MM:月
dd:日
HH:小时
mm:分钟
ss:秒
SSS:毫秒
Date类示例:
public class Main
{
public static void main(String[] args)
{
//1、获取当前日期
Date now = new Date();
System.out.println(now.getYear() + 1900); //2020 必须加上1900
System.out.println(now.getMonth() + 1);//8 0-11,必须加上1
System.out.println(now.getDate());//24 0-31,不能加1
System.out.println(now.getDay()); //1 0-6,以星期天(0)开始
System.out.println(now.toString());//Mon Aug 24 21:14:24 CST 2020
System.out.println(now.toLocaleString());//2020-8-24 21:14:24
//2、基本的日期比较
Date other = new Date(now.getTime() + 1);
System.out.println(now.after(other));//false
System.out.println(now.before(other));//true
//3、使用SimpleDateFormat进行日期格式化
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(format.format(now));//2020-08-24 21:14:24
//3.1使用自定义日期格式化
SimpleDateFormat predefineFormat = new SimpleDateFormat("E yyyy-MM-dd");
System.out.println(predefineFormat.format(now));//星期一 2020-08-24
}
}
其他格式语法介绍:
G:公元
E:一周中的周几
D:一年中的第几天
w:一年中的第几个星期
a:上下/下午 标记符
k:时(1~24)
K:时 在上午或下午(0~11)
其他格式语法示例:
public class Main
{
public static void main(String[] args)
{
//获取当前日期
Date now = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(format.format(now));//2020-08-24 21:32:33
SimpleDateFormat format1 = new SimpleDateFormat("G E D w a k K yyyy-MM-dd");
System.out.println(format1.format(now));//公元 星期一 237 35 下午 21 9 2020-08-24
}
}
Calendar
java.util.Calendar可以用于获取并设置年、月、日、时、分、秒,它和Date比,主要多了一个可以做简单的日期和时间运算的功能。
常用方法:
get(Calendar.YEAR):获取指定字段的值,参数为预定义的常量,返回值均为int。年份时不需要加上1900,月份时返回范围0~11。
set(Calendar.YEAR,2020):设置指定字段的值。
add(Calendar.YEAR,2):增加指定字段的值,可以为负数
参数和返回值均为int类型。
Calendar类示例:
public class Main
{
public static void main(String[] args)
{
//1、获取当前时间(唯一的方法)
Calendar now = Calendar.getInstance();
int y = now.get(Calendar.YEAR);//不用再加1900
int m = now.get(Calendar.MONTH) + 1;//仍要加1
int d = now.get(Calendar.DAY_OF_MONTH);
int w = now.get(Calendar.DAY_OF_WEEK);//1-7 星期日为1
int hh = now.get(Calendar.HOUR_OF_DAY);
int mm = now.get(Calendar.MINUTE);
int ss = now.get(Calendar.SECOND);
int ms = now.get(Calendar.MILLISECOND);
System.out.println(y + "-" + m + "-" + d + " " + hh + ":" + mm + ":" + ss + "." + ms + " " + w);
//输出:2020-8-24 21:35:21.166 2
//2、设置其他的时间
now.clear();//必须先清除,否则未设置的值(如时、分、秒)会以已有值进行显示
now.set(Calendar.YEAR, 2018);
now.set(Calendar.MONTH, 9);//月份会加1
now.set(Calendar.DAY_OF_MONTH, 1);
now.set(Calendar.HOUR_OF_DAY, 10);
now.set(Calendar.MINUTE, 10);
now.set(Calendar.SECOND, 1);
// now.set(2018,9,1,10,10,2); //等同于上面的设置
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(now.getTime()));
//输出:2018-10-01 10:10:01
//3、简单的时间/日期运算
Calendar c = Calendar.getInstance();
c.add(Calendar.YEAR, 1);//可以为负数
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(c.getTime()));
//输出:2021-08-24 21:35:21
}
}
可以使用Calendar写一个DateUtils类,提供一些公共方法。
DateUtils类示例:
public final class DateUtils
{
/**
* 获取星期几
*
* @param date 要获取星期的日期
* @return 星期几,星期日为1,星期一为2,以此类推
*/
public static int getWeek(Date date)
{
Calendar c = Calendar.getInstance();
c.setTime(date);
return c.get(Calendar.DAY_OF_WEEK);
}
/**
* 获取星期几
*
* @return 星期几,星期日为1,星期一为2,以此类推 季度
*/
public static int getWeek()
{
Calendar c = Calendar.getInstance();
return c.get(Calendar.DAY_OF_WEEK);
}
/**
* 获取季度
*
* @param date 要获取季度的日期
* @return 季度,一季度为0,第二季度为1,第三季度为2,第三季度为3
*/
public static int getQuarter(Date date)
{
Calendar c = Calendar.getInstance();
c.setTime(date);
return c.get(Calendar.MONTH) / 3;
}
/**
* 获取当前季度
*
* @return 季度,一季度为0,第二季度为1,第三季度为2,第三季度为3
*/
public static int getQuarter()
{
Calendar c = Calendar.getInstance();
return c.get(Calendar.MONTH) / 3;
}
/**
* 增加月
*
* @param date 增加前的日期
* @param month 增加的月数
* @return 增加后的日期
*/
public static Date addMonth(Date date, int month)
{
Calendar c = Calendar.getInstance();
c.setTime(date);
c.add(Calendar.MONTH, month);
return c.getTime();
}
/**
* 增加季度
*
* @param date 增加前的日期
* @param quarter 增加的季度数
* @return 增加后的日期
*/
public static Date addQuarter(Date date, int quarter)
{
return addMonth(date, quarter * 3);
}
/**
* 获取当月的最后一天
*
* @param date 日期
* @return 当月最后一天
*/
public static Date getMonthEnd(Date date)
{
Calendar c = Calendar.getInstance();
c.setTime(date);
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
c.set(Calendar.DATE, 1);
c.add(Calendar.MONTH, 1);
c.add(Calendar.DAY_OF_MONTH, -1);
return c.getTime();
}
}
Java 8的API
本地日期和时间:LocalDateTime,LocalDate,LocalTime;(默认严格按照ISO 8601规定的日期和时间格式进行打印),以上三个类都提供静态方法now()获取当前时间日期/日期/时间对象
时间间隔:Duration;
用于取代SimpleDateFormat的格式化类型:DateTimeFormatter
改进点:新API修正了旧API不合理的常量设计
Month的范围用1~12表示1月到12月;
Week的范围用1~7表示周一到周日
LocalDateTime、LocalDate、LocalTime
获取本地的当前日期和时间:
public class Main
{
public static void main(String[] args)
{
//获取当前日期和时间now()
LocalDateTime now = LocalDateTime.now();
LocalDate localDate = now.toLocalDate();//转为当前日期
LocalTime localTime = now.toLocalTime();//转为当前时间
System.out.println(now);//2020-08-24T22:36:24.071
System.out.println(localDate);//2020-08-24
System.out.println(localTime);//22:36:24.071
}
}
通过of()方法,以指定的日期和时间创建LocalDateTime:
public class Main
{
public static void main(String[] args)
{
LocalDate date = LocalDate.of(2020, 10, 1);//2020-10-01
LocalTime time = LocalTime.of(10, 1, 1);//10:01:01
LocalDateTime localDateTime = LocalDateTime.of(date, time);
System.out.println(localDateTime);//2020-10-01T10:01:01
LocalDateTime localDateTime2 = LocalDateTime.of(2020, 10, 1, 10, 1, 1);
System.out.println(localDateTime2);//2020-10-01T10:01:01
}
}
因为严格按照ISO 8601的格式,因此,将字符串转换为LocalDateTime就可以传入标准格式:
public class Main
{
public static void main(String[] args)
{
//使用字符串 parse()
LocalDate parseDate = LocalDate.parse("2019-10-01");
LocalTime parseTime = LocalTime.parse("10:01:01");
//ISO 8601规定的日期和时间间隔符为T
LocalDateTime parseDateTime = LocalDateTime.parse("2019-10-01T10:01:01.111");
System.out.println(parseDate);
System.out.println(parseTime);
System.out.println(parseDateTime);
}
}
注意ISO 8601规定的日期和时间分隔符是T。标准格式如下:
日期:yyyy-MM-dd
时间:HH:mm:ss
带毫秒的时间:HH:mm:ss.SSS
日期和时间:yyyy-MM-ddTHH:mm:ss
带毫秒的日期和时间:yyyy-MM-ddTHH:mm:ss.SSS
自定义输出格式 DateTimeFormatter:
public class Main
{
public static void main(String[] args)
{
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH-mm-ss");
System.out.println(formatter.format(LocalDateTime.now())); // 2020/08/24 22-36-24
LocalDateTime parse = LocalDateTime.parse("2019/10/01 10-01-01", formatter);
System.out.println(parse);//2019-10-01T10:01:01
}
}
LocalDateTime提供了对日期和时间进行加减的非常简单的链式调用:
public class Main
{
public static void main(String[] args)
{
// 使用plusXxx()方法进行增加,例如plusDays(7)会把2020-08-24变为2020-08-31
// 使用minusXxx()方法进行减少,例如minusDays(7)会把2020-08-24变为2020-08-17
LocalDateTime dateTime = LocalDateTime.of(2020, 8, 24, 10, 1, 1);
System.out.println("原始时间:" + dateTime);//原始时间:2020-08-24T10:01:01
//加7天减1小时
LocalDateTime dt1 = dateTime.plusDays(7).minusHours(1);
System.out.println("增加7天并减去1小时后:" + dt1);//增加7天并减去1小时后:2020-08-31T09:01:01
LocalDateTime dt2 = dt1.plusMonths(1);
System.out.println("增加1个月后:" + dt2);// 增加1个月后:2020-09-30T09:01:01 月份加减时会自动调整日期,例如从2020-08-31减去一个月的结果是2020-09-30
}
}
对日期和时间进行调整则使用withXxx()方法,例如:withHour(15)会把10:11:12变为15:11:12:
调整年:withYear()
调整月:withMonth()
调整日:withDayOfMonth()
调整时:withHour()
调整分:withMinute()
调整秒:withSecond()
public class Main
{
public static void main(String[] args)
{
LocalDateTime dateTime5 = LocalDateTime.of(2020, 8, 31, 10, 1, 1);
System.out.println("原始时间:" + dateTime5);//原始时间:2020-08-31T10:01:01
LocalDateTime dateTime5After = dateTime5.withMonth(9);
System.out.println("调整月份后:" + dateTime5After);//调整月份后:2020-09-30T10:01:01 月份调整时也会自动调整日期
}
}
Duration和Period
Duration表示两个时刻之间的时间间隔。另一个类似的Period表示两个日期之间的天数:
public class Main
{
public static void main(String[] args)
{
LocalDateTime end = LocalDateTime.of(2020, 10, 1, 10, 1, 1);
LocalDateTime start = LocalDateTime.now();
System.out.println("当前时间:" + start);//当前时间:2020-08-24T23:18:41.030
//时间
Duration duration = Duration.between(start, end);
System.out.println("间隔天数:" + duration.toDays());//间隔天数:37
System.out.println("间隔小时数:" +duration.toHours());//间隔小时数:898
System.out.println("间隔分钟数:" +duration.toMinutes());//间隔分钟数:53922
System.out.println("间隔秒数:" +duration.toMillis());//间隔秒数:3235339970
//日期
Period period = LocalDate.of(2019, 10, 1).until(LocalDate.of(2020, 10, 10));
System.out.println("间隔年数:" + period.getYears());//间隔年数:1
System.out.println("间隔月数:" + period.getMonths());//间隔月数:0
System.out.println("间隔天数:" + period.getDays());//间隔月数:9
}
}