在 JDK1.8 之前都使用时将相关的操作存在多线程问题,可以通过 ThreadLocal 来解决
public class
DateFormatThreadLocal {
private static final
ThreadLocal<DateFormat>
df
=
new
ThreadLocal<DateFormat>() {
@Override
protected
DateFormat initialValue() {
return new
SimpleDateFormat(
"yyyyMMdd"
);
}
};
public static final
Date convert(String source)
throws
ParseException {
return
df
.get().parse(source);
}
}
使用 LocalDate、 LocalTime、 LocalDateTime
LocalDate、 LocalTime、 LocalDateTime 类的实例是不可变的对象,分别表示使用 ISO-8601日历系统的日期、时间、日期和时间。它们提供简单的日期或时间,并不包含当前的时间信息,也不包含与时区相关的信息
注 : ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示法
LocalDateTime ldt = LocalDateTime.
now
();
System.
out
.println(ldt);
LocalDateTime ld2 = LocalDateTime.
of
(
2016
,
11
,
21
,
10
,
10
,
10
);
System.
out
.println(ld2);
LocalDateTime ldt3 = ld2.plusYears(
20
);
System.
out
.println(ldt3);
LocalDateTime ldt4 = ld2.minusMonths(
2
);
System.
out
.println(ldt4);
System.
out
.println(ldt.getYear());
System.
out
.println(ldt.getMonthValue());
System.
out
.println(ldt.getDayOfMonth());
System.
out
.println(ldt.getHour());
System.
out
.println(ldt.getMinute());
System.
out
.println(ldt.getSecond());
方法 | 描述 | 示例 |
now() | 静态方法,根据当前时间创建对象 |
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now();
LocalDateTime localDateTime = LocalDateTime.now();
|
of() | 静态方法,根据指定日期/时间创建对象 |
LocalDate localDate = LocalDate.of(2016, 10, 26);
LocalTime localTime = LocalTime.of(02, 22, 56);
LocalDateTime localDateTime = LocalDateTime.of(2016, 10, 26, 12, 10, 55);
|
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) | |
getDayOfWeek | 获得星期几(返回一个 DayOfWeek枚举值) | |
getMonth | 获得月份, 返回一个 Month 枚举值 | |
getMonthValue | 获得月份(1-12) | |
getYear | 获得年份 | |
until | 获得两个日期之间的 Period 对象,或者指定 ChronoUnits 的数字 | |
isBefore, isAfter | 比较两个 LocalDate | |
isLeapYear | 判断是否是闰年 |
Instant 时间戳 (使用 Unix 元年 1970年1月1日 00:00:00 所经历的毫秒值)
用于“时间戳”的运算。它是以Unix元年(传统的设定为UTC时区1970年1月1日午夜时分)开始所经历的描述进行运算
Instant ins = Instant.
now
();
//默认使用 UTC 时区
System.
out
.println(ins);
OffsetDateTime odt = ins.atOffset(ZoneOffset.
ofHours
(
8
));
System.
out
.println(odt);
System.
out
.println(ins.getNano());
Instant ins2 = Instant.
ofEpochSecond
(
5
);
System.
out
.println(ins2);
Duration 和 Period
Duration : 用于计算两个“时间”间隔
Period : 用于计算两个“日期”间隔
Instant ins1 = Instant.
now
();
System.
out
.println(
"--------------------"
);
try
{
Thread.
sleep
(
1000
);
}
catch
(InterruptedException ignored) {
}
Instant ins2 = Instant.
now
();
System.
out
.println(
"所耗费时间为:"
+ Duration.
between
(ins1, ins2));
System.
out
.println(
"----------------------------------"
);
LocalDate ld1 = LocalDate.
now
();
LocalDate ld2 = LocalDate.
of
(
2011
,
1
,
1
);
Period pe = Period.
between
(ld2, ld1);
System.
out
.println(pe.getYears());
System.
out
.println(pe.getMonths());
System.
out
.println(pe.getDays());
日期的操纵
TemporalAdjuster : 时间校正器。有时我们可能需要获取例如 : 将日期调整到“下个周日”等操作
TemporalAdjusters : 该类通过静态方法提供了大量的常用 TemporalAdjuster 的实现
例如获取下个周日:
LocalDate nextSunday = LocalDate.
now
().with(TemporalAdjusters.
next
(DayOfWeek.
SUNDAY
));
LocalDateTime ldt = LocalDateTime.
now
();
System.
out
.println(ldt);
LocalDateTime ldt2 = ldt.withDayOfMonth(
10
);
System.
out
.println(ldt2);
LocalDateTime ldt3 = ldt.with(TemporalAdjusters.
next
(DayOfWeek.
SUNDAY
));
System.
out
.println(ldt3);
// 自定义:下一个工作日
LocalDateTime ldt5 = ldt.with((l) -> {
LocalDateTime ldt4 = (LocalDateTime) l;
DayOfWeek dow = ldt4.getDayOfWeek();
if
(dow.equals(DayOfWeek.
FRIDAY
)) {
return
ldt4.plusDays(
3
);
}
else if
(dow.equals(DayOfWeek.
SATURDAY
)) {
return
ldt4.plusDays(
2
);
}
else
{
return
ldt4.plusDays(
1
);
}
});
System.
out
.println(ldt5);
解析与格式化
java.time.format.DateTimeFormatter 类:该类提供了三种格式化方法 :
1> 预定义的标准格式
2> 语言环境相关的格式
3> 自定义的格式
// DateTimeFormatter dtf = DateTimeFormatter.ISO_LOCAL_DATE;
DateTimeFormatter dtf = DateTimeFormatter.
ofPattern
(
"yyyy年MM月dd日 HH:mm:ss E"
);
LocalDateTime ldt = LocalDateTime.
now
();
String strDate = ldt.format(dtf);
System.
out
.println(strDate);
LocalDateTime newLdt = ldt.
parse
(strDate, dtf);
System.
out
.println(newLdt);
时区的处理
Java8 中加入了对时区的支持,带时区的时间为分别为 : ZonedDate、 ZonedTime、 ZonedDateTime
其中每个时区都对应着 ID,地区ID都为 “ {区域}/{城市}”的格式
例如 : Asia/Shanghai 等
ZoneId : 该类中包含了所有的时区信息
getAvailableZoneIds() : 可以获取所有时区时区信息
of(id) : 用指定的时区信息获取 ZoneId 对象
Set<String> set = ZoneId.
getAvailableZoneIds
();
set.forEach(System.
out
::println);
LocalDateTime ldt = LocalDateTime.
now
(ZoneId.
of
(
"Asia/Shanghai"
));
System.
out
.println(ldt);
ZonedDateTime zdt = ZonedDateTime.
now
(ZoneId.
of
(
"US/Pacific"
));
System.
out
.println(zdt);
与传统日期处理的转换
类
|
To 遗留类
|
From 遗留类
|
java.time.Instant
java.util.Date
|
Date.from(instant) | date.toInstant() |
java.time.Instant
java.sql.Timestamp
|
Timestamp.from(instant) | timestamp.toInstant() |
java.time.ZonedDateTime
java.util.GregorianCalendar
|
GregorianCalendar.from(zonedDateTime) | cal.toZonedDateTime() |
java.time.LocalDate
java.sql.Time
|
Date.valueOf(localDate) | date.toLocalDate() |
java.time.LocalTime
java.sql.Time
|
Date.valueOf(localDate) | date.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() | 无 |
JDK1.8前的时间操作与之后的时间操作
以下操作存在问题
SimpleDateFormat sdf =
new
SimpleDateFormat(
"yyyyMMdd"
);
Callable<Date> task =
new
Callable<Date>() {
@Override
public
Date call()
throws
Exception {
return
sdf
.parse(
"20161121"
);
}
};
ExecutorService pool = Executors.
newFixedThreadPool
(
10
);
List<Future<Date>> results =
new
ArrayList<>();
for
(
int
i =
0
; i <
10
; i++) {
results.add(pool.submit(task));
}
for
(Future<Date> future : results) {
System.
out
.println(future.get());
}
pool.shutdown();
解决多线程安全问题
Callable<Date> task =
new
Callable<Date>() {
@Override
public
Date call()
throws
Exception {
return
DateFormatThreadLocal.
convert
(
"20161121"
);
}
};
ExecutorService pool = Executors.
newFixedThreadPool
(
10
);
List<Future<Date>> results =
new
ArrayList<>();
for
(
int
i =
0
; i <
10
; i++) {
results.add(pool.submit(task));
}
for
(Future<Date> future : results) {
System.
out
.println(future.get());
}
pool.shutdown();
使用 JDK1.8 的 DateTimeFormatter 就不存在 多线程问题
DateTimeFormatter dtf = DateTimeFormatter.
ofPattern
(
"yyyyMMdd"
);
Callable<LocalDate> task =
new
Callable<LocalDate>() {
@Override
public
LocalDate call()
throws
Exception {
LocalDate ld = LocalDate.
parse
(
"20161121"
,
dtf
);
return
ld;
}
};
ExecutorService pool = Executors.
newFixedThreadPool
(
10
);
List<Future<LocalDate>> results =
new
ArrayList<>();
for
(
int
i =
0
; i <
10
; i++) {
results.add(pool.submit(task));
}
for
(Future<LocalDate> future : results) {
System.
out
.println(future.get());
}
pool.shutdown();