(三)Java常用类之日期使用 | 【奔跑吧!JAVA】

举报
lwq1228 发表于 2021/06/18 22:55:41 2021/06/18
【摘要】 日期在Java中是一块非常复杂的内容,在Java8之前主要使用java.util.Date处理日期,该类是非线程安全的,在Java8中引入了LocalDate、LocalTime、LocalDateTime等很多新的日期处理类,解决了线程安全问题。

1、JDK8之前日期时间处理方式

1.1、java.lang.System类

System类提供的public static native long currentTimeMillis();用来返回当前时间与197011000秒之间以毫秒为单位的时间差,此方法主要适用于计算时间差。

计算世界时间的主要标准有:
	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时间点类

时间线上的一个瞬时点。概念上讲,它只是简单的表示自197011000秒(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

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。