转:http://blog.csdn.net/chenleixing/article/details/44408875
转:https://segmentfault.com/q/1010000007862493?_ea=1478023
转:https://zhuanlan.zhihu.com/p/28133858
现有API存在的问题:
- 线程安全: Date和Calendar不是线程安全的,你需要编写额外的代码处理线程安全问题
- API设计和易用性: 由于Date和Calendar的设计不当你无法完成日常的日期操作
- ZonedDate和Time: 你必须编写额外的逻辑处理时区和那些旧的逻辑
好在JSR 310规范中为Java8添加了新的API,
在java.time包中,新的API纠正了过去的缺陷
新的日期API
ZoneId: 时区ID,用来确定Instant和LocalDateTime互相转换的规则
Instant: 用来表示时间线上的一个点
LocalDate: 表示没有时区的日期, LocalDate是不可变并且线程安全的
LocalTime: 表示没有时区的时间, LocalTime是不可变并且线程安全的
LocalDateTime: 表示没有时区的日期时间, LocalDateTime是不可变并且线程安全的
Clock: 用于访问当前时刻、日期、时间,用到时区
Duration: 用秒和纳秒表示时间的数量
最常用的就是LocalDate、LocalTime、LocalDateTime了,从它们的名字就可以看出是操作日期
和时间的。这些类是主要用于当时区不需要显式地指定的上下文。在本章节中我们将讨论最常用的api。
LocalDate:
// 根据字符串取:
LocalDate localDate= LocalDate.parse("2014-02-28"); // 严格按照ISO yyyy-MM-dd验证,02写成2都不行,当然也有一个重载方法允许自己定义格式
// 获取当天的日期
LocalDate today = LocalDate.now(); System.out.println("Today's Local date : " + today);
//获取当前的年月日
LocalDate today = LocalDate.now();
int year = today.getYear();
int month = today.getMonthValue();
int day = today.getDayOfMonth();
System.out.printf("Year : %d Month : %d day : %d \t %n", year, month, day);
Output
Today's Local date : 2014-01-14
Year : 2014 Month : 1 day : 14
// 获取某个特定的日期
LocalDate dateOfBirth = LocalDate.of(2010, 01, 14);
System.out.println("Your Date of birth is : " + dateOfBirth);
Output : Your Date of birth is : 2010-01-14
// 取本月第1天:
LocalDate firstDayOfThisMonth = localDate.with(TemporalAdjusters.firstDayOfMonth());
// 取本月第2天:
LocalDate secondDayOfThisMonth = localDate.withDayOfMonth(2);
// 取本月最后一天
LocalDate lastDayOfThisMonth = localDate.with(TemporalAdjusters.lastDayOfMonth());
// 取当前时间的第一个周一
LocalDate firstMondayOfThisTime = LocalDate.parse("2017-01-01").with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY)); // 2017-01-02
// 取当前时间的前一天
LocalDate beforeDayOfThisTime = LocalDate.parse("2017-01-01").minusDays(1);
// 取当前时间的后一天
LocalDate afterDayOfThisTime = LocalDate.parse("2017-01-01").plusDays(1);
//Date转LocalDate
Date date = new Date();
LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
//LocalDate 转 Date
LocalDateTime localDateTime = LocalDateTime.now();
Date date = Date.from(localDateTime.toInstant(ZoneOffset.UTC));
//检查闰年
if(today.isLeapYear()){
System.out.println("This year is Leap year");
}else {
System.out.println("2014 is not a Leap year");
}
Output: 2014 is not a Leap year
//返回两个日期之间的区间并以字符串集合方式返回
public static List collectLocalDates(String timeStart, String timeEnd){
LocalDate start=LocalDate.parse(timeStart);LocalDate end=LocalDate.parse(timeEnd);
// 用起始时间作为流的源头,按照每次加一天的方式创建一个无限流
return Stream.iterate(start, localDate -> localDate.plusDays(1))
// 截断无限流,长度为起始时间和结束时间的差+1个
.limit(ChronoUnit.DAYS.between(start, end) + 1)
// 由于最后要的是字符串,所以map转换一下
.map(LocalDate::toString)
// 把流收集为List
.collect(Collectors.toList());
}
====================================LocalDate API==================================
getYear() int 获取当前日期的年份
getMonth() Month 获取当前日期的月份对象
getMonthValue() int 获取当前日期是第几月
getDayOfWeek() DayOfWeek 表示该对象表示的日期是星期几
getDayOfMonth() int 表示该对象表示的日期是这个月第几天
getDayOfYear() int 表示该对象表示的日期是今年第几天
withYear(int year) LocalDate 修改当前对象的年份
withMonth(int month) LocalDate 修改当前对象的月份
withDayOfMonth(int dayOfMonth) LocalDate 修改当前对象在当月的日期
isLeapYear() boolean 是否是闰年
lengthOfMonth() int 这个月有多少天
lengthOfYear() int 该对象表示的年份有多少天(365或者366)
plusYears(long yearsToAdd) LocalDate 当前对象增加指定的年份数
plusMonths(long monthsToAdd) LocalDate 当前对象增加指定的月份数
plusWeeks(long weeksToAdd) LocalDate 当前对象增加指定的周数
plusDays(long daysToAdd) LocalDate 当前对象增加指定的天数
minusYears(long yearsToSubtract) LocalDate 当前对象减去指定的年数
minusMonths(long monthsToSubtract) LocalDate 当前对象减去注定的月数
minusWeeks(long weeksToSubtract) LocalDate 当前对象减去指定的周数
minusDays(long daysToSubtract) LocalDate 当前对象减去指定的天数
compareTo(ChronoLocalDate other) int 比较当前对象和other对象在时间上的大小,返回值如果为正,则当前对象时间较晚,
isBefore(ChronoLocalDate other) boolean 比较当前对象日期是否在other对象日期之前
isAfter(ChronoLocalDate other) boolean 比较当前对象日期是否在other对象日期之后
isEqual(ChronoLocalDate other) boolean 比较两个日期对象是否相等
SimpleDateFormat Joda-Time Apache-DateUtils 解析ISO8601日期字符串的异同
转:https://www.cnblogs.com/harryzhang/archive/2016/06/07/SimpleDateFormat_ISO8601_FormatString.html
import java.util.Date;
import java.text.SimpleDateFormat;
import org.apache.commons.lang3.time.DateUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
String datestr1 = "2016-06-07T14:08:09.235+08:00"; //ISO8601
String datestr2 = "2016-06-07 14:08:09"; //Without Millis
String datestr3 = "2016-06-07 14:08:09.235"; //With Millis
//Joda Time
Date date0 = new DateTime(datestr1).toDate();
Date date1 = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZZ").parseDateTime(datestr1).toDate();
Date date2 = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").parseDateTime(datestr2).toDate();
Date date3 = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS").parseDateTime(datestr3).toDate();
//JDK
date1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX").parse(datestr1); //XXX means Timezone for Java SimpleDateFormat
date2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(datestr2);
date3 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").parse(datestr3);
//Apache
date1 = DateUtils.parseDate(datestr1, "yyyy-MM-dd'T'HH:mm:ss.SSSZZ");
date2 = DateUtils.parseDate(datestr2, "yyyy-MM-dd HH:mm:ss");
date3 = DateUtils.parseDate(datestr3, "yyyy-MM-dd HH:mm:ss.SSS");
测试中使用了三种常见格式的日期字符串,其中包括Json转换默认的ISO8601格式。经测试SimpleDateFormat Joda-Time Apache-DateUtils三种方式都能实现对这三种日期格式的解析,其中:
1. SimpleDateFormat 解析ISO8601的格式串为 "yyyy-MM-dd'T'HH:mm:ss.SSSXXX",其中XXX表示时区,与通用的ZZ不一样。
2. Joda-Time 默认格式就是ISO8601,故可以直接用 new DateTime(...) 的方式直接解析ISO8601日期串,当然也可以用日期格式串来解析,用日期格式串解析日期的代码略长。
3. Apache-DateUtils 解析ISO8601的格式串和Joda一样是 "yyyy-MM-dd'T'HH:mm:ss.SSSZZ",解析代码相对Joda-Time更简洁。
吐槽一下:SimpleDateFormat用XXX来表示时区真是太变态了,浪费我半天时间才搞定,特此记录。