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