前言:
发现很多开发人员做在时间相关的问题的时候,各有各的方法,然后对时间相关的处理,各种Java自带的时间相关类的知识面都不是很清楚,有时候看见他们在开发时候,都是一边使用到了,然后临时百度去处理时间相关的问题。
说个简单的,比如现在要问一首歌的时长,后台返回给你00:03:06
,然后你代码中要用到总秒数时长,这时候问你怎么把这个变成具体的秒数。在现有的项目中,我看这个的处理代码是这样的:
if (min.contains(":")) { | |
String[] items = min.split(":"); | |
duration += (Integer.valueOf(items[0]) * 60 * 60 * 1000 + Integer.valueOf(items[1]) * 60 * 1000 + Integer.valueOf(items[2]) * 1000); | |
} |
上面代码当然没有任何问题,但是我们其实可以用时间相关类来处理。
正文:
1. 时间获取
既然说到了时间相关知识,最主要的肯定先要获取到时间。
1.1 Date:
其实看脑图,就已经很详细了,而且Date大家应该熟悉的不要太熟悉了,所以不会超级详细说明,我们只挑几个点说一下:
构造函数:
Date date = new Date(); | |
// 使用 toString() 函数显示当前日期时间 | |
date.toString(); //Sat Aug 31 15:20:08 CST 2019 | |
Date date1 = new Date(1000); | |
//1970.01.01 00:00:00开始加上你填入的数值后的时间点 | |
date1.toString(); //Thu Jan 01 08:00:01 CST 1970 |
get/set函数:
Date date = new Date(); | |
//获取当前Date代表的时间距离1970.01.01 08:00:00的差值 | |
//'实际的Date代表的是1970.01.01 00:00:00的时间差,因为当前是东八区,所以获取到的是08:00:00' | |
date.getTime(); //1567576587763 | |
Date date1 = new Date(1000); | |
date1.getTime(); //1000 | |
Date date2 = new Date(); | |
date2.setTime(1000); | |
date2.getTime(); //1000 |
二个Date比较函数:
Date aaaaa = new Date(1000); | |
Date bbbbb = new Date(2000); | |
aaaaa.after(bbbbb);//false | |
aaaaa.before(bbbbb);//true | |
aaaaa.equals(bbbbb);//false | |
aaaaa.compareTo(bbbbb);//-1(a<b返回-1,a==b返回0,a>b返回1) |
1.2 Calendar:
我们知道了Date
可以代表时间值(因为有了Date
就可以获取距离1970-01-01 08:00:00 的差值,也就知道了当前Date
代表的时间)
所以Calendar
在获取时间的方法上,不仅提供了获取时间返回long
类型的方法,还提供了返回Date
对象的方法
获取时间:
Calendar cl = Calendar.getInstance(); | |
Date date = cl.getTime();//获取Date对象 | |
cl.getTimeInMillis();//直接获取long值 | |
date.getTime() 与 cl.getTimeInMillis()的结果是一样的 |
当然Calendar
也可以具体的拿年月日时分秒等具体某个想要的值:
比如获取当前时间的小时: | |
Calendar cl = Calendar.getInstance(); | |
//比如现在是下午四点,获取到的就 | |
cl.get(Calendar.HOUR_OF_DAY)); | |
是16 | |
//'注意一点,拿到的Mouth是从0开始的,比如现在是9月,你获取的是8' | |
cl.get(Calendar.MONTH); //8 |
具体的参数有很多,可以自己去选:
设置时间:
上面说了获取时间,设置时间也是一样的,可以直接设置long类型,也可以设置Date类型,也可以直接设置具体的年月日字段值。
public final void setTime(Date date) | |
public void setTimeInMillis(long millis) | |
public void set(int field, int value) | |
public final void set(int year, int month, int date) | |
public final void set(int year, int month, int date, int hourOfDay, int minute) | |
public final void set(int year, int month, int date, int hourOfDay, int minute,int second) |
二个Calendar对象比较: 完全可以参考前面的二个Date对象进行比较,这里也不细说了:
其实我们前面说的Date
和Calendar
都是大家很熟悉的类,用的也是最多的,但是因为使用方式不友好,所以后面java8之后,都是使用新的·Instant
和Localxxxx
系列用来替换Date
和Calendar
的类了。
1.3 Instant:
很多人说,Date
不是挺好用的,感觉够用了。假如我现在需要你获取当前时间,然后在该基础上加上6小时,再求时间,你就会发现有点不方便了。
Date dd1 = new Date(); | |
dd1.setTime(dd1.getTime()+6*60*60*1000); | |
//'当前有些人会说Date不是有个setHours()方法吗?但实际已经标记抛弃了' |
我们看下Instant
的用法:
Instant i = Instant.now(); | |
i.toString(); //2019-09-04T09:44:07.169Z | |
Instant i2 = i.plus(6,ChronoUnit.HOURS);//加了6个小时 | |
i2.toString(); //2019-09-04T15:44:07.169Z | |
//也可以通过Duration类辅助 ('Duration类后面会讲到') | |
Instant i3 = i.plus(Duration.ofHours(6)); | |
i3.toString(); //2019-09-04T15:44:07.169Z | |
//也可以通过TimeUnit辅助类('TimeUnit类后面会讲到') | |
Instant i4 = i.plusMillis(TimeUnit.HOURS.toMillis(6)); | |
i4.toString(); ////2019-09-04T15:44:07.169Z | |
//'减少则使用minus方法,使用方式同plus' |
二个Instant对象的相关比较方法,与Date一样:
这里主要讲一个until
方法:
Instant i = Instant.now(); | |
Instant i2 = i.plus(6,ChronoUnit.HOURS); | |
i2.until(i,ChronoUnit.HOURS); //-6 | |
i.until(i2,ChronoUnit.HOURS); //6 | |
'(i2.until(i,ChronoUnit.HOURS); | |
i2到i1,说明要回到以前,当然是要减少6个小时,反之亦然)' |
PS: Instant.now(); 拿到的时间是比我们当前中国时区慢8小时,大家要注意下
1.4 LocalXXXXX系列
Local系列主要有: LocalTime
, LocalDate
,LocalDateTime
从单纯的字面意思就可以看出来:LocalTime
是指时间(时分秒),LocalDate
是指日期(年月日),LocalDateTime
是整个完整日期(年-月-日-时-分-秒)
1.4.1 LocalDate :
基本的方法就如上面脑图,常用的方法也都有了。
这里提个点:
Calendar
获取的月份是从0
开始的,比如现在是9月份
,你获取到的数字是8
。但是localDate.getMonthValue()
获取到的是9
。更贴合实际。
1.4.2 LocalTime :
LocalTime
的方法也入上面脑图,常用的方法也都有了。
1.4.3 LocalDateTime :
LocalDateTime = LocalDate + LocalTime
LocalDate.atTime()方法添加时间 | |
返回的结果对象同时变为LocalDateTime对象 | |
LocalTime.atDate()方法添加日期 | |
返回的结果对象同时变为LocalDateTime对象 |
而LocalDateTime
的使用和LocalTime
和LocalDate
的使用方法基本的一样。
1.4.4 ZoneDateTime :
和LocalDateTime也基本相同,从字面意思看我们也知道是带有时区相关的:
LocalDateTime.now(); | |
//2019-09-05T22:49:06.369 | |
ZoneDateTime.now(); | |
//2019-09-05T22:49:06.371+08:00[Asia/Shanghai] |
我们可以看到当前的时区,其他方法使用方式也基本都一模一样。
2.时间格式化
前面我们已经说了怎么获取到时间。接下去我们讲时间和各种格式的字符串等各种相互转换。
- 但我们知道界面上我们想要显示的文字不同:
2018-08-07 09:12:12
,2018#08#07#09#12#12
各种方式,这个是时间转成字符串显示。 - 然后假如别人传给你
2018-08-07 09:12:12
,2018#08#07#09#12#12
,想要把字符串转换成时间对象。
2.1 DateFormat:
DateFormat
是日期/时间格式化子类的抽象类,它以与语言无关的方式格式化并解析日期或时间。日期/时间格式化子类(如SimpleDateFormat
)允许进行格式化(也就是日期 -> 文本)、解析(文本-> 日期)和标准化。将日期表示为 Date 对象,或者表示为从 GMT(格林尼治标准时间)1970 年 1 月 1 日 00:00:00这一刻开始的毫秒数。
2.1.1时间和字符串的互转:
DateFormat
可帮助进行格式化并解析任何语言环境的日期。对于月、星期,甚至日历格式(阴历和阳历),其代码可完全与语言环境的约定无关。
要格式化一个当前语言环境下的日期,可使用某个静态工厂方法:
myString = DateFormat.getDateInstance().format(myDate);
如果格式化多个日期,那么获取该格式并多次使用它是更为高效的做法,这样系统就不必多次获取有关环境语言和国家/地区约定的信息了。
DateFormat df = DateFormat.getDateInstance(); | |
for (int i = 0; i < myDate.length; ++i) { | |
output.println(df.format(myDate[i]) + "; "); | |
} |
要格式化不同语言环境的日期,可在 getDateInstance() 的调用中指定它。
DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, Locale.FRANCE);
还可使用 DateFormat
进行解析。
myDate = df.parse(myString);
2.1.2获取DateFormat对象:
使用getDateInstance
来获取该国家/地区的标准日期格式。另外还提供了一些其他静态工厂方法。使用 getTimeInstance
可获取该国家/地区的时间格式。使用 getDateTimeInstance
可获取日期和时间格式。可以将不同选项传入这些工厂方法,以控制结果的长度(从 SHORT
到 MEDIUM
到 LONG
再到 FULL
)。确切的结果取决于语言环境,但是通常:
SHORT 完全为数字,如 12.13.52 或 3:30pm | |
MEDIUM 较长,如 Jan 12, 1952 | |
LONG 更长,如 January 12, 1952 或 3:30:32pm | |
FULL 是完全指定,如 Tuesday、April 12、1952 AD 或 3:30:42pm PST。 |
如果愿意,还可以在格式上设置时区。如果想对格式化或解析施加更多的控制(或者给予用户更多的控制),可以尝试将从工厂方法所获取的 DateFormat 强制转换为 SimpleDateFormat。这适用于大多数国家/地区;只是要记住将其放入一个 try 代码块中,以防遇到特殊的格式。还可以使用借助 ParsePosition 和 FieldPosition 的解析和格式化方法形式来逐步地解析字符串的各部分。 对齐任意特定的字段,或者找出字符串在屏幕上的选择位置。 同步日期格式不是同步的。建议为每个线程创建独立的格式实例。如果多个线程同时访问一个格式,则它必须保持外部同步。
2.2 SimpleDateFormat:
SimpleDateFormat
是DateFormat
的子类,所以前面的DateFormat
的基本的知识介绍基本都是一模一样的。这里就不说明了。
这个类估计大家百分之99.9999都使用,并且知道怎么使用了。
下面这段代码,基本是使用率最高的:
Date date = new Date(); | |
String strDateFormat = "yyyy-MM-dd HH:mm:ss"; | |
SimpleDateFormat sdf = new SimpleDateFormat(strDateFormat); | |
//时间转换为字符串 | |
sdf.format(date); //2019-09-06 21:13:23 | |
String str = "2019-09-06 21:13:23"; | |
//字符串转换为时间 | |
Date date = sdf.parse(str); |
主要的不熟悉的反而不是方法的使用,而是格式的定义老是记不清楚:
字母 日期或时间元素 表示 示例 | |
G Era 标志符 Text AD | |
y 年 Year 1996; 96 | |
M 年中的月份 Month July; Jul; 07 | |
w 年中的周数 Number 27 | |
W 月份中的周数 Number 2 | |
D 年中的天数 Number 189 | |
d 月份中的天数 Number 10 | |
F 月份中的星期 Number 2 | |
E 星期中的天数 Text Tuesday; Tue | |
a Am/pm 标记 Text PM | |
H 一天中的小时数(0-23) Number 0 | |
k 一天中的小时数(1-24) Number 24 | |
K am/pm 中的小时数(0-11) Number 0 | |
h am/pm 中的小时数(1-12) Number 12 | |
m 小时中的分钟数 Number 30 | |
s 分钟中的秒数 Number 55 | |
S 毫秒数 Number 978 | |
z 时区 General time zone Pacific Standard Time; PST; GMT-08:00 | |
Z 时区 RFC 822 time zone -0800 |
2.3 DateTimeFormatter:
这个是Java8 后的推荐转换使用类。
2.3.1 字符串转换时间对象:
// 定义一个任意格式的日期时间字符串 | |
String str1 = "2014==04==12 01时06分09秒"; | |
// 根据需要解析的日期、时间字符串定义解析所用的格式器 | |
DateTimeFormatter fomatter1 = DateTimeFormatter.ofPattern("yyyy==MM==dd HH时mm分ss秒"); | |
// 执行解析 | |
LocalDateTime dt1 = LocalDateTime.parse(str1, fomatter1); | |
// ---下面代码再次解析另一个字符串--- | |
String str2 = "2014?$四月?$13 20小时"; | |
DateTimeFormatter fomatter2 = DateTimeFormatter.ofPattern("yyy?$MMM?$dd HH小时"); | |
LocalDateTime dt2 = LocalDateTime.parse(str2, fomatter2); |
这里的使用方式和SimpleDateFormat
基本一致。
2.3.2 :时间对象转换字符串:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy==MM==dd HH时mm分ss秒"); | |
//'1. 和SimpleDateFormat的使用方法一样,把时间对象作为参数传入' | |
formatter.format(LocalDateTime.now()); | |
//'2. 把DateTimeFormatter作为参数传入' | |
LocalDateTime.now().format(formatter); |
3.时间相关类
3.1 比较时间:
我们可以看到获取某二个日期直接差值的对象,主要是:年月日的Period
类和秒的Duration
类.
3.2 时间辅助类:
3.2.1 TimeUnit:
时间颗粒度转换 :
比如我想算N个小时M分钟有几秒,很多人可能是这么写的
N* 60 * 60 + M * 60; | |
其实有了TimeUnit
这个类,很多不同时间单位的相互转换非常方便。
TimeUnit.HOURS.toSeconds(N) + TimeUnit.MINUTES.toSeconds(M);
特别是换算成其他毫秒等,使用一般的乘法,那么多个0,很容易弄错,用TimeUnit就很方便了:
TimeUnit.HOURS.toMillis(N) + TimeUnit.MINUTES.toMillis(M); | |
//把3天转化成小时 | |
TimeUnit.HOURS.convert( 3 , TimeUnit.DAYS ); | |
//结果是:72 |
延时:
除了这个,TimeUnit
还可以用在线程Sleep:
一般人写线程休眠:
Thread.sleep( 5 * 1000 );
使用TimeUnit
:
TimeUnit.SECONDS.sleep( 5 );
还有timeJoin/timeWait
等,都是同理。
结语:
回到刚开始的问题,我们刚开始提的歌曲时长获取:
我们也可以通过这些自带的时间工具类(我随便举二个写法,当然还有其他写法:)
String str = "00:03:06"; | |
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss"); | |
LocalTime localTime = LocalTime.parse(str, formatter); | |
localTime.toSecondOfDay();//186 | |
String str1 = "00:00:00"; | |
LocalTime time1 = LocalTime.parse(str1); | |
String str2 = "00:03:06"; | |
LocalTime time2 = LocalTime.parse(str2); | |
Duration duration = Duration.between(time1,time2); | |
duration.getSeconds(); //186 |
又是很懒的不更新文章.........有错误的请指出哦。