Java开发笔记(四十三)更好用的本地日期时间
话说Java一连设计了两套时间工具,分别是日期类型Date,以及日历类型Calendar,按理说用在编码开发中绰绰有余了。然而随着Java的日益广泛使用,人们还是发现了它们的种种弊端。且不说先天不良的Date类型,单说后起之秀的Calendar类型,这个日历工具在实际开发中仍然存在以下毛病:
1、日历工具获取当前月份的时候,与Date一样都是从0开始计数,比如通过get方法获得的一月份数值为0;
2、日历工具获取当天是星期几的时候,星期日是排在最前面的,通过get方法获得的星期日数值为1,而星期一数值居然是2!
3、日历工具能够表达的最小时间单位是毫秒,使得时间精度不够高,难以用在更加精密的科学运算场合。
4、日历工具没有提供闰年的判断方法。
5、日历工具缺乏自己的格式化工具,居然还得借助于Date类型那边的格式化工具SimpleDateFormat,方能将日期时间按照指定格式输出为字符串。
总而言之,不管是Date还是Calendar,在解决复杂问题之时的编码都很别扭,故而每个Java工程基本要重新编写一个日期处理工具DateUtil,在新工具内部封装常见的日期处理操作,这样才能满足实际业务的开发要求。于是Date和Calendar两个难兄难弟从JDK1.1开始并肩作战,一路走到Java5、Java6乃至Java7,后来估摸着无可救药了,干爹Oracle一不做、二不休,终于在Java8推出了全新的日期时间类型,意图通过新类型一劳永逸治好Date和Calendar的沉疴宿疾。
全新的日期时间类型不单单是一个类型,而是一个家族,它的成员主要有LocalDate、LocalTime、LocalDateTime等等,接下来分别介绍这几个日期时间类型:
1、本地日期类型LocalDate
获取本地日期的实例很简单,调用该类型的now方法即可,并且顾名思义得到的是当前日期。通过本地日期获取年月日的数值,就是日常生活中的习惯数字,例如一月份对应的数值是1,十二月份对应的数值是12,星期一对应的数值是1,星期日对应的数值是7等等。此外,本地日期额外提供了几个常用的统计方法,包括:该日期所在的年份一共有多少天、该日期所在的月份一共有多少天、该日期所在的年份是否为闰年等。下面的代码便演示了如何从本地日期获取各种数值的例子:
// 获得本地日期的实例
LocalDate date = LocalDate.now();
System.out.println("date=" + date.toString());
// 获得该日期所在的年份
int year = date.getYear();
System.out.println("year=" + year);
// 获得该日期所在的月份。注意getMonthValue方法返回的是数字月份,而getMonth方法返回的是英文月份
int month = date.getMonthValue();
System.out.println("month=" + month + ", english month=" + date.getMonth());
// 获得该日期所在的日子
int dayOfMonth = date.getDayOfMonth();
System.out.println("dayOfMonth=" + dayOfMonth);
// 获得该日期在一年当中的序号
int dayOfYear = date.getDayOfYear();
System.out.println("dayOfYear=" + dayOfYear);
// 获得该日期是星期几。注意getDayOfWeek方法返回的是英文的星期几,后面跟着的getValue方法才返回数字的星期几
int dayOfWeek = date.getDayOfWeek().getValue();
System.out.println("dayOfWeek=" + dayOfWeek + ", english weekday=" + date.getDayOfWeek());
// 获得该日期所在的年份一共有多少天
int lengthOfYear = date.lengthOfYear();
System.out.println("lengthOfYear=" + lengthOfYear);
// 获得该日期所在的月份一共有多少天
int lengthOfMonth = date.lengthOfMonth();
System.out.println("lengthOfMonth=" + lengthOfMonth);
// 判断该日期所在的年份是否为闰年
boolean isLeapYear = date.isLeapYear();
System.out.println("isLeapYear=" + isLeapYear);
除了创建处于当前日期的本地实例,LocalDate还支持创建指定日期的本地实例,就像以下代码示范的那样:
// 构造一个指定年月日的日期实例
LocalDate dateManual = LocalDate.of(2018, 11, 22);
System.out.println("dateManual=" + dateManual.toString());
至于针对某个单位的数值,LocalDate也提供了专门的修改方法,例如以plus打头的系列方法用来增加日期数值,以minus打头的系列方法用来减少日期数值,以with打头的系列方法用来设置日期数值,这些日期修改的具体用法示例如下:
dateManual = dateManual.plusYears(0); // 增加若干年份
dateManual = dateManual.plusMonths(0); // 增加若干月份
dateManual = dateManual.plusDays(0); // 增加若干日子
dateManual = dateManual.plusWeeks(0); // 增加若干星期
dateManual = dateManual.minusYears(0); // 减少若干年份
dateManual = dateManual.minusMonths(0); // 减少若干月份
dateManual = dateManual.minusDays(0); // 减少若干日子
dateManual = dateManual.minusWeeks(0); // 减少若干星期
dateManual = dateManual.withYear(2000); // 设置指定的年份
dateManual = dateManual.withMonth(12); // 设置指定的月份
dateManual = dateManual.withDayOfYear(1); // 设置当年的日子
dateManual = dateManual.withDayOfMonth(1); // 设置当月的日子
此外,作为一种日期类型,LocalDate一如既往地支持判断两个日期实例的早晚关系,比如equals方法用于判断两个日期是否相等,isBefore方法用于判断A日期是否在B日期之前,isAfter方法用于判断A日期是否在B日期之后等。具体的本地日期校验代码如下所示:
// 判断两个日期是否相等
boolean equalsDate = date.equals(dateManual);
System.out.println("equalsDate=" + equalsDate);
// 判断A日期是否在B日期之前
boolean isBeforeDate = date.isBefore(dateManual);
System.out.println("isBeforeDate=" + isBeforeDate);
// 判断A日期是否在B日期之后
boolean isAfterDate = date.isAfter(dateManual);
System.out.println("isAfterDate=" + isAfterDate);
// 判断A日期是否与B日期相等
boolean isEqualDate = date.isEqual(dateManual);
System.out.println("isEqualDate=" + isEqualDate);
2、本地时间类型LocalTime
前面介绍的LocalDate只能操作年月日,若要操作时分秒则需通过本地时间类型LocalTime。获取本地时间的实例依然要调用该类型的now方法,接着就能通过该实例分别获取对应的时分秒乃至纳秒(一秒的十亿分之一),下面便演示了如何调用LocalTime的基本方法:
// 获得本地时间的实例
LocalTime time = LocalTime.now();
System.out.println("time=" + time.toString());
// 获得该时间所在的时钟
int hour = time.getHour();
System.out.println("hour=" + hour);
// 获得该时间所在的分钟
int minute = time.getMinute();
System.out.println("minute=" + minute);
// 获得该时间所在的秒钟
int second = time.getSecond();
System.out.println("second=" + second);
// 获得该时间秒钟后面的纳秒单位。一秒等于一千毫秒,一毫秒等于一千微秒,一微秒等于一千纳秒,算下来一秒等于十亿纳秒
int nano = time.getNano();
System.out.println("nano=" + nano);
如同本地日期LocalDate那样,LocalTime也允许创建指定时分秒的时间实例,还支持单独修改时钟、分钟、秒钟和纳秒。当然修改时间的途径包括plus系列方法、minus系列方法、with系列方法等等,它们的调用方式示例如下:
// 构造一个指定时分秒的时间实例
LocalTime timeManual = LocalTime.of(14, 30, 25);
System.out.println("timeManual=" + timeManual.toString());
timeManual = timeManual.plusHours(0); // 增加若干时钟
timeManual = timeManual.plusMinutes(0); // 增加若干分钟
timeManual = timeManual.plusSeconds(0); // 增加若干秒钟
timeManual = timeManual.plusNanos(0); // 增加若干纳秒
timeManual = timeManual.minusHours(0); // 减少若干时钟
timeManual = timeManual.minusMinutes(0); // 减少若干分钟
timeManual = timeManual.minusSeconds(0); // 减少若干秒钟
timeManual = timeManual.minusNanos(0); // 减少若干纳秒
timeManual = timeManual.withHour(0); // 设置指定的时钟
timeManual = timeManual.withMinute(0); // 设置指定的分钟
timeManual = timeManual.withSecond(0); // 设置指定的秒钟
timeManual = timeManual.withNano(0); // 设置指定的纳秒
另外,LocalTime依然提供了equals、isBefore、isAfter等方法用于判断两个时间的先后关系,具体的方法调用如下所示:
// 判断两个时间是否相等
boolean equalsTime = time.equals(timeManual);
System.out.println("equalsTime=" + equalsTime);
// 判断A时间是否在B时间之前
boolean isBeforeTime = time.isBefore(timeManual);
System.out.println("isBeforeTime=" + isBeforeTime);
// 判断A时间是否在B时间之后
boolean isAfterTime = time.isAfter(timeManual);
System.out.println("isAfterTime=" + isAfterTime);
3、本地日期时间类型LocalDateTime
现在有了LocalDate专门处理年月日,又有了LocalTime专门处理时分秒,还需要一种类型能够同时处理年月日和时分秒,它就是本地日期时间类型LocalDateTime。LocalDateTime基本等价于LocalDateTime与LocalTime的合集,它同时拥有二者的绝大部分方法,故这里不再赘述。下面是创建该类型实例的代码片段,读者可参考之前LocalDateTime与LocalTime的调用代码,尝试补齐LocalDateTime的方法调用过程。
// 演示LocalDateTime的各种方法
private static void showLocalDateTime() {
// 获得本地日期时间的实例
LocalDateTime datetime = LocalDateTime.now();
System.out.println("datetime=" + datetime.toString());
// LocalDateTime的方法是LocalDate与LocalTime的合集,
// 也就是说LocalDate与LocalTime的大部分方法可以直接拿来给LocalDateTime使用,
// 因而下面不再演示LocalDateTime的详细方法如何调用了。
// 注意LocalDateTime不提供lengthOfYear、lengthOfMonth、isLeapYear这三个方法。
}
更多Java技术文章参见《Java开发笔记(序)章节目录》
Java开发笔记(四十三)更好用的本地日期时间的更多相关文章
- Java开发笔记(十三)利用关系运算符比较大小
前面在<Java开发笔记(九)赋值运算符及其演化>中提到,Java编程中的等号“=”表示赋值操作,并非数学上的等式涵义.Java通过等式符号“==”表示左右两边相等,对应数学的等号“=”: ...
- Java开发笔记(序)章节目录
现将本博客的Java学习文章整理成以下笔记目录,方便查阅. 第一章 初识JavaJava开发笔记(一)第一个Java程序Java开发笔记(二)Java工程的帝国区划Java开发笔记(三)Java帝国的 ...
- Java开发笔记(八十三)利用注解技术检查空指针
注解属于比较高级的Java开发技术,前面介绍的内置注解专用于编译器检查代码,另外一些注解则由各大框架定义与调用,像Web开发常见的Spring框架.Mybatis框架,Android开发常见的Butt ...
- Java开发笔记(二十三)数组工具Arrays
数组作为一种组合形式的数据类型,必然要求提供一些处理数组的简便办法,包括数组比较.数组复制.数组排序等等.为此Java专门设计了Arrays工具,该工具包含了几个常用方法,方便程序员对数组进行加工操作 ...
- Java开发笔记(四十五)成员属性与成员方法
前面介绍了许多数据类型,除了基本类型如整型int.双精度型double.布尔型boolean之外,还有高级一些的如包装整型Integer.字符串类型String.本地日期类型LocalDate等等,那 ...
- Java开发笔记(九十四)文件通道的性能优势
前面介绍了字节缓存的一堆概念,可能有的朋友还来不及消化,虽然文件通道的用法比起传统I/O有所简化,可是平白多了个操控繁琐的字节缓存,分明比较传统I/O更加复杂了.尽管字节缓存享有缓存方面的性能优势,但 ...
- Java开发笔记(三十四)字符串的赋值及类型转换
不管是基本的char字符型,还是包装字符类型Character,它们的每个变量只能存放一个字符,无法满足对一串字符的加工.为了能够直接操作一连串的字符,Java设计了专门的字符串类型String,该类 ...
- Java开发笔记(四十)日期与字符串的互相转换
前面介绍了如何通过Date工具获取各个时间数值,但是用户更喜欢形如“2018-11-24 23:04:18”这种结构清晰.简洁明了的字符串,而非啰里八唆依次汇报每个时间单位及其数值的描述.既然日期时间 ...
- Java开发笔记(四十二)日历工具的常见应用
前面介绍了日历工具Calendar的基本用法,乍看起来Calendar与Date两个半斤八两,似乎没有多大区别,那又何苦庸人自扰鼓捣一个新玩意呢?显然这样小瞧了Calendar,其实它的作用大着呢,接 ...
随机推荐
- Python连接MySQL数据库之pymysql模块使用
安装PyMySQL pip install pymysql PyMySQL介绍 PyMySQL是在python3.x版本中用于连接MySQL服务器的一个库,2中则使用mysqldb. Django中也 ...
- 【RL-TCPnet网络教程】第26章 RL-TCPnet之DHCP应用
第26章 RL-TCPnet之DHCP应用 本章节为大家讲解RL-TCPnet的DHCP应用,学习本章节前,务必要优先学习第25章的DHCP基础知识.有了这些基础知识之后,再搞本章节会有事半功 ...
- 【从零开始搭建自己的.NET Core Api框架】(一)创建项目并集成swagger:1.1 创建
系列目录 一. 创建项目并集成swagger 1.1 创建 1.2 完善 二. 搭建项目整体架构 三. 集成轻量级ORM框架——SqlSugar 3.1 搭建环境 3.2 实战篇:利用SqlSuga ...
- [Swift]LeetCode219. 存在重复元素 II | Contains Duplicate II
Given an array of integers and an integer k, find out whether there are two distinct indices i and j ...
- Redis面试题
1.谈谈Redis的主从复制流程 有几个重点:主节点负责写,从节点负责读,slave node 主要用来进行横向扩容,做读写分离,扩容的 slave node 可以提高读的吞吐量.必须开启 maste ...
- Xapian使用入门
关键字:搜索引擎.Xapian 一篇拖了两三年的入门总结文章,今天发出来,一方面是自己的总结,另一方面是给自己和他人的备忘.读者需要对搜索引擎有初步了解,譬如了解倒排.term.doc.相似度打分等概 ...
- Python——day14 三目运算、推导式、递归、匿名、内置函数
一.三目(元)运算符 定义:就是 if...else...语法糖前提:简化if...else...结构,且两个分支有且只有一条语句注:三元运算符的结果不一定要与条件直接性关系 cmd = input ...
- BBS论坛(三十三)
33.celery实现邮件异步发送 (1)task.py pip install celery redis from celery import Celery from flask import Fl ...
- 手把手的教你安装PyCharm --Pycharm安装详细教程(一)(非常详细,非常实用)
简介 Jetbrains家族和Pycharm版本划分: pycharm是Jetbrains家族中的一个明星产品,Jetbrains开发了许多好用的编辑器,包括Java编辑器(IntelliJ IDEA ...
- .NET Core玩转机器学习
最近在搞机器学习,目前国内没有什么关于ML.NET的教程,官方都是一大堆英文,经过了我的努力,找到了Relax Development大哥的博客,有关于ML.NET的内容 原文地址:https://w ...