(三)Java常用类之日期使用 | 【奔跑吧!JAVA】
【摘要】 日期在Java中是一块非常复杂的内容,在Java8之前主要使用java.util.Date处理日期,该类是非线程安全的,在Java8中引入了LocalDate、LocalTime、LocalDateTime等很多新的日期处理类,解决了线程安全问题。
1、JDK8之前日期时间处理方式
1.1、java.lang.System类
System类提供的public static native long currentTimeMillis();用来返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差,此方法主要适用于计算时间差。
计算世界时间的主要标准有:
UTC(Coordinated Universal Time)
GMT(Greenwich Mean Time)
CST(Central Standard Time)
public class DateTest1 {
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
System.out.println("开始时间戳:" + start);
Thread.sleep(3000);
long end = System.currentTimeMillis();
System.out.println("结束时间戳:" + end);
System.out.println("间隔时间差为:" + (end - start));
}
}
1.2、java.util.Date类与java.sql.Date类
两个类的关系:
java.util.Date类
|---java.sql.Date类
两个构造器的使用:
构造器一:Date():创建一个对应当前时间的Date对象
构造器二:创建指定毫秒数的Date对象
两个方法的使用:
getTime():获取当前Date对象对应的毫秒数。(时间戳)
toString():显示当前的年、月、日、时、分、秒。
java.sql.Date对应着数据库中的日期类型的变量:
public class DateTest2 {
public static void main(String[] args) {
//构造器一:Date():创建一个对应当前时间的Date对象
Date date1 = new Date();
//Fri Jun 18 20:49:21 CST 2021
System.out.println(date1.toString());
//1624020561213
System.out.println(date1.getTime());
//构造器二:创建指定毫秒数的Date对象
Date date2 = new Date(1624020561013L);
System.out.println(date2.toString());
//创建java.sql.Date对象
java.sql.Date date3 = new java.sql.Date(1624020401013L);
//2021-06-18
System.out.println(date3);
//如何将java.util.Date对象转换为java.sql.Date对象
//情况一:多态的形式直接强转日期
Date date4 = new java.sql.Date(1624020401013L);
java.sql.Date date5 = (java.sql.Date) date4;
System.out.println(date5);
//情况二:通过java.util.Date的getTime方法
Date date6 = new Date();
java.sql.Date date7 = new java.sql.Date(date6.getTime());
System.out.println(date7);
}
}
1.3、java.text.SimpleDataFormat类
SimpleDateFormat对日期Date类的格式化和解析
两个操作:
格式化:日期 ---> 字符串
解析:格式化的逆过程,字符串 ---> 日期
public class DateTest3 {
public static void main(String[] args) throws ParseException {
//照指定的方式格式化和解析:调用带参的构造器
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
//格式化
Date date = new Date();
String format1 = sdf1.format(date);
System.out.println(format1);
//解析:要求字符串必须是符合SimpleDateFormat识别的格式(通过构造器参数体现),否则会抛异常
Date date2 = sdf1.parse("2020-02-18 11:48:27");
System.out.println(date2);
}
}
1.4、java.util.Calendar类:日历类、抽象类
1.实例化
方式一:创建其子类GregorianCalendar的对象
方式二:调用其静态方法getInstance()
2.常用方法
get():通过get方法可以获取日期中的年、月、日、时、分、秒等
set():通过set方法设置日期的值(可设置年、月、日、时、分、秒等)
add():在日期上增加指定的天数、周数或月数
getTime():日历类 转成 Date
setTime():Date 转成 日历类
public class DateTest4 {
public static void main(String[] args) {
//1.实例化
//方式一:创建其子类GregorianCalendar的对象
Calendar calendar1 = new GregorianCalendar();
System.out.println(calendar1.getClass());
//方式二:调用其静态方法getInstance()
Calendar calendar2 = Calendar.getInstance();
System.out.println(calendar2.getClass());
//2.常用方法
//get()
System.out.println("年:" + calendar2.get(Calendar.YEAR));
//赋值时年月日时分秒常用的6个值,注意月份下标从0开始,所以取月份要+1
System.out.println("月:" + (calendar2.get(Calendar.MONTH) + 1));
System.out.println("日:" + calendar2.get(Calendar.DAY_OF_MONTH));
System.out.println("时:" + calendar2.get(Calendar.HOUR_OF_DAY));
System.out.println("分:" + calendar2.get(Calendar.MINUTE));
System.out.println("秒:" + calendar2.get(Calendar.SECOND));
//set()
//calendar可变性
int days = calendar2.get(Calendar.DAY_OF_MONTH);
System.out.println(days);
calendar2.set(Calendar.DAY_OF_MONTH, 22);
days = calendar2.get(Calendar.DAY_OF_MONTH);
System.out.println(days);
//add(),举例:在日期上减掉3天
calendar2.add(Calendar.DAY_OF_MONTH, -3);
days = calendar2.get(Calendar.DAY_OF_MONTH);
System.out.println(days);
//getTime():日历类 转成 Date
Date date = calendar2.getTime();
System.out.println(date);
//setTime():Date 转成 日历类
Date date1 = new Date();
calendar2.setTime(date1);
days = calendar2.get(Calendar.DAY_OF_MONTH);
System.out.println(days);
}
}
2、JDK8中新日期时间处理方式
2.1、日期时间API的迭代
第一代:jdk 1.0 Date类
第二代:jdk 1.1 Calendar类,一定程度上替换Date类
第三代:jdk 1.8 提出了新的一套API
2.2、前两代存在的问题举例:
可变性:像日期和时间这样的类应该是不可变的。
偏移性:Date中的年份是从1900开始的,而月份都从0开始。
格式化:格式化只对Date用,Calendar则不行。
此外,它们也不是线程安全的;不能处理闰秒等。
2.3、java 8 中新的日期时间API涉及到的包
java.time – 包含值对象的基础包
java.time.chrono – 提供对不同的日历系统的访问
java.time.format – 格式化和解析时间和日期
java.time.temporal – 包括底层框架和扩展特性
java.time.zone – 包含时区支持的类
说明:大多数开发者只会用到基础包和format包,也可能会用到temporal包。因此,尽管有68个新的公开类型,大多数开发者,大概将只会用到其中的三分之一。
2.4、本地日期(LocalDate)、本地时间(LocalTime)、本地日期时间(LocalDateTime)的使用
LocalDate、LocalTime、LocalDateTime 类是其中较重要的几个类,它们的实例是不可变的对象,分别表示使用ISO-8601日历系统的日期、时间、日期和时间。
它们提供了简单的本地日期或时间,并不包含当前的时间信息,也不包含与时区相关的信息。
LocalDate:代表IOS格式(yyyy-MM-dd)的日期,可以存储生日、纪念日等日期。
LocalTime:表示一个时间,而不是日期。
LocalDateTime:是用来表示日期和时间的,这是一个最常用的类之一。
注:ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示法,也就是公历。
常用方法:
now():静态方法,根据当前时间创建对象
now(ZoneId zone):静态方法,根据当前时间创建指定时区的对象
of():静态方法,根据指定日期/时间创建对象
getDayOfMonth():获得月份天数(1-31)
getDayOfYear():获得年份天数(1-366)
getDayOfWeek():获得星期几(返回一个 DayOfWeek 枚举值)
getMonth():获得月份, 返回一个 Month 枚举值
getMonthValue():获得月份(1-12)
getYear():获得年份
getHour()、getMinute()、getSecond():获得当前对象对应的小时、分钟、秒
withDayOfMonth()、withDayOfYear()、withMonth()、withYear():将月份天数、年份天数、月份、年份修改为指定的值并返回新的对象
plusDays()、plusWeeks()、plusMonths()、plusYears()、plusHours():向当前对象添加几天、几周、几个月、几年、几小时
minusMonths()、minusWeeks()、minusDays()、minusYears()、minusHours:从当前对象减去几月、几周、几天、几年、几小时
2.4.1、创建日期、时间或日期时间
public class DateTest5 {
public static void main(String[] args) {
//根据当前时间创建对象
LocalDate curDate = LocalDate.now();
System.out.println("当前日期为:" + curDate);
LocalTime curTime = LocalTime.now();
System.out.println("当前时间为:" + curTime);
LocalDateTime curDateTime = LocalDateTime.now();
System.out.println("当前日期时间为:" + curDateTime);
//后续均以LocalDateTime为例,LocalDate和LocalTime使用同LocalDateTime一致
//根据当前时间创建指定时区的对象
//ZoneId:类中包含了所的时区信息
//getAvailableZoneIds():获取所的ZoneId
Set<String> zoneIds = ZoneId.getAvailableZoneIds();
for (String s : zoneIds) {
System.out.println(s);
}
System.out.println();
//获取“America/Belize”时区对应的时间
LocalDateTime localDateTime = LocalDateTime.now(ZoneId.of("America/Belize"));
System.out.println(localDateTime);
//ZonedDateTime:带时区的日期时间
//now():获取本时区的ZonedDateTime对象
ZonedDateTime zonedDateTime = ZonedDateTime.now();
System.out.println(zonedDateTime);
//now(ZoneId id):获取指定时区的ZonedDateTime对象
ZonedDateTime zonedDateTime1 = ZonedDateTime.now(ZoneId.of("America/Belize"));
System.out.println(zonedDateTime1);
//of():根据指定日期/时间创建对象
LocalDateTime ofDate = LocalDateTime.of(2021, 5, 4, 12, 12, 30);
System.out.println(ofDate);
}
}
2.4.2、获取年、月、日、时、分、秒信息
LocalDateTime提供了获取年、月、日的快捷方法,其实例还包含很多其它的日期属性。通过调用这些方法就可以很方便的得到需要的日期信息,不用像以前一样需要依赖java.util.Calendar类。
public class DateTest6 {
public static void main(String[] args) {
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("年:" + localDateTime.getYear());
System.out.println("月:" + localDateTime.getMonthValue());
System.out.println("日:" + localDateTime.getDayOfMonth());
System.out.println("时:" + localDateTime.getHour());
System.out.println("分:" + localDateTime.getMinute());
System.out.println("秒:" + localDateTime.getSecond());
}
}
2.4.3、判断两个日期是否相等
在项目开发的时候总会遇到判断两个日期是否相等的问题。下面这个例子会帮助你用Java 8的方式去解决,LocalDate重载了equal方法。注意,如果比较的日期是字符型的,需要先解析成日期对象再作判断。
public class DateTest7 {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
LocalDate date1 = LocalDate.of(2021, 6, 18);
if (date1.equals(today)) {
System.out.printf("今天 %s 和日期 %s 是同一天 %n", today, date1);
} else {
System.out.printf("今天 %s 和日期 %s 不是同一天 %n", today, date1);
}
}
}
2.4.4、检查像生日、节假日这种周期性事件
Java中可以通过MonthDay类检查类似生日、纪念日、法定假日(国庆以及春节)等周期性日期。这个类组合了月份和日,去掉了年,这意味着你可以用它判断每年都会发生事件。和这个类相似的还有一个YearMonth类。这些类也都是不可变并且线程安全的值类型。
public class DateTest8 {
public static void main(String[] args) {
//取得当前日期
LocalDate today = LocalDate.now();
//根据日期2018-06-18获取日期实例
LocalDate dateOfBirth = LocalDate.of(2018, 6, 18);
//根据06-18日期获取MonthDay实例
MonthDay birthday = MonthDay.of(dateOfBirth.getMonth(), dateOfBirth.getDayOfMonth());
//取得当前日期除了年以外的日期部分
MonthDay currentMonthDay = MonthDay.from(today);
//判断与设置的日期是否是同一天(不含年)
if (currentMonthDay.equals(birthday)) {
System.out.println("祝您生日快乐!!");
} else {
System.out.println("当前日期不是您的生日!!");
}
}
}
2.4.5、在现有的时间上增加天数
Java 8提供了更好的 plusDays() 方法替换 add() ,并且是兼容的。注意,这些方法返回一个全新的LocalDate实例,由于其不可变性,返回后一定要用变量赋值。
public class DateTest9 {
public static void main(String[] args) {
LocalDate localDate = LocalDate.now();
// 增加两天
LocalDate newDate = localDate.plusDays(-2);
System.out.println("增加两天后日期为:" + newDate);
// 也可直接使用plus方法,使用ChronoUnit类声明的时间单位,增加两天
LocalDate newDate1 = localDate.plus(2, ChronoUnit.DAYS);
System.out.println("增加两天后日期为:" + newDate1);
}
}
说明:增加周、月、年和小时与上述例子使用方式一样,分别调用如下方法即可:plusWeeks()、plusMonths()、plusYears()、plusHours(),如果是减掉指定的天数使用对应的minusXXX方法即可;也可直接使用plus或minus方法配合ChronoUnit类声明的时间单位进行计算。
2.4.6、判断日期是早于还是晚于另一个日期
LocalDate 类有两类方法 isBefore() 和 isAfter() 用于比较日期。调用 isBefore()方法时,如果给定日期小于当前日期则返回 true。
public class DateTest10 {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
LocalDate after = LocalDate.of(2021, 6, 29);
if (after.isAfter(today)) {
System.out.println("当前日期在给定日期之后");
}
//减去一天
LocalDate before = LocalDate.of(2021, 6, 1);
if (before.isBefore(today)) {
System.out.println("当前日期在给定日期之前");
}
}
}
2.4.7、检查闰年
LocalDate类有一个很实用的方法 isLeapYear() 判断该实例是否是一个闰年,这是一个纯Java逻辑编写的判断闰年的程序。
public class DateTest11 {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
if(today.isLeapYear()){
System.out.println("当前年度是闰年");
}else {
System.out.println("当前年度不是闰年");
}
}
}
2.5、java.time.Clock时钟类
Java 8增加了一个 Clock 时钟类用于获取当时的时间戳,或当前时区下的日期时间信息。以前用到System.currentTimeInMillis() 和 TimeZone.getDefault() 的地方都可用Clock替换。
public class DateTest12 {
public static void main(String[] args) {
// 根据系统时间返回当前时间并设置为UTC。
Clock clock = Clock.systemUTC();
System.out.println("Clock : " + clock);
// 根据系统时钟区域返回时间
Clock defaultClock = Clock.systemDefaultZone();
System.out.println("Clock : " + clock);
}
}
2.6、java.time.Instant时间点类
时间线上的一个瞬时点。概念上讲,它只是简单的表示自1970年1月1日0时0分0秒(UTC开始的秒数),类似于 java.util.Date类。
常用方法:
now():静态方法,返回默认UTC时区的Instant类的对象
ofEpochMilli(long epochMilli):静态方法,返回在1970-01-01 00:00:00基础上加上指定毫秒数之后的Instant类的对象
atOffset(ZoneOffset offset):结合即时的偏移来创建一个 OffsetDateTime
toEpochMilli():返回1970-01-01 00:00:00到当前时间的毫秒数,即为时间戳
public class DateTest13 {
public static void main(String[] args) {
Instant timestamp = Instant.now();
System.out.println("当前时间点是:" + timestamp);
}
}
2.7、java.time.Period类,用于计算两个“日期”间隔,以年、月、日衡量
有一个常见日期操作是计算两个日期之间的天数、周数或月数。在Java 8中可以用java.time.Period类来做计算。下面这个例子中,我们计算了当天和将来某一天之间的月数。
常用方法:
between(LocalDatestart,LocalDate end):静态方法,返回Period对象,表示两个本地日期的间隔
getYears():返回此期间的年数
getMonths():返回此期间的月数
getDays():返回此期间的天数
withYears(int years):返回设置间隔指定年数以后的Period对象
withMonths(int months):返回设置间隔指定月数以后的Period对象
withDays(int days):返回设置间隔指定日数以后的Period对象
public class DateTest14 {
public static void main(String[] args) {
//当前日期是6月
LocalDate today = LocalDate.now();
//设定日期为12月
LocalDate java8Release = LocalDate.of(2021, Month.DECEMBER, 19);
Period period = Period.between(today, java8Release);
System.out.println(period.getYears());
System.out.println(period.getMonths());
System.out.println(period.getDays());
Period period1 = period.withYears(2);
System.out.println(period1);
System.out.println("当前日期与设定日期相差:" + period.getMonths() + "个月");
}
}
2.8、Duration,用于计算两个“时间”间隔,以秒和纳秒为基准
常用方法:
between(Temporal start,Temporal end):静态方法,返回Duration对象,表示两个时间的间隔
getNano():返回时间间隔的纳秒数
getSeconds():返回时间间隔的秒数
toDays():返回时间间隔期间的天数
toHours():返回时间间隔期间的小时数
toMinutes():返回时间间隔期间的分钟数
toMillis():返回时间间隔期间的毫秒数
toNanos():返回时间间隔期间的纳秒数
public class DateTest15 {
public static void main(String[] args) {
LocalTime localTime = LocalTime.now();
LocalTime localTime1 = LocalTime.of(21, 25, 52);
//between():静态方法,返回Duration对象,表示两个时间的间隔
Duration duration = Duration.between(localTime1, localTime);
System.out.println(duration);
System.out.println(duration.getSeconds());
System.out.println(duration.getNano());
LocalDateTime localDateTime = LocalDateTime.of(2021, 6, 15, 21, 25, 52);
LocalDateTime localDateTime1 = LocalDateTime.of(2020, 6, 12, 21, 25, 52);
Duration duration1 = Duration.between(localDateTime1, localDateTime);
System.out.println(duration1.toDays());
}
}
2.9、java.time.format.DateTimeFormatter日期时间格式化类
格式化或解析日期、时间,类似于SimpleDateFormat
实例化方式:
预定义的标准格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
本地化相关的格式。如:ofLocalizedDateTime(FormatStyle.LONG)
自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)
常用方法:
ofPattern(String pattern):静态方法,返回一个指定字符串格式的DateTimeFormatter
format(TemporalAccessor t):格式化一个日期、时间,返回字符串
parse(CharSequence text):将指定格式的字符序列解析为一个日期、时间
public class DateTest16 {
public static void main(String[] args) {
//自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)
DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
//格式化
String str4 = formatter3.format(LocalDateTime.now());
System.out.println(str4);
//解析
TemporalAccessor accessor = formatter3.parse("2021-06-18 10:21:18");
System.out.println(accessor);
}
}
2.10、java.time.temporal.TemporalAdjuster日期时间校正器类
TemporalAdjuster是Java 8引入的新的处理日期和时间API的一部分。
TemporalAdjuster是一个函数式接口,在TemporalAdjusters类中有许多预定义的实现。
该接口有一个名为adjustInto()的抽象方法,可以通过向其传递Temporal对象在其任何实现中调用它。
TemporalAdjuster允许我们执行复杂的日期操作。
比如,获得下个星期日,当月的最后一天或下一年的第一天的日期。
当然,我们也可以使用旧的java.util.Calendar来完成这样的操作。
public class DateTest17 {
public static void main(String[] args) {
//获取当前日期的下一个周日是哪天?
TemporalAdjuster temporalAdjuster = TemporalAdjusters.next(DayOfWeek.SUNDAY);
LocalDateTime localDateTime = LocalDateTime.now().with(temporalAdjuster);
System.out.println(localDateTime);
//获取下一个工作日是哪天?
LocalDate localDate = LocalDate.now().with(temporal -> {
LocalDate date = (LocalDate) temporal;
if (date.getDayOfWeek().equals(DayOfWeek.FRIDAY)) {
return date.plusDays(3);
} else if (date.getDayOfWeek().equals(DayOfWeek.SATURDAY)) {
return date.plusDays(2);
} else {
return date.plusDays(1);
}
});
System.out.println("下一个工作日是:" + localDate);
}
}
【奔跑吧!JAVA】有奖征文火热进行中:https://bbs.huaweicloud.com/blogs/265241
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)