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 private DateUtil() {} 034 035 public static String datePatternWithoutDividing = "yyyyMMdd"; 036 public static String datePattern = "yyyy-MM-dd"; 037 public static final String dateMinutePattern = "yyyy-MM-dd HH:mm"; 038 public static final String dateMinutePattern2 = "yyyy-MM-dd'T'HH:mm"; 039 public static String datetimePattern = "yyyy-MM-dd HH:mm:ss"; 040 public static final String dateMillisecondPattern = "yyyy-MM-dd HH:mm:ss SSS"; 041 public static final String dateCSTPattern = "EEE MMM dd HH:mm:ss zzz yyyy"; 042 043 private static final ThreadLocal<HashMap<String, SimpleDateFormat>> TL = ThreadLocal.withInitial(() -> new HashMap<>()); 044 045 private static final Map<String, DateTimeFormatter> dateTimeFormatters = new ConcurrentHashMap<>(); 046 047 public static DateTimeFormatter getDateTimeFormatter(String pattern) { 048 DateTimeFormatter ret = dateTimeFormatters.get(pattern); 049 if (ret == null) { 050 ret = DateTimeFormatter.ofPattern(pattern); 051 dateTimeFormatters.put(pattern, ret); 052 } 053 return ret; 054 } 055 056 public static SimpleDateFormat getSimpleDateFormat(String pattern) { 057 SimpleDateFormat ret = TL.get().get(pattern); 058 if (ret == null) { 059 if (dateCSTPattern.equals(pattern)) { 060 ret = new SimpleDateFormat(dateCSTPattern, Locale.US); 061 } else { 062 ret = new SimpleDateFormat(pattern); 063 } 064 TL.get().put(pattern, ret); 065 } 066 return ret; 067 } 068 069 070 public static Date parseDate(Object value) { 071 if (value instanceof Number) { 072 return new Date(((Number) value).longValue()); 073 } 074 if (value instanceof Timestamp) { 075 return new Date(((Timestamp) value).getTime()); 076 } 077 if (value instanceof LocalDate) { 078 return DateUtil.toDate((LocalDate) value); 079 } 080 if (value instanceof LocalDateTime) { 081 return DateUtil.toDate((LocalDateTime) value); 082 } 083 if (value instanceof LocalTime) { 084 return DateUtil.toDate((LocalTime) value); 085 } 086 String s = value.toString(); 087 if (StringUtil.isNumeric(s)) { 088 return new Date(Long.parseLong(s)); 089 } 090 return DateUtil.parseDate(s); 091 } 092 093 094 095 public static Date parseDate(String dateString) { 096 if (StringUtil.isBlank(dateString)) { 097 return null; 098 } 099 dateString = dateString.trim(); 100 try { 101 SimpleDateFormat sdf = getSimpleDateFormat(getPattern(dateString)); 102 try { 103 return sdf.parse(dateString); 104 } catch (ParseException ex) { 105 //2022-10-23 00:00:00.0 106 int lastIndexOf = dateString.lastIndexOf("."); 107 if (lastIndexOf == 19) { 108 return parseDate(dateString.substring(0, lastIndexOf)); 109 } 110 111 //2022-10-23 00:00:00,0 112 lastIndexOf = dateString.lastIndexOf(","); 113 if (lastIndexOf == 19) { 114 return parseDate(dateString.substring(0, lastIndexOf)); 115 } 116 117 //2022-10-23 00:00:00 000123 118 lastIndexOf = dateString.lastIndexOf(" "); 119 if (lastIndexOf == 19) { 120 return parseDate(dateString.substring(0, lastIndexOf)); 121 } 122 123 if (dateString.contains(".") || dateString.contains("/")) { 124 dateString = dateString.replace(".", "-").replace("/", "-"); 125 return sdf.parse(dateString); 126 } else { 127 throw ex; 128 } 129 } 130 } catch (ParseException ex) { 131 throw new IllegalArgumentException("The date format is not supported for the date string: " + dateString); 132 } 133 } 134 135 136 137 public static LocalDateTime parseLocalDateTime(String dateString) { 138 if (StringUtil.isBlank(dateString)) { 139 return null; 140 } 141 dateString = dateString.trim(); 142 DateTimeFormatter dateTimeFormatter = getDateTimeFormatter(getPattern(dateString)); 143 try { 144 return LocalDateTime.parse(dateString, dateTimeFormatter); 145 } catch (Exception ex) { 146 //2022-10-23 00:00:00.0 147 int lastIndexOf = dateString.lastIndexOf("."); 148 if (lastIndexOf == 19) { 149 return parseLocalDateTime(dateString.substring(0, lastIndexOf)); 150 } 151 152 //2022-10-23 00:00:00,0 153 lastIndexOf = dateString.lastIndexOf(","); 154 if (lastIndexOf == 19) { 155 return parseLocalDateTime(dateString.substring(0, lastIndexOf)); 156 } 157 158 //2022-10-23 00:00:00 000123 159 lastIndexOf = dateString.lastIndexOf(" "); 160 if (lastIndexOf == 19) { 161 return parseLocalDateTime(dateString.substring(0, lastIndexOf)); 162 } 163 164 if (dateString.contains(".") || dateString.contains("/")) { 165 dateString = dateString.replace(".", "-").replace("/", "-"); 166 dateTimeFormatter = getDateTimeFormatter(getPattern(dateString)); 167 return LocalDateTime.parse(dateString, dateTimeFormatter); 168 } else { 169 throw ex; 170 } 171 } 172 } 173 174 175 private static String getPattern(String dateString) { 176 int length = dateString.length(); 177 if (length == datetimePattern.length()) { 178 return datetimePattern; 179 } else if (length == datePattern.length()) { 180 return datePattern; 181 } else if (length == dateMinutePattern.length()) { 182 if (dateString.contains("T")) { 183 return dateMinutePattern2; 184 } 185 return dateMinutePattern; 186 } else if (length == dateMillisecondPattern.length()) { 187 return dateMillisecondPattern; 188 } else if (length == datePatternWithoutDividing.length()) { 189 return datePatternWithoutDividing; 190 } else if (length == dateCSTPattern.length()) { 191 return dateCSTPattern; 192 } else { 193 throw new IllegalArgumentException("The date format is not supported for the date string: " + dateString); 194 } 195 } 196 197 198 public static LocalDateTime toLocalDateTime(Date date) { 199 if (date == null) { 200 return null; 201 } 202 // java.sql.Date 不支持 toInstant(),需要先转换成 java.util.Date 203 if (date instanceof java.sql.Date) { 204 date = new Date(date.getTime()); 205 } 206 207 Instant instant = date.toInstant(); 208 ZoneId zone = ZoneId.systemDefault(); 209 return LocalDateTime.ofInstant(instant, zone); 210 } 211 212 213 public static LocalDate toLocalDate(Date date) { 214 if (date == null) { 215 return null; 216 } 217 // java.sql.Date 不支持 toInstant(),需要先转换成 java.util.Date 218 if (date instanceof java.sql.Date) { 219 date = new Date(date.getTime()); 220 } 221 222 Instant instant = date.toInstant(); 223 ZoneId zone = ZoneId.systemDefault(); 224 LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone); 225 return localDateTime.toLocalDate(); 226 } 227 228 229 public static LocalTime toLocalTime(Date date) { 230 if (date == null) { 231 return null; 232 } 233 // java.sql.Date 不支持 toInstant(),需要先转换成 java.util.Date 234 if (date instanceof java.sql.Date) { 235 date = new Date(date.getTime()); 236 } 237 238 Instant instant = date.toInstant(); 239 ZoneId zone = ZoneId.systemDefault(); 240 LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone); 241 return localDateTime.toLocalTime(); 242 } 243 244 245 public static Date toDate(LocalDateTime localDateTime) { 246 if (localDateTime == null) { 247 return null; 248 } 249 ZoneId zone = ZoneId.systemDefault(); 250 Instant instant = localDateTime.atZone(zone).toInstant(); 251 return Date.from(instant); 252 } 253 254 255 public static Date toDate(LocalDate localDate) { 256 if (localDate == null) { 257 return null; 258 } 259 ZoneId zone = ZoneId.systemDefault(); 260 Instant instant = localDate.atStartOfDay().atZone(zone).toInstant(); 261 return Date.from(instant); 262 } 263 264 265 public static Date toDate(LocalTime localTime) { 266 if (localTime == null) { 267 return null; 268 } 269 LocalDate localDate = LocalDate.now(); 270 LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime); 271 ZoneId zone = ZoneId.systemDefault(); 272 Instant instant = localDateTime.atZone(zone).toInstant(); 273 return Date.from(instant); 274 } 275 276 277 public static String toDateTimeString(Date date) { 278 return toString(date, datetimePattern); 279 } 280 281 282 public static String toString(Date date, String pattern) { 283 return date == null ? null : getSimpleDateFormat(pattern).format(date); 284 } 285 286 287}