第四章 新的日期和时间API

一、时间线
在历史上,基本的时间单元‘秒’来自于地球围绕其轴心的自转。地球完成一次自转需要24小时或者86400秒。
Java日期和时间API规范要求Java使用如下时标:
  • 每天都有86400秒
  • 每天正午与官方时间准确匹配
  • 其他时间也要以一种精确定义的方式与其紧密匹配
1.在Java中,一个 Instant 对象表示时间轴上的一个点(绝对时间),原点(元年)被规定为1970年1月1日的午夜。从原点开始,时间按照每天86400秒进行计算。向前向后分别以纳秒为单位。Instant的最小值( Instant . MIN )可以回退到10亿年前之久,最大值( Instant . MAX )表示1000000000年的12月31日
  • Instant.now():返回当前的瞬时点
  • Duration.between(start,end):计算两个瞬时点之间的时间距离
--------------------------------------------------------------------------------------------------------------------
Instant start= Instant . now() ;
Thread. sleep (1000);
Instant end= Instant . now() ;
Duration timeElapsed= Duration . between(start,end) ;
long millis = timeElapsed. toMillis() ;
--------------------------------------------------------------------------------------------------------------------
2.一个Duration对象表示两个瞬时点之间的时间量,可以通过调用 toNanos toMillis toSeconds toMinutes toHours 或者 toDays 方法,得到以各种时间单位来表示的 Duration 对象
Duration 对象在内部存储上需要多个long值,秒钟的值由一个long值保存,而纳秒的值由另一个int保存,大概300年的纳秒值才会导致long值溢出
3.时间 Instant Duration 的数学操作
方法
描述
plus,minus
对当前Instant或者Duration添加或减少一段时间
plusNanos,plusMillis,
plusSeconds,plusMinutes,
plusHours,plusDays
根据指定的时间单位,对当前Instant或者Duration添加一段时间

minusNanos,minusMillis,
minusSeconds,minusMinutes,
minusHours,minusDays
根据指定的时间单位,对当前Instant或者Duration减少一段时间
multipliedBy,dividedBy
返回当前Duration与指定long值相乘或相除得到的一段时间,注意
这只能用于Duration不能用于Instant
isZero,isNegativ
检查Duration是否为0或负数
例子:检查某个算法是否比另一个算法至少快十倍
--------------------------------------------------------------------------------------------------------------------
Duration timeElapsed2= Duration . between(start2,end2) ;
boolean overTenTimesFaster=
timeElapsed. multipliedBy (10). minus (timeElapsed2). isNegative ();
--------------------------------------------------------------------------------------------------------------------
4. Instant Duration 类都是不可变的,他们的所有方法,例如 multipliedBy 或者 minus 都会返回一个新的实例

二、本地日期
在新的JavaAPI中,有两种人类时间本地日期/时间和带时区的时间,例如
“June 14,1903”、“July 16,1969,09:32:00 EDT”,有许多计算是不需要时区的,并且在某些情况下,考虑时区可能会导致错误的结果,API设计者们不推荐使用带时区的时间,生日、假期、会议时间等,最好都用本地日期或事件来表示,除非真的希望表示绝对的瞬时点
1. LocalDate 是一个带有年份、月份、当月天数的日期,要创建一个 LocalDate 可以使用静态方法 now of
--------------------------------------------------------------------------------------------------------------------
LocalDate today= LocalDate . now() ;
LocalDate alonzosBirthday= LocalDate . of (1903,6,14);
alonzosBirthday= LocalDate . of (1903,Month.JUNE,14);
--------------------------------------------------------------------------------------------------------------------
2.与 Date 不同, LocalDate 使用与正常生活中一样的数字来表示月份,即1表示1月份,除此之外还可以使用Month枚举
3.LocalDate常用方法
方法
描述
now,of
静态方法,根据当前时间或指定的年、月、日来创建一个LocalDate对象
plusDays,plusWeeks,
plusMonths,plusYears
向当前LocalDate对象添加几天、几周、几个月或者几年
minusDays,minusWeeks,
minusMonths,minusYears
从当前LocalDate对象中减去几天、几周、几个月或者几年
plus,minus
添加或减少一个Duration或Period
withDayOfMonth
withDayOfYear
withMonth,withYear
将月份天数、年份天数、月份、年份修改为指定的值,并返回一个新的
LocalDate对象
getDayOfMonth
获得月份天数(1~31)
getDayOfYear
获得年份天数(1~366)
getDayWeek
获得星期几(返回一个DayOfWeek的枚举值)
getMonth,getMonthValue
获得月份,或者为一个Month枚举的值,或者是1~12之间的一个数字
getYear
获得年份,-999999999-999999999之间
Until
获得两个日期之间的Period对象,或者指定ChronoUnits数字
isBefore,isAfter
比较两个LocalDate
isLeapYear
如果当年为闰年,即当年的年份可以被4或400整除,但不能被100整除,
则返回true,该算法适用于以前的所有年份,即使从历史角度看并不准确
例子1
--------------------------------------------------------------------------------------------------------------------
LocalDate programmersDay= LocalDate . of (2014,1,1). plusDays (255);
--------------------------------------------------------------------------------------------------------------------
例子2
--------------------------------------------------------------------------------------------------------------------
independenceDay. until (christmas); //返回5个月21天
independenceDay. until (christmas, ChronoUnit . DAYS ); //返回174天
--------------------------------------------------------------------------------------------------------------------
例子3
--------------------------------------------------------------------------------------------------------------------
LocalDate . of (1900,1,1). getDayOfWeek() . getValue()
--------------------------------------------------------------------------------------------------------------------
4.两个瞬时点之间的距离时一个持续时间 Duration ,而对于本地日期,对应的对象就是时段 Period ,表示一段逝去的年、月或日。可以通过birthday. plus ( Period . ofYears (1))或者birthday. plusYears (1)来获取下一年的生日日期,但如果时闰年,birthday. plus ( Duration . ofDays (365))会导致错误的结果
5. DayOfWeek 枚举提供了一些方便的方法 plus minus ,用来计算模为7的星期几,例如:DayOfWeek.SATURDAY. plus (3)会返回DayOfWeek.TUESDAY
6.除了 LocalDate ,Java8中还提供了 MonthDay YearMonth Year 类来描述部分日期,例如 MonthDay 可以用来表示12月25日

三、日期校正器
1.编写代码时候,经常计算例如"每月的第一个周二"这样的日期。 TemporalAdjusters 类提供了许多静态方法来进行常用的校正。可以将一个校正方法的结果传递给 with 方法,与往常一样, with 方法会返回一个新的 LocalDate 对象,而不会修改原有的对象
--------------------------------------------------------------------------------------------------------------------
LocalDate firstTuesday= LocalDate . of (year,month,1)
. with ( TemporalAdjusters . nextOrSame ( DayOfWeek . TUESDAY ));
--------------------------------------------------------------------------------------------------------------------
2.TemporalAdjusters类中的日期校正方法
方法
描述
next(weekday),previous(weekday)
指定工作日的前一天或后一天
nextOrSame(weekday)
previousOrSame(weekday)
从指定的日期开始,指定工作日的前一天或
后一天
dayOfWeekInMonth(n,weekday)
某月中的第n个工作日(weekday所指定)
lastInMonth(weekday)
某月中的最后一个工作日(weekday所指定)
firstDayOfMonth(),firstDayOfNextMonth()
firstDayOfNextYear(),lastDayOfMonth()
lastDayOfPreviousMonth(),lastDayOfYear()
 
3.可以通过 TemporalAdjuster 接口来实现自己的校正器
--------------------------------------------------------------------------------------------------------------------
TemporalAdjuster NEXT_WORKDAY=w->{
LocalDate result=( LocalDate )w;
do{
result=result. plusDays (1);
}while( result . getDayOfWeek() . getValue() >=6);
return result;
}
LocalDate backToWork=today. with (NEXT_WORKDAY);
--------------------------------------------------------------------------------------------------------------------
在本例中,lambda表达式的参数类型为 Temporal ,必须被强制转换成 LocalDate 对象,我们可以通过 ofDateAdjuster 方法以及一个 UnaryOperator <LocalDate>的lambda表达式来避免强制转换
--------------------------------------------------------------------------------------------------------------------
TemporalAdjuster NEXT_WORKDAY= TemporalAdjusters . ofDateAdjuster (w->{
LocalDate result=w;
do{
result=result. plusDays (1);
}while( result . getDayOfWeek() . getValue() >=6);
return result;
});
--------------------------------------------------------------------------------------------------------------------

四、本地时间
1. LocalTime 表示一天中的某个时间,例如15:30:00,其实例可以通过 now 或者 of 方法来创建
--------------------------------------------------------------------------------------------------------------------
LocalTime rightNow= LocalTime . now ();
LocalTime bedTime= LocalTime . of (22,30);
--------------------------------------------------------------------------------------------------------------------
2.LocalTime方法
方法
描述
now,of
静态方法,根据当前时间或者指定时间创建实例
plusHours,plusMinutes
plusSeconds,plusNanos
向当前LocalTime对象添加几个小时、几分钟、几秒或者
几微秒
minusHours,minusMinutes
minusSeconds,minusNanos
从当前LocalTime对象中减去几个小时、几分钟、几秒或
者几微妙
plus,minus
添加或减少一个Duration
withHour,withMinute
withSecond,withNano
将小时、分钟、秒钟、微秒修改为指定的值,并返回一个新的
LocalTime对象
getHour,getMinute
getSecond,getNano
获得当前LocalTime的小时、分钟、秒钟及微秒值
toSecondOfDay,toNanoOfDay
返回午夜时间与当前LocalTime之间相隔的秒钟数或微秒
isBefore,isAfter
比较两个LocalTime
3. LocalTime 本身并不关心是AM还是PM,而是交给格式化程序来做这件事
4. LocalDatetime 类表示一个日期和时间,该类适合用来存储确定时区中的某个时间点,例如某一次具体的课程或者活动安排。但是如果需要进行跨夏令时的时间计算,或者需要处理的用户处于不同的时区中,应该使用 ZonedDateTime

五、带时区的时间
1.因特网编号管理局(IANA)维护着一份全球所有已知时区的数据库,每年会更新几次,这些更新主要处理夏令时规则的改变,Java就使用了IANA数据库。每个时区都有一个ID,例如America/New_York或者Europe/Berlin,想获取素有可用的时区,可以调用
ZoneId . getAvailableIds
2.更具指定的时区ID,静态方法 ZoneId . of (id)会返回一个 ZoneId 对象,可以通过local. atZone (zoneId)将一个 LocalDateTime 对象转换成一个 ZonedDateTime 对象,或者通过调用静态方法 ZonedDateTime . of (year,month,day,hour,minute,second,nano, zoneId )
来创建一个 ZonedDateTime 对象
--------------------------------------------------------------------------------------------------------------------
ZoneDateTime apollo11launch=
ZonedDateTime . of (1969,7,16,9,32,0,0, ZoneId . of ("America/New_York"));
--------------------------------------------------------------------------------------------------------------------
3.可以调用apollo11launch. toInstant() 来获得对应的 Instant 对象,也可以通过调用
instant. atZone(zonedId) 将一个 Instant 对象转换成一个指定时区的 ZonedDateTime 对象
4.ZonedDateTime的方法
方法
描述
now,of,ofInstant
静态方法,根据当前时间或指定的年、月、
日、分、秒、微秒(或者一个LocalDate、
LocalTime对象)和ZonedId,或者一个
Instant对象和ZoneId创建实例
plusDays,plusWeeks
plusMonths,plusYears
plusHours,plusMinutes
plusSeconds,plusNanos
向当前ZonedDateTime对象添加相应单位
的时间
minusDays,minusWeeks
minusMonths,minusYears
minusHours,minusMinutes
minusSecond,minusNanos
从当前ZonedDateTime对象中减去相应单位
的时间
plus,minus
添加或减少一个Duration或者Period
withDayOfMonth,withDayOfYear
withMonth,withYear,withHour
withMinute,withSecond,withNano
将相应单位的时间改为指定的值,并返回
一个新的ZonedDateTime对象
withZoneSameInstant
withZoneSameLocal
返回指定时区中的一个新ZonedDateTime对
象,它可以表示相同的瞬时点或者本地时间
getDayOfMonth
获得月份天数
getDayOfYear
获得年份天数
getDayOfWeek
获得星期几(返回一个DayOfWeek的枚举值)
getMonth,getMonthValue
获得月份,或者为一个Month枚举的值,或
者为1~12之间的数字
getYear
获得年份
getHour,getMinute
getSecond,getNano
获得ZonedDatetime对象的小时、分钟、秒钟
或者微秒数
getOffset
获得与UTC之间的时差,返回一个
ZoneOffset对象,时差在-12:00到+14:00
之间,会根据夏令时发生改变
toLocaldate,toLocalTime
toInstant
返回本地日期、本地时间、瞬时点
isBefore,isAfter
比较两个ZonedDateTime
注:UTC表示"世界协调时",是格林威治皇家天文台的时间
5.当调整一个跨夏令时的日期时,不要添加7天的Duration对象,而应该使用Period类,否则无法处理夏令时
--------------------------------------------------------------------------------------------------------------------
ZonedDateTime nextMeeting=meeting. plus ( Duration . ofDays (7)); //不能处理夏令时
ZonedDateTime nextMeeting=meeting. plus ( Period . ofDays (7));
--------------------------------------------------------------------------------------------------------------------

六、格式化和解析
DateTimeFormatter 类提供了三种格式化方法来打印日期/时间:
  • 预定义的标准格式
  • 语言环境相关的格式
  • 自定义的格式
标准格式主要用于机器可读的时间戳如:1969-07-16-05:00,语言相关的格式是为了让人能够读懂日期和时间,这里只简单描述语言相关的格式。
DateTimeFormatter 类用来代替 DateFormat ,如果出于向后兼容的考虑,需要一个 DateFormat 的实例,可以通过调用 DateTimeFormatter 实例的 toFormat() 方法来维护
1.Java8对日期和时间各提供了4种风格,SHORT、MEDIUM、LONG和FULL
风格
日期
时间
SHORT
7/16/69
9:32 AM
MEDIUM
Jul 16,1969
9:32:00 AM
LONG
July 16,1969
9:32:00 AM EDT
FULL
Wednesday,July 16,1969
9:32:00 AM EDT
可以通过静态方法 ofLocalizedDate ofLocalizedTime ofLocalizedDateTime 来创建这类格式
--------------------------------------------------------------------------------------------------------------------
DateTimeFormatter formatter=
DateTimeFormatter . ofLocalizedDateTime ( FormatStyle . LONG );
String formatted=formatter. format (apollo11launch);
--------------------------------------------------------------------------------------------------------------------
如果要更改其他的语言环境,只需要使用 withLocale
--------------------------------------------------------------------------------------------------------------------
formatted=formatter. withLocale (Locale.FRENCH). formar (apollo11launch);
--------------------------------------------------------------------------------------------------------------------
2.可以通过 ofPattern() 方法来自定义日期的格式
--------------------------------------------------------------------------------------------------------------------
formatted= DateTimeFormatter . ofPattern ("E yyyy-MM-dd HH:mm");
//Wed 1969-07-16 09:32
--------------------------------------------------------------------------------------------------------------------

七、与遗留代码互操作
Instant <===>java.util.Date
Date. from(instant)
date. toInstant()
ZonedDateTime<===>java.util.GregorianCalendar
GregorianCalendar. from(zonedDateTime)
cal. toZonedDateTime()
Instant<===>java.sql.Timestamp
Timestamp. from(instant)
timestamp. toInstant()
LocalDateTime<===>java.sql.Timestamp
Timestamp. valueOf(localDateTime)
timeStamp. toLocalDateTime()
LocalDate<===>java.sql.Time
Date. valueOf(localDate)
date. toLocalDate()
LocalTime<===>java.sql.Time
Time. valueOf(localTime)
date. toLocalDate()
DateTimeFormatter<===>java.text.DateFormat
formatter. toFormat()
java.util.TimeZone<===>ZoneId
Timezone. getTimeZone(id)
timeZone. toZoneId()
java.nio.file.attribute.FileTime<===>Instant
FileTime. from(instant)
fileTime. toInstant()



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值