Java8.0以前:
Date对象:
时间基准以1900年元旦开始,JDK1.0时出现,大部分方法已过时(@Deprecated),格式化时需要借助text包,结构混乱;
Calendar对象:
每周第一天从周日开始,月份从0开始,日期运算默认正向加法
TimeZone对象:
时区换算不方便
以上缺点如果都还能补救,接下来的情况就不容乐观了
使用线程池,实现带有返回值的多线程程序
@Test
public void time0() {
//使用多线程,批量转换时间
Callable task = new Callable() {
//volatile不能解决,底层缓存还是多线程公用,发生冲突
/*volatile*/ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
@Override//synchronized彻底解决同步,效率降低
public /*synchronized*/ Date call() throws Exception {
return sdf.parse("2018-01-01 01:01:01");
}
};
ExecutorService pool = Executors.newFixedThreadPool(10);
List> results = new ArrayList<>();
for (int i = 0; i < 20; i++) {
results.add(pool.submit(task));
}
//输出
results.forEach(f -> {
try {
System.out.println(f.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
});
}
执行结果,发现有些线程转换成功了,但是有些线程直接出异常了,更有的线程竟然转换出错误的结果
为了解决这个问题,经过尝试volatile关键字和synchronized关键字,最后只有synchronized成功了,但是牺牲了效率
新引入的API解决方法
@Test
public void time0() {
//可以多线程公用
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
Callable task = () -> LocalDate.parse("2018-01-01", dtf);
ExecutorService pool = Executors.newFixedThreadPool(10);
List> results = new ArrayList<>();
for (int i = 0; i < 20; i++) {
results.add(pool.submit(task));
}
//输出,正常输出
results.forEach(f -> {
try {
System.out.println(f.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
});
}
java.time:处理时间的功能类包
java.time.chrono:时间特殊的格式包,依据不同国家和地区进行格式化,包括年号纪年、其他历法、特殊公元纪年
java.time.temporal:时间运算包
java.time.zone:时区转换包
国际标准化组织制定的现代公民的日期和时间的表示法规范
@Test
public void time1(){
//13:55:31.613
LocalTime localTime = LocalTime.now();
//2018-06-07
LocalDate localDate = LocalDate.now();
//2018-06-07T13:55:31.613
LocalDateTime localDateTime = LocalDateTime.now();
}
@Test
public void time2() {
//2018年1月1日,ofEpochDay以1970年元旦为准的天数,ofYearDay以指定年的元旦加指定的天数
LocalDate localDate = LocalDate.of(2018, 1, 1);
//10时10分10秒123毫秒456微秒789纳秒,ofSecondOfDay当日秒,ofNanoOfDay当日纳秒
LocalTime localTime = LocalTime.of(10, 10, 10, 123_456_789);
//时间合并
LocalDateTime localDateTime1 = localTime.atDate(localDate);
LocalDateTime localDateTime2 = localDate.atTime(localTime);
//重写toString()方法实现格式化输出
System.out.println(localDate);//2018-01-01
System.out.println(localTime);//10:10:10.123456789
System.out.println(localDateTime1);//2018-01-01T10:10:10.123456789
System.out.println(localDateTime2);//2018-01-01T10:10:10.123456789
}
@Test
public void time3() {
LocalDate localDate = LocalDate.of(-1018,Month.JANUARY,1);
LocalTime localTime = LocalTime.of(10,10,10,123456789);
int num;
//时
num = localTime.getHour();//10
//分
num = localTime.getMinute();//10
//秒
num = localTime.getSecond();//10
//纳秒
num = localTime.getNano();//123456789
//年
num = localDate.getYear();//2018
//月
num = localDate.getMonthValue();//1
//日
num = localDate.getDayOfMonth();//1
//一年中的第几日
num = localDate.getDayOfYear();//1
//去掉getValue()直接输出英文单词
//星期,1:周一(ordinal 1为周日)
DayOfWeek dayOfWeek = localDate.getDayOfWeek();//MONDAY
int value = dayOfWeek.getValue();//1
//月,1:一月
Month month = localDateTime.getMonth();//JUNE
value = month.getValue();//6
//BCE:公元前,0;CE:公元后,1
Era era = localDate.getEra();//CE
value = era.getValue();//1
}
@Test
public void time4() {
//时区
Set set = ZoneId.getAvailableZoneIds();
//遍历所有支持的时区ID
//set.forEach(System.out::println);
//时区,可以负数,输出东8区时间:2018-06-07T14:14:03.436+08:00
OffsetDateTime offsetDateTime = LocalDateTime.now().atOffset(ZoneOffset.ofHours(8));
//获取指定时区当前时间,输出东9区时间:2018-06-07T15:14:03.437
LocalDateTime ldt1 = LocalDateTime.now(ZoneId.of("Japan"));//等价于"Etc/GMT-9"
//获取指定时间差的时区,不能为负数,时间以0时区为准,输出东8区30分时间:2018-06-07T14:44:03.437
LocalDateTime ldt2 = LocalDateTime.now(ZoneOffset.ofHoursMinutes(8, 30));
//给时间指定时区,输出:2018-06-07T14:14:03.433-08:00[Etc/GMT+8]
ZonedDateTime zdt = localDateTime.atZone(ZoneId.of("Etc/GMT+8"));
//指定时间的时区,输出:01:01:01
LocalTime lt = LocalTime.of(1, 1, 1);
//输出:01:01:01+08:00
OffsetTime odt = lt.atOffset(ZoneOffset.ofHoursMinutesSeconds(8, 0, 0));
}
@Test
public void time5() {
//时间戳(以1970年元旦为准,Unix元年),输出:2018-06-07T06:21:51.082Z
Instant instant = Instant.now();//UTC时区(欧洲,格林尼治时间)
//从1970年元旦至今的毫秒数,UTC时区时间
long l = instant.toEpochMilli();//1528352511082
//创建时间戳
instant = Instant.ofEpochMilli(l);//2018-06-07T06:33:44.298Z
//时钟戳
Clock clock = Clock.systemDefaultZone();//SystemClock[Asia/Shanghai]
//获取时区ID
ZoneId zone = clock.getZone();//Asia/Shanghai
//从1970年元旦至今的毫秒数
long millis = clock.millis();//1528352511099
//获取当前时间的时间戳,输出:2018-06-07T14:31:45.147Z
instant = LocalDateTime.now().toInstant(ZoneOffset.UTC);
}
@Test
public void time6() {
//时间差
Duration duration = Duration.between(Instant.ofEpochSecond(1_0000_0000), Instant.ofEpochSecond(2_0000_0000));//PT27777H46M40S
long hours = duration.toHours();//27777
long minutes = duration.toMinutes();//1666666
long seconds = duration.getSeconds();//100000000
//日期差
Period period = Period.between(LocalDate.of(2000, 1, 1), LocalDate.of(3000, 12, 31));//P1000Y11M30D
int years = period.getYears();//1000
int months = period.getMonths();//11
int days = period.getDays();//30
//日期运算,plus为加法,minus为减法,可以出现负数
LocalDate localDate = LocalDate.of(2018, 1, 1);
//100天后
LocalDate ld = localDate.plusDays(100);//2018-04-11
//30月前
ld = localDate.minusMonths(30);//2015-07-01
//13周后
ld = localDate.plusWeeks(30);//2018-07-30
//10年10月10周10日后
ld = localDate.plusYears(10).plusYears(10).plusWeeks(10).plusDays(10);//2038-03-22
LocalDateTime localDateTime = LocalDateTime.of(2018, 1, 1, 1, 1, 1, 1);
//纳秒增加运算
LocalDateTime ldt = localDateTime.plusNanos(123_1234_1234_1234_1234L);//2057-01-06T10:29:44.412341235
/*
使用指定时间单位
*/
localDateTime = LocalDateTime.of(2018, 1, 1, 1, 1, 1, 1);
//1纳秒后
ldt = localDateTime.plus(1, ChronoUnit.NANOS);//2018-01-01T01:01:01.000000002
//1微秒后
ldt = localDateTime.plus(1, ChronoUnit.MICROS);//2018-01-01T01:01:01.000001001
//1毫秒后
ldt = localDateTime.plus(1, ChronoUnit.MILLIS);//2018-01-01T01:01:01.001000001
//1秒后
ldt = localDateTime.plus(1, ChronoUnit.SECONDS);//2018-01-01T01:01:02.000000001
//1分钟后
ldt = localDateTime.plus(1, ChronoUnit.MINUTES);//2018-01-01T01:02:01.000000001
//1小时后
ldt = localDateTime.plus(1, ChronoUnit.HOURS);//2018-01-01T02:01:01.000000001
//半天后
ldt = localDateTime.plus(1, ChronoUnit.HALF_DAYS);//2018-01-01T13:01:01.000000001
//1天后
ldt = localDateTime.plus(1, ChronoUnit.DAYS);//2018-01-02T01:01:01.000000001
//1周后
ldt = localDateTime.plus(1, ChronoUnit.WEEKS);//2018-01-08T01:01:01.000000001
//1个月后
ldt = localDateTime.plus(1, ChronoUnit.MONTHS);//2018-02-01T01:01:01.000000001
//1年后
ldt = localDateTime.plus(1, ChronoUnit.YEARS);//2019-01-01T01:01:01.000000001
//1个年代后
ldt = localDateTime.plus(1, ChronoUnit.DECADES);//2028-01-01T01:01:01.000000001
//1个世纪后
ldt = localDateTime.plus(1, ChronoUnit.CENTURIES);//2118-01-01T01:01:01.000000001
//1000年
ldt = localDateTime.plus(1, ChronoUnit.MILLENNIA);//3018-01-01T01:01:01.000000001
//跨公元
ldt = LocalDateTime.of(-2017, 1, 1, 1, 1, 1, 1)
.plus(1, ChronoUnit.ERAS);//2018-01-01T01:01:01.000000001
}
@Test
public void time7() {
//时间校正器
LocalDateTime localDateTime = LocalDateTime.of(2018, 1, 1, 1, 1, 1);
LocalDateTime result;
//设置为10号
result = localDateTime.withDayOfMonth(10);//2018-01-10T01:01:01
//设置为下一个周日
result = localDateTime.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));//2018-01-07T01:01:01
//下一个工作日,输出:2018-01-02T01:01:01
result = localDateTime.with(in -> {
LocalDateTime out = (LocalDateTime) in;
DayOfWeek dow = out.getDayOfWeek();
if (dow.equals(DayOfWeek.FRIDAY)) {
out = out.plusDays(3);
} else if (dow.equals(DayOfWeek.SATURDAY)) {
out = out.plusDays(2);
} else {
out = out.plusDays(1);
}
return out;
});
//预产期,输出:2018-10-08T01:01:01
result = localDateTime.with((in) -> {
LocalDateTime out = (LocalDateTime) in;
return out.plusDays(280);
});
}
@Test
public void time8() {
//时间格式化
DateTimeFormatter dtfISO = DateTimeFormatter.ISO_DATE_TIME;
LocalDateTime localDateTime = LocalDateTime.of(2018, 1, 1, 1, 1, 1, 123_456_789);
String strDate = localDateTime.format(dtfISO);//2018-01-01T01:01:01.123456789
//自定义格式化时间
/* https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html */
DateTimeFormatter dtfDIY = DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分ss秒n纳秒");
strDate = localDateTime.format(dtfDIY);//2018年01月01日01时01分01秒123456789纳秒
//自定义解析时间
TemporalAccessor ta = dtfDIY.parse("1234年05月06日07时08分09秒987654321纳秒");
LocalDateTime ldt = LocalDateTime.from(ta);//1234-05-06T07:08:09.987654321
//国际化
String dateIN = "2010-01-01 01:23:45";
DateTimeFormatter dtfIN = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime ldtIN = LocalDateTime.parse(dateIN, dtfIN);
DateTimeFormatter dtfOUT = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL, FormatStyle.MEDIUM).withLocale(Locale.KOREA);
String dateOUT = ldtIN.format(dtfOUT);
System.out.println(dateOUT);//2010년 1월 1일 금요일 오전 1:23:45
}
@Test
public void time9() {
/*
特殊的四种历法,以公元2018年1月1日为准
*/
//佛历,以公元543年为元年
ThaiBuddhistDate thaiBuddhistDate = ThaiBuddhistChronology.INSTANCE.date(2561, 1, 1);//ThaiBuddhist BE 2561-01-01
//台湾,以公元1911年为元年
MinguoDate minguoDate = MinguoChronology.INSTANCE.date(107, 1, 1);//Minguo ROC 107-01-01
//日本
/*
明治(1868-01-01 - 1912-07-29)
大正(1912-07-30 - 1926-12-24)
昭和(1926-12-25 - 1989-01-07)
平成(1989-01-08 - 2019-04-30)(日本历法改年号时,Java需要打补丁补充年号)
*/
//JapaneseDate japaneseDate = JapaneseChronology.INSTANCE.date(2018, 1, 1);
JapaneseDate japaneseDate = JapaneseChronology.INSTANCE.date(JapaneseEra.HEISEI, 30, 1, 1);//Japanese Heisei 30-01-01
//伊斯兰历(回历),公元639年为元年,伊历=公历-622+(公历-622)/32,公历=伊历+622-伊历/33,日落天黑为一天的开始
HijrahDate hijrahDate = HijrahChronology.INSTANCE.date(1439, 4, 14);//Hijrah-umalqura AH 1439-04-14
/*
借助Unix元年(1970年元旦)进行转换
*/
//公历转伊历
HijrahDate hd = HijrahChronology.INSTANCE.dateEpochDay(LocalDate.of(2018, 1, 1).toEpochDay());//Hijrah-umalqura AH 1439-04-14
//伊历转公历
LocalDate ld = LocalDate.ofEpochDay(HijrahDate.of(1439, 4, 14).toEpochDay());//2018-01-01
//台湾历转日本历
JapaneseDate jd = JapaneseChronology.INSTANCE.dateEpochDay(MinguoChronology.INSTANCE.date(107, 1, 1).toEpochDay());//Japanese Heisei 30-01-01
}