我是靠谱客的博主 负责皮带,这篇文章主要介绍java8-LocalDate详解LocalDate,现在分享给大家,希望可以做个参考。

LocalDate

分类分工

java.time.LocalDate ->只对年月日做出处理
java.time.LocalTime ->只对时分秒纳秒做出处理
java.time.LocalDateTime ->同时可以处理年月日和时分秒

优点

除了使用起来更加简单和灵活,主要是传统的时期处理类Date、Calendar不是多线程安全的,而LocalDate 线程安全的,所以不用担心并发问题。

实际使用

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; import com.google.common.collect.Lists; /** * * * Java 8 的时间工具类 */ public class DateUtils { /** * 默认使用系统当前时区 */ private static final ZoneId ZONE = ZoneId.systemDefault(); private static final String DATE_FORMAT = "yyyy-MM-dd"; private static final String DATE_FORMAT_DS = "yyyyMMdd"; private static final String DATE_FORMAT_DEFAULT = "yyyy-MM-dd HH:mm:ss"; private static final String TIME_FORMAT = "yyyyMMddHHmmss"; private static final String REGEX = "\:|\-|\s"; public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); /** * 获取当前时间 * * @param format * @return */ public static String getCurrentTime(String format) { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format); LocalDateTime now = LocalDateTime.now(); return now.format(dateTimeFormatter); } /** * 获取昨日时间 * * @param format * @return */ public static String getYesterday(String format) { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format); LocalDate nowDate = LocalDate.now(); LocalDate yesterday = nowDate.minusDays(1); return yesterday.format(dateTimeFormatter); } /** * 获取上周的时间 * * @param format * @return */ public static String getLastWeek(String format) { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format); LocalDate nowDate = LocalDate.now(); LocalDate lastWeek = nowDate.minusWeeks(1); return lastWeek.format(dateTimeFormatter); } /** * 获取上个月的时间 * * @param format * @return */ public static String getLastMonth(String format) { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format); LocalDate nowDate = LocalDate.now(); LocalDate lastMonth = nowDate.minusMonths(1); return lastMonth.format(dateTimeFormatter); } /** * 获取去年的时间 * * @param format * @return */ public static String getLastYear(String format) { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format); LocalDate nowDate = LocalDate.now(); LocalDate lastYear = nowDate.minusYears(1); return lastYear.format(dateTimeFormatter); } /** * 获取前多少天的日期 * * @param format * @param num * @return */ public static String getBeforeSomeDay(String format, int num) { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format); LocalDate nowDate = LocalDate.now(); LocalDate beforeDay = nowDate.minusDays(num); return beforeDay.format(dateTimeFormatter); } /** * 获取指定时间的前多少天 * * @param format * @param date * @param num * @return */ public static String getBeforeDayOfDate(String format, String date, int num) { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format); LocalDate localDate = LocalDate.parse(date, dateTimeFormatter); LocalDate beforeDay = localDate.minusDays(num); return beforeDay.format(dateTimeFormatter); } /** * 获取当天的开始时间 yyyy-MM-dd 00:00:00 * * @param format * @return */ public static String getDayStartTime(String format, String date) { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format); LocalDate localDate = LocalDate.parse(date, dateTimeFormatter); LocalDateTime toDayStart = LocalDateTime.of(localDate, LocalTime.MIN); return toDayStart.format(FORMATTER); } /** * 获取当天的结束时间 yyyy-MM-dd 23:59:59 * * @param format * @return */ public static String getDayEndTime(String format, String date) { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format); LocalDate localDate = LocalDate.parse(date, dateTimeFormatter); LocalDateTime toDayStart = LocalDateTime.of(localDate, LocalTime.MAX); return toDayStart.format(FORMATTER); } /** * 获取两个时间之间的间隔天数 * * @param startDate yyyyMMdd * @param endDate yyyyMMdd * @return */ public static long getRangeCountOfDate(String startDate, String endDate) { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATE_FORMAT_DS); LocalDate startLocalDate = LocalDate.parse(startDate, dateTimeFormatter); LocalDate endLocalDate = LocalDate.parse(endDate, dateTimeFormatter); long count = ChronoUnit.DAYS.between(startLocalDate, endLocalDate); return count; } /** * 后期两个时间之间的所有日期 【包含开始时间和结束时间】 * * @param startDate yyyyMMdd * @param endDate yyyyMMdd * @return */ public static List<String> getRangeOfDate(String startDate, String endDate) { List<String> range = Lists.newArrayList(); DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATE_FORMAT_DS); LocalDate startLocalDate = LocalDate.parse(startDate, dateTimeFormatter); LocalDate endLocalDate = LocalDate.parse(endDate, dateTimeFormatter); long count = ChronoUnit.DAYS.between(startLocalDate, endLocalDate); if (count < 0) { return range; } range = Stream.iterate(startLocalDate, d -> d.plusDays(1)).limit(count + 1).map( s -> s.format(dateTimeFormatter)).collect(Collectors.toList()); return range; } public static void main(String[] args) { System.out.println(getRangeOfDate("20191010", "20191020")); } }

参考:https://blog.csdn.net/wusd1256/article/details/102934354

Date线程不安全的原因

1- SimpleDateFormat线程安全问题

使用ExecutorService提交多个任务的方式,模拟并发环境将字符串转换为日期即测试parse方法,代码如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Test public void testParse() { ExecutorService executorService = Executors.newCachedThreadPool(); List<String> dateStrList = Lists.newArrayList( "2018-04-01 10:00:01", "2018-04-02 11:00:02", "2018-04-03 12:00:03", "2018-04-04 13:00:04", "2018-04-05 14:00:05" ); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); for (String str : dateStrList) { executorService.execute(() -> { try { simpleDateFormat.parse(str); TimeUnit.SECONDS.sleep(1); } catch (Exception e) { e.printStackTrace(); } }); } }

运行后,报错如下:
在这里插入图片描述
可见并发环境下使用SimpleDateFormat的parse方法有线程安全问题!

线程安全问题的原因:

在SimpleDateFormat转换日期是通过Calendar对象来操作的,SimpleDateFormat继承DateFormat类,DateFormat类中维护一个Calendar对象,代码如下:
在这里插入图片描述
在这里插入图片描述
通过DateFormat类中的注释可知:此处Calendar实例被用来进行日期-时间计算,既被用于format方法也被用于parse方法!

在parse方法的最后,会调用CalendarBuilder的establish方法,入参就是SimpleDateFormat维护的Calendar实例,在establish方法中会调用calendar的clear方法,如下:
在这里插入图片描述
可知SimpleDateFormat维护的用于format和parse方法计算日期-时间的calendar被清空了,如果此时线程A将calendar清空且没有设置新值,线程B也进入parse方法用到了SimpleDateFormat对象中的calendar对象,此时就会产生线程安全问题!

2- 解决方案

**每一个使用SimpleDateFormat对象进行日期-时间进行format和parse方法的时候就创建一个新的SimpleDateFormat对象,用完就销毁即可!**代码如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/** * 模拟并发环境下使用SimpleDateFormat的parse方法将字符串转换成Date对象 */ @Test public void testParseThreadSafe() { ExecutorService executorService = Executors.newCachedThreadPool(); List<String> dateStrList = Lists.newArrayList( "2018-04-01 10:00:01", "2018-04-02 11:00:02", "2018-04-03 12:00:03", "2018-04-04 13:00:04", "2018-04-05 14:00:05" ); for (String str : dateStrList) { executorService.execute(() -> { try { //创建新的SimpleDateFormat对象用于日期-时间的计算 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); simpleDateFormat.parse(str); TimeUnit.SECONDS.sleep(1); simpleDateFormat = null; //销毁对象 } catch (Exception e) { e.printStackTrace(); } }); } }

在运行可以发现不会报出之前的错误了!

综上所述,使用SimpleDateFormat对象进行日期-时间计算时,如果SimpleDateFormat是多个线程共享的就会有线程安全问题!应该让每一个线程都有一个独立的SimpleDateFormat对象用于日期-时间的计算!此时就可以使用ThreadLocal将SimpleDateFormat绑定到线程上,是的该线程上的日期-时间计算顺序的使用SimpleDateFormat对象,这样也可以避免线程安全问题!

另外就是使用LocalDateTime

复制代码
1
2
3
4
LocalDateTime now = LocalDateTime.of(LocalDate.now(), LocalTime.now()); DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); String dateStr = now.format(fmt);

最后

以上就是负责皮带最近收集整理的关于java8-LocalDate详解LocalDate的全部内容,更多相关java8-LocalDate详解LocalDate内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(74)

评论列表共有 0 条评论

立即
投稿
返回
顶部