001/* 002 * Copyright 2017 Anyware Services 003 * 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 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 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 org.ametys.core.util; 017 018import java.time.Duration; 019import java.time.Instant; 020import java.time.LocalDate; 021import java.time.LocalDateTime; 022import java.time.ZoneId; 023import java.time.ZonedDateTime; 024import java.time.chrono.IsoChronology; 025import java.time.format.DateTimeFormatter; 026import java.time.format.ResolverStyle; 027import java.util.Date; 028 029import org.apache.commons.lang3.StringUtils; 030 031/** 032 * Helper for converting dates from the old ({@link Date}) to the new ({@link java.time}) JDK 033 * Special thanks to http://stackoverflow.com/questions/21242110/convert-java-util-date-to-java-time-localdate#answer-27378709 034 * which inspired this code 035 * 036 * See also http://stackoverflow.com/questions/19431234/converting-between-java-time-localdatetime-and-java-util-date 037 */ 038public final class DateUtils 039{ 040 /** 041 * The ISO date-time formatter that formats or parses a date-time with an offset, such as '2011-12-03T10:15:30.000+01:00'. 042 */ 043 private static DateTimeFormatter __ISO_OFFSET_DATE_TIME = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX").withResolverStyle(ResolverStyle.STRICT).withChronology(IsoChronology.INSTANCE); 044 045 private DateUtils() 046 { 047 // empty 048 } 049 050 /** 051 * Converts this {@link Date} object to an {@link Instant}. 052 * @param date The date object 053 * @return an instant representing the same point on the time-line as this {@link Date} object 054 */ 055 public static Instant asInstant(Date date) 056 { 057 return date == null ? null : date.toInstant(); 058 } 059 060 /** 061 * Converts this {@link Date} object to an {@link Instant}. 062 * @param date The date object 063 * @param zone The zone 064 * @return an instant representing the same point on the time-line as this {@link Date} object 065 */ 066 public static ZonedDateTime asZonedDateTime(Date date, ZoneId zone) 067 { 068 return date == null ? null : asInstant(date).atZone(zone != null ? zone : ZoneId.systemDefault()); 069 } 070 071 /** 072 * Converts this {@link Date} object to a {@link LocalDate}. 073 * 074 * This returns a {@link LocalDate} with the same year, month and day as this {@link Date}. 075 * @param date The date object 076 * @param zone The zone 077 * @return the {@link LocalDate} part of this {@link Date} 078 */ 079 public static LocalDate asLocalDate(Date date, ZoneId zone) 080 { 081 return asZonedDateTime(date, zone).toLocalDate(); 082 } 083 084 /** 085 * Converts this {@link Date} object to a {@link LocalDate}. 086 * 087 * This returns a {@link LocalDate} with the same year, month and day as this {@link Date}. 088 * @param date The date object 089 * @return the {@link LocalDate} part of this {@link Date} 090 */ 091 public static LocalDate asLocalDate(Date date) 092 { 093 return asLocalDate(date, ZoneId.systemDefault()); 094 } 095 096 /** 097 * Converts this {@link Date} object to a {@link LocalDateTime}. 098 * 099 * This returns a {@link LocalDateTime} with the same year, month, day and time as this {@link Date}. 100 * @param date The date object 101 * @param zone The zone 102 * @return the {@link LocalDateTime} part of this {@link Date} 103 */ 104 public static LocalDateTime asLocalDateTime(Date date, ZoneId zone) 105 { 106 return asZonedDateTime(date, zone).toLocalDateTime(); 107 } 108 109 /** 110 * Converts this {@link Date} object to a {@link LocalDateTime}. 111 * 112 * This returns a {@link LocalDateTime} with the same year, month, day and time as this {@link Date}. 113 * @param date The date object 114 * @return the {@link LocalDateTime} part of this {@link Date} 115 */ 116 public static LocalDateTime asLocalDateTime(Date date) 117 { 118 return asLocalDateTime(date, ZoneId.systemDefault()); 119 } 120 121 /** 122 * Converts this {@link LocalDate} object to a {@link Date}. 123 * 124 * @param localDate The local date object 125 * @return the {@link Date} part of this {@link LocalDate} 126 */ 127 public static Date asDate(LocalDate localDate) 128 { 129 return asDate(localDate, ZoneId.systemDefault()); 130 } 131 132 /** 133 * Converts this {@link LocalDate} object to a {@link Date}. 134 * 135 * @param localDate The local date object 136 * @param zone The zone 137 * @return the {@link Date} part of this {@link LocalDate} 138 */ 139 public static Date asDate(LocalDate localDate, ZoneId zone) 140 { 141 return Date.from(localDate.atStartOfDay().atZone(zone).toInstant()); 142 } 143 144 /** 145 * Converts this {@link LocalDateTime} object to a {@link Date}. 146 * 147 * @param localDateTime The local date time object 148 * @return the {@link Date} part of this {@link LocalDateTime} 149 */ 150 public static Date asDate(LocalDateTime localDateTime) 151 { 152 return asDate(localDateTime, ZoneId.systemDefault()); 153 } 154 155 /** 156 * Converts this {@link LocalDateTime} object to a {@link Date}. 157 * 158 * @param localDateTime The local date time object 159 * @param zone The zone 160 * @return the {@link Date} part of this {@link LocalDateTime} 161 */ 162 public static Date asDate(LocalDateTime localDateTime, ZoneId zone) 163 { 164 return Date.from(localDateTime.atZone(zone).toInstant()); 165 } 166 167 /** 168 * Converts this {@link ZonedDateTime} object to a {@link Date}. 169 * 170 * @param zonedDateTime The local date time object 171 * @return the {@link Date} part of this {@link LocalDateTime} 172 */ 173 public static Date asDate(ZonedDateTime zonedDateTime) 174 { 175 return Date.from(zonedDateTime.toInstant()); 176 } 177 178 /** 179 * Format a duration for logs 180 * @param duration duration to log 181 * @return a string representing the duration 182 */ 183 public static String formatDuration(Duration duration) 184 { 185 return formatDuration(duration.toMillis()); 186 } 187 188 /** 189 * Format a duration for logs 190 * @param duration miliseconds representing the duration 191 * @return a string representing the duration 192 */ 193 public static String formatDuration(long duration) 194 { 195 StringBuilder sb = new StringBuilder(); 196 long durationCopy = duration; 197 long ms = durationCopy % 1000; 198 durationCopy /= 1000; 199 long s = durationCopy % 60; 200 durationCopy /= 60; 201 long m = durationCopy % 60; 202 durationCopy /= 60; 203 long h = durationCopy % 24; 204 durationCopy /= 24; 205 206 boolean showDays = durationCopy > 0; 207 boolean showHours = showDays || h > 0; 208 boolean showMinuts = showHours || m > 0; 209 boolean showSeconds = showMinuts || s > 0; 210 211 if (showDays) 212 { 213 sb.append(durationCopy); 214 sb.append("j "); 215 } 216 if (showHours) 217 { 218 sb.append(formatNumber(h, 2)); 219 sb.append("h "); 220 } 221 if (showMinuts) 222 { 223 sb.append(formatNumber(m, 2)); 224 sb.append("m "); 225 } 226 if (showSeconds) 227 { 228 sb.append(formatNumber(s, 2)); 229 sb.append("s "); 230 } 231 sb.append(formatNumber(ms, 3)); 232 sb.append("ms"); 233 return sb.toString(); 234 } 235 private static String formatNumber(long number, int nbNumbers) 236 { 237 String numberFormatted = String.valueOf(number); 238 while (numberFormatted.length() < nbNumbers) 239 { 240 numberFormatted = "0" + numberFormatted; 241 } 242 return numberFormatted; 243 } 244 245 /** 246 * Get the ISO date-time formatter that formats or parses a date-time with an offset, such as '2011-12-03T10:15:30.000+01:00'. 247 * This formatter is similar to {@link DateTimeFormatter#ISO_OFFSET_DATE_TIME} but force 3-digits milliseconds. 248 * @return ISO date-time formatter 249 */ 250 public static DateTimeFormatter getISODateTimeFormatter() 251 { 252 return __ISO_OFFSET_DATE_TIME; 253 } 254 255 /** 256 * Converts a {@link Date} object to {@link String} using the ISO date formatter 257 * @param value the value to convert 258 * @return the date as a {@link String} 259 */ 260 public static String dateToString(Date value) 261 { 262 if (value == null) 263 { 264 return null; 265 } 266 267 ZonedDateTime zdt = DateUtils.asZonedDateTime(value, null); 268 return zdt.format(getISODateTimeFormatter()); 269 } 270 271 /** 272 * Parses a String into a {@link Date}, using ISO 8601 format. 273 * @param value an ISO 8601 formatted String. 274 * @return the corresponding Date, or null if the input is null. 275 */ 276 public static Date parse(String value) 277 { 278 if (StringUtils.isEmpty(value)) 279 { 280 return null; 281 } 282 283 LocalDateTime ldt = LocalDateTime.parse(value, DateTimeFormatter.ISO_DATE_TIME); 284 return asDate(ldt); 285 } 286}