001/**
002 * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
003 * <p>
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * <p>
008 * http://www.apache.org/licenses/LICENSE-2.0
009 * <p>
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package com.mybatisflex.core.util;
017
018
019import java.sql.Timestamp;
020import java.text.ParseException;
021import java.text.SimpleDateFormat;
022import java.time.*;
023import java.time.format.DateTimeFormatter;
024import java.util.Date;
025import java.util.HashMap;
026import java.util.Locale;
027import java.util.Map;
028import java.util.concurrent.ConcurrentHashMap;
029
030
031public class DateUtil {
032
033    public static String datePatternWithoutDividing = "yyyyMMdd";
034    public static String datePattern = "yyyy-MM-dd";
035    public static final String dateMinutePattern = "yyyy-MM-dd HH:mm";
036    public static final String dateMinutePattern2 = "yyyy-MM-dd'T'HH:mm";
037    public static String datetimePattern = "yyyy-MM-dd HH:mm:ss";
038    public static final String dateMillisecondPattern = "yyyy-MM-dd HH:mm:ss SSS";
039    public static final String dateCSTPattern = "EEE MMM dd HH:mm:ss zzz yyyy";
040
041    private static final ThreadLocal<HashMap<String, SimpleDateFormat>> TL = ThreadLocal.withInitial(() -> new HashMap<>());
042
043    private static final Map<String, DateTimeFormatter> dateTimeFormatters = new ConcurrentHashMap<>();
044
045    public static DateTimeFormatter getDateTimeFormatter(String pattern) {
046        DateTimeFormatter ret = dateTimeFormatters.get(pattern);
047        if (ret == null) {
048            ret = DateTimeFormatter.ofPattern(pattern);
049            dateTimeFormatters.put(pattern, ret);
050        }
051        return ret;
052    }
053
054    public static SimpleDateFormat getSimpleDateFormat(String pattern) {
055        SimpleDateFormat ret = TL.get().get(pattern);
056        if (ret == null) {
057            if (dateCSTPattern.equals(pattern)) {
058                ret = new SimpleDateFormat(dateCSTPattern, Locale.US);
059            } else {
060                ret = new SimpleDateFormat(pattern);
061            }
062            TL.get().put(pattern, ret);
063        }
064        return ret;
065    }
066
067
068    public static Date parseDate(Object value) {
069        if (value instanceof Number) {
070            return new Date(((Number) value).longValue());
071        }
072        if (value instanceof Timestamp) {
073            return new Date(((Timestamp) value).getTime());
074        }
075        if (value instanceof LocalDate) {
076            return DateUtil.toDate((LocalDate) value);
077        }
078        if (value instanceof LocalDateTime) {
079            return DateUtil.toDate((LocalDateTime) value);
080        }
081        if (value instanceof LocalTime) {
082            return DateUtil.toDate((LocalTime) value);
083        }
084        String s = value.toString();
085        if (StringUtil.isNumeric(s)) {
086            return new Date(Long.parseLong(s));
087        }
088        return DateUtil.parseDate(s);
089    }
090
091
092
093    public static Date parseDate(String dateString) {
094        if (StringUtil.isBlank(dateString)) {
095            return null;
096        }
097        dateString = dateString.trim();
098        try {
099            SimpleDateFormat sdf = getSimpleDateFormat(getPattern(dateString));
100            try {
101                return sdf.parse(dateString);
102            } catch (ParseException ex) {
103                //2022-10-23 00:00:00.0
104                int lastIndexOf = dateString.lastIndexOf(".");
105                if (lastIndexOf == 19) {
106                    return parseDate(dateString.substring(0, lastIndexOf));
107                }
108
109                //2022-10-23 00:00:00,0
110                lastIndexOf = dateString.lastIndexOf(",");
111                if (lastIndexOf == 19) {
112                    return parseDate(dateString.substring(0, lastIndexOf));
113                }
114
115                //2022-10-23 00:00:00 000123
116                lastIndexOf = dateString.lastIndexOf(" ");
117                if (lastIndexOf == 19) {
118                    return parseDate(dateString.substring(0, lastIndexOf));
119                }
120
121                if (dateString.contains(".") || dateString.contains("/")) {
122                    dateString = dateString.replace(".", "-").replace("/", "-");
123                    return sdf.parse(dateString);
124                } else {
125                    throw ex;
126                }
127            }
128        } catch (ParseException ex) {
129            throw new IllegalArgumentException("The date format is not supported for the date string: " + dateString);
130        }
131    }
132
133
134
135    public static LocalDateTime parseLocalDateTime(String dateString) {
136        if (StringUtil.isBlank(dateString)) {
137            return null;
138        }
139        dateString = dateString.trim();
140        DateTimeFormatter dateTimeFormatter = getDateTimeFormatter(getPattern(dateString));
141        try {
142            return LocalDateTime.parse(dateString, dateTimeFormatter);
143        } catch (Exception ex) {
144            //2022-10-23 00:00:00.0
145            int lastIndexOf = dateString.lastIndexOf(".");
146            if (lastIndexOf == 19) {
147                return parseLocalDateTime(dateString.substring(0, lastIndexOf));
148            }
149
150            //2022-10-23 00:00:00,0
151            lastIndexOf = dateString.lastIndexOf(",");
152            if (lastIndexOf == 19) {
153                return parseLocalDateTime(dateString.substring(0, lastIndexOf));
154            }
155
156            //2022-10-23 00:00:00 000123
157            lastIndexOf = dateString.lastIndexOf(" ");
158            if (lastIndexOf == 19) {
159                return parseLocalDateTime(dateString.substring(0, lastIndexOf));
160            }
161
162            if (dateString.contains(".") || dateString.contains("/")) {
163                dateString = dateString.replace(".", "-").replace("/", "-");
164                dateTimeFormatter = getDateTimeFormatter(getPattern(dateString));
165                return LocalDateTime.parse(dateString, dateTimeFormatter);
166            } else {
167                throw ex;
168            }
169        }
170    }
171
172
173    private static String getPattern(String dateString) {
174        int length = dateString.length();
175        if (length == datetimePattern.length()) {
176            return datetimePattern;
177        } else if (length == datePattern.length()) {
178            return datePattern;
179        } else if (length == dateMinutePattern.length()) {
180            if (dateString.contains("T")) {
181                return dateMinutePattern2;
182            }
183            return dateMinutePattern;
184        } else if (length == dateMillisecondPattern.length()) {
185            return dateMillisecondPattern;
186        } else if (length == datePatternWithoutDividing.length()) {
187            return datePatternWithoutDividing;
188        } else if (length == dateCSTPattern.length()) {
189            return dateCSTPattern;
190        } else {
191            throw new IllegalArgumentException("The date format is not supported for the date string: " + dateString);
192        }
193    }
194
195
196    public static LocalDateTime toLocalDateTime(Date date) {
197        if (date == null) {
198            return null;
199        }
200        // java.sql.Date 不支持 toInstant(),需要先转换成 java.util.Date
201        if (date instanceof java.sql.Date) {
202            date = new Date(date.getTime());
203        }
204
205        Instant instant = date.toInstant();
206        ZoneId zone = ZoneId.systemDefault();
207        return LocalDateTime.ofInstant(instant, zone);
208    }
209
210
211    public static LocalDate toLocalDate(Date date) {
212        if (date == null) {
213            return null;
214        }
215        // java.sql.Date 不支持 toInstant(),需要先转换成 java.util.Date
216        if (date instanceof java.sql.Date) {
217            date = new Date(date.getTime());
218        }
219
220        Instant instant = date.toInstant();
221        ZoneId zone = ZoneId.systemDefault();
222        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
223        return localDateTime.toLocalDate();
224    }
225
226
227    public static LocalTime toLocalTime(Date date) {
228        if (date == null) {
229            return null;
230        }
231        // java.sql.Date 不支持 toInstant(),需要先转换成 java.util.Date
232        if (date instanceof java.sql.Date) {
233            date = new Date(date.getTime());
234        }
235
236        Instant instant = date.toInstant();
237        ZoneId zone = ZoneId.systemDefault();
238        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
239        return localDateTime.toLocalTime();
240    }
241
242
243    public static Date toDate(LocalDateTime localDateTime) {
244        if (localDateTime == null) {
245            return null;
246        }
247        ZoneId zone = ZoneId.systemDefault();
248        Instant instant = localDateTime.atZone(zone).toInstant();
249        return Date.from(instant);
250    }
251
252
253    public static Date toDate(LocalDate localDate) {
254        if (localDate == null) {
255            return null;
256        }
257        ZoneId zone = ZoneId.systemDefault();
258        Instant instant = localDate.atStartOfDay().atZone(zone).toInstant();
259        return Date.from(instant);
260    }
261
262
263    public static Date toDate(LocalTime localTime) {
264        if (localTime == null) {
265            return null;
266        }
267        LocalDate localDate = LocalDate.now();
268        LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
269        ZoneId zone = ZoneId.systemDefault();
270        Instant instant = localDateTime.atZone(zone).toInstant();
271        return Date.from(instant);
272    }
273
274
275    public static String toDateTimeString(Date date) {
276        return toString(date, datetimePattern);
277    }
278
279
280    public static String toString(Date date, String pattern) {
281        return date == null ? null : getSimpleDateFormat(pattern).format(date);
282    }
283
284
285}