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}