Java常用类之JDK8中新日期时间API
新日期时间API的出现背景
JDK1.0中包含了一个java.util.Date类,但是它的大多数方法已经在JDK1.1引入了Calendar类之后被弃用了。而Calendar并不比Date好多少。它们存在的问题:
- 可变性:像日期和时间这样的类应该是不可变的
- 偏移性:Date中的年份是从1900开始的,而月份是从0开始的
- 格式化:格式化只对Date有用,Calendar则不行
- 此外,Calendar和Date也不是线程安全的;不能处理闰秒
新时间日期API
java.time-包含值对象的基础包
java.time.chrono-提供对不同的日历系统的访问
java.time.format-格式化和解析时间和日期
java.time.temporal-包括底层框架和扩展性
java.time.zone-包含时区支持的类
- LocalDate、LocalTime、LocalDateTime
- LocalDate、LocalTime、LocalDateTime类是其中比较重要的几个类,它们的实例是不可变的对象,分别表示使用ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的本地日期或时间,并不包含当前的时间信息,也不包含与时区相关的信息
- LocalDate代表ISO格式(yyyy-MM-dd)的日期,可以存储生日、纪念日等日期。
- LocalTime表示一个时间,而不是日期
- LocalDateTime是用来表示日期和时间的,这是一个最常用的类之一
注:ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示法,也就是公历
方法 | 描述 |
---|---|
now()/ * now(ZoneId zone) | 静态方法,根据当前时间创建对象/指定时区的对象 |
of() | 静态方法,根据指定日期/时间创建对象 |
getDayOfMonth()/getDayOfYear() | 获取月份天数(1-31)/获取年份天数(1-366) |
getDayOfWeek() | 获取星期几(返回一个DayOfWeek枚举值) |
getMonth() | 获取月份,返回一个Month枚举值 |
getMonthValue()/getYear() | 获得月份(1-12)/获得年份 |
getHour()/getMinute()/getSecond() | 获取当前对象对应的小时、分钟、秒 |
withDayOfMonth()/withDayOfYear()/withMonth()/withYear() | 将月份天数、年份天数、月份、年份修改为指定的值并返回新对象 |
plusDays()/plusWeeks()/plusMonths()/plusHours() | 向当前对象添加几天、几周、几个月、几年、几小时 |
minusMonths()/minusWeeks()/minusDays()/minusYears/minusHours() | 从当前对象减去几月、几周、几天、几年、几小时 |
/**
* @author jiangl
* @version 1.0
* @date 2021/4/20 10:46
*/
public class JDK8DateTimeTest {
/**
* LocalDate、LocalTime、LocalDateTime的使用
* 1.LocalDateTime相较于LocalDate、LocalTime,使用频率高
* 2.类似于Calendar
*/
@Test
public void test(){
//now():获取当前的日期、时间、日期+时间
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now();
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDate);
System.out.println(localTime);
System.out.println(localDateTime);
//of():
LocalDateTime localDateTime1 = LocalDateTime.of(2021,04,20,11,16);
System.out.println(localDateTime1);
//getXxx()
//获取当月的第几天
System.out.println(localDateTime1.getDayOfMonth());
//获取当周的第几天
System.out.println(localDateTime1.getDayOfWeek());
//获取当年的第几天
System.out.println(localDateTime1.getDayOfYear());
//获取月份
System.out.println(localDateTime1.getMonthValue());
//获取分钟
System.out.println(localDateTime1.getMinute());
//withXxx() 不可变性
LocalDateTime localDateTime2 = localDateTime1.withDayOfMonth(22);
System.out.println(localDateTime1);
System.out.println(localDateTime2);
//plusXxx()
LocalDateTime ldt = LocalDateTime.now();
LocalDateTime ldt2 = ldt.plusMonths(3);
System.out.println(ldt);
System.out.println(ldt2);
}
}
- 瞬时:Instant
- Instant:时间线上的一个瞬时点。这可能被用来记录应用程序中的事件时间戳。
- 在处理时间和日期的时候,我们通常会想到年,月,日,时,分,秒。然而,这只是时间的一个模型,是面向人类的。第二种通用模型是面向机器的,或者说是连续的。在此模型中,时间线中的一个点表示一个很大的数,这有利于计算机处理。在UNIX中,这个数从1970年开始,以秒为单位;同样的,在java中也是从1970年开始,但以毫秒为单温
- java.time包通过值类型Instant提供机器视图,不提供人类意义上的时间单位。Intant表示时间线上的一点,而不需要任何上下文信息,例如,时区。概念上讲,Instant只是简单的表示自1970年1月1日0时0分0秒(UTC)开始的秒数。因为java.time包是基于纳秒计算的,所以Instant的精度可以达到纳秒级。
- (1 ns = 10 ^-9s) 1秒 = 1000毫秒 = 10^6秒 = 10 ^ 9纳秒
方法 | 描述 |
---|---|
now() | 静态方法,返回默认UTC时区的Instant类的对象 |
ofEpochMilli(long ephochMilli) | 静态方法,返回1970-01-01 00:00:00基础上加上指定毫秒数之后的Instant类的对象 |
atOffset(ZoneOffset offset) | 结合即时的偏移来创建一个OffsetDateTime |
toEpochMilli() | 返回1970-01-01 00:00:00到当前时间的毫秒数,即为时间戳 |
时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年1月1日08时00分00秒)起至现在的总秒数
计算世界时间的主要标准有:
- UTC(Coordinated Universal Time)
- GMT(Greenwich Mean Time) 英国(欧洲)采用时间
- CST(Central Standard Time) 美国采用时间
@Test
public void test2(){
Instant now = Instant.now();
System.out.println(now);
//北京时间对应本初子午线时间差8小时
//添加时间偏移量
System.out.println(now.atOffset(ZoneOffset.ofHours(8)));
//获取1970年1月1日 00:00:00(UTC)开始的毫秒数
System.out.println(now.toEpochMilli());
//给定的毫秒数,获取Instant的实例
System.out.println(Instant.ofEpochMilli(1618895260287L));
}
- 格式化与解析日期或时间
- java.time.format.DateTimeFormatter类:该类提供了三种格式化方法:
- 预定义的标准格式。如:
- ISO_LOCAL_DATE_TIME;ISO_LOCALE_DATE;ISO_LOCAL_TIME
- 本地化相关格式。如:ofLocalizedDateTime(FormateStyle.LONG)\
- ofLocalizedDateTime()
- FomatStyle.LONG/FormatStyle.MEDIUM / FormatStyle.SHORT 适用于LocalDateTime
- ofLocalizedDate()
- FormatStyle.FULL / FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT : 适用于LocalDate
- ofLocalizedDateTime()
- 自定义格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss E”)
- 预定义的标准格式。如:
方法 | 描述 |
---|---|
ofPattern(String pattern) | 静态方法,返回一个指定字符串格式的DateTimeFormatter |
format(TemporalAccessor t) | 格式化一个日期、时间,返回字符串 |
parse(CharSequence text) | 将指定格式的字符序列解析为一个日期、时间 |
- 其他API
- ZoneId:该类中包含了所有的时区信息,一个时区的ID,如Europe/Pairs
- ZonedDateTime:一个在ISO-8601日历系统时区的日期时间,如2007-12-03T10:15:30——01:00 Europe/Paris。
- 其中每个时区都对应着ID,地区ID都为“{区域}/{城市}”的格式,例如:Asia/Shanghai等。
- Clock:使用时区提供对当前即时、日期和时间的访问时钟。
- 持续时间:Duration,用于计算两个“时间”间隔。
- 日期间隔:Period,用于计算两个“日期”间隔。
- TemporalAdjuster:时间校正器。有时我们可能需要获取例如:将日期调整到“下一个工作日”等操作
- TemporalAdjusters:该类通过静态方法(firstDayOfXxx()/lastDayOfXxx()/nextXxx())提供了大量的常用的TemporalAdjuster的实现。
ZoneId,ZoneDateTime:
/**
* 其他的时间API
*/
@Test
public void test4(){
//ZoneId:类中包含了所有的时区信息
//ZoneId的getAvailableZoneIds():获取所有的ZoneId
Set<String> zoneIds = ZoneId.getAvailableZoneIds();
for(String s : zoneIds){
System.out.println(s);
}
//ZoneId的of():获取指定时区的时间
LocalDateTime localDateTime = LocalDateTime.now(ZoneId.of("Europe/Monaco"));
System.out.println(localDateTime);
//ZoneDateTime:带时区的日期
//ZoneDateTime的now():获取本时区的ZoneDateTime()对象
ZonedDateTime now = ZonedDateTime.now();
System.out.println(now);
//ZoneDateTime的now(ZoneId id):获取指定时区的ZoneDateTime对象
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println(zonedDateTime);
}
Duration:
@Test
public void testDuration(){
//Duration:用于计算两个“时间”间隔,以秒和纳秒为基准
LocalTime now = LocalTime.now();
LocalTime of = LocalTime.of(15, 23, 32);
//between():静态方法,返回Duration对象,表示两个时间的间隔
Duration between = Duration.between(now, of);
System.out.println(between);
//相差多少秒
System.out.println(between.getSeconds());
//相差多少纳秒
System.out.println(between.getNano());
LocalDateTime of1 = LocalDateTime.of(2020, 6, 12, 15, 23, 32);
LocalDateTime of2 = LocalDateTime.of(2021, 6, 12, 15, 23, 32);
Duration between1 = Duration.between(of1, of2);
System.out.println(between1.toDays());
}
Period:
/**
* Period:用于计算两个“日期”间隔,以年,月,日衡量。
*/
@Test
public void testPeriod(){
LocalDate now = LocalDate.now();
LocalDate of = LocalDate.of(2020, 3, 18);
Period period = Period.between(now, of);
System.out.println(period);
System.out.println(period.getYears());
System.out.println(period.getMonths());
System.out.println(period.getDays());
Period period1 = period.withYears(2);
System.out.println(period1);
Temporal temporal = period1.addTo(of);
System.out.println(temporal);
}
TemporalAdjuster:
/**
* TemporalAdjuster:时间校正器
*/
@Test
public void testTemporalAdjuster(){
//获取当前日期的下一个周日是哪天?
TemporalAdjuster next = TemporalAdjusters.next(DayOfWeek.SUNDAY);
LocalDateTime with = LocalDateTime.now().with(next);
System.out.println(with);
//获取下一个工作日是哪天?
LocalDate with1 = LocalDate.now().with(new TemporalAdjuster() {
@Override
public Temporal adjustInto(Temporal 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("下一个工作日为:"+with1);
}
-
jdk8中心日期时间api与传统日期处理的转换
类 To遗留类 From遗留类 java.time.Instant与java.util.Date Date.from(instant) date.toInstant() java.time.Instant与java.sql.TimeStamp TimeStamp.form(instant) timestamp.toInstant() java.time.ZonedDateTime与java.util.GregorianCalendar GregorianCalendar.from(zonedDateTime) cal…toZonedDateTime() java.time.LocalDate与java.sql.Time Date.valueOf(localDate) cal.toLocalDate() java.time.LocalTime与java.sql.Time Date.valueOf(localTime) cal.toLocalTime() java.time.LocalDateTime与java.sql.TimeStamp TimeStamp.valueOf(localDateTime) timestamp.toLocalDateTime() java.time.ZoneId与java.util.TimeZone TimeZone.getTimeZone(id) timeZone.toZoneId() java.time.format.DateTimeFormatter与java.text.DateFormat formatter.toFormat() 无