001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.camel.util; 018 019import java.time.Duration; 020 021import org.slf4j.Logger; 022import org.slf4j.LoggerFactory; 023 024/** 025 * Time utils. 026 */ 027public final class TimeUtils { 028 029 private static final Logger LOG = LoggerFactory.getLogger(TimeUtils.class); 030 031 private TimeUtils() { 032 } 033 034 public static boolean isPositive(Duration dur) { 035 return dur.getSeconds() > 0 || dur.getNano() != 0; 036 } 037 038 /** 039 * Prints since age in a human-readable format as 9s, 27m44s, 3h12m, 3d8h, as seen on Kubernetes etc. 040 * 041 * @param time time of the event (millis since epoch) 042 * @return age in human-readable since the given time. 043 */ 044 public static String printSince(long time) { 045 long age = System.currentTimeMillis() - time; 046 return printDuration(age, false); 047 } 048 049 /** 050 * Prints since age in a human-readable format as 9s, 27m44s, 3h12m, 3d8h, as seen on Kubernetes etc. 051 * 052 * @param time time of the event (millis since epoch) 053 * @param precise whether to be precise and include more details 054 * @return age in human-readable since the given time. 055 */ 056 public static String printSince(long time, boolean precise) { 057 long age = System.currentTimeMillis() - time; 058 return printDuration(age, precise); 059 } 060 061 /** 062 * Prints the age in a human-readable format as 9s, 27m44s, 3h12m, 3d8h, as seen on Kubernetes etc. 063 * 064 * @param age age in millis 065 * @return age in human-readable. 066 */ 067 public static String printAge(long age) { 068 return printDuration(age, false); 069 } 070 071 /** 072 * Prints the age in a human-readable format as 9s, 27m44s, 3h12m, 3d8h, as seen on Kubernetes etc. 073 * 074 * @param age age in millis 075 * @param precise whether to be precise and include more details 076 * @return age in human-readable. 077 */ 078 public static String printAge(long age, boolean precise) { 079 return printDuration(age, precise); 080 } 081 082 /** 083 * Prints the duration in a human-readable format as 9s, 27m44s, 3h12m, 3d8h, etc. 084 * 085 * @param uptime the uptime in millis 086 * @return the time used for displaying on screen or in logs 087 */ 088 public static String printDuration(Duration uptime) { 089 return printDuration(uptime, false); 090 } 091 092 /** 093 * Prints the duration in a human-readable format as 9s, 27m44s, 3h12m, 3d8h, etc. 094 * 095 * @param uptime the uptime in millis 096 * @param precise whether to be precise and include more details 097 * @return the time used for displaying on screen or in logs 098 */ 099 public static String printDuration(Duration uptime, boolean precise) { 100 return printDuration(uptime.toMillis(), precise); 101 } 102 103 /** 104 * Prints the duration in a human-readable format as 9s, 27m44s, 3h12m, 3d8h, etc. 105 * 106 * @param uptime the uptime in millis 107 * @return the time used for displaying on screen or in logs 108 */ 109 public static String printDuration(long uptime) { 110 return printDuration(uptime, false); 111 } 112 113 /** 114 * Prints the duration in a human-readable format as 9s, 27m44s, 3h12m, 3d8h, etc. 115 * 116 * @param uptime the uptime in millis 117 * @param precise whether to be precise and include more details 118 * @return the time used for displaying on screen or in logs 119 */ 120 public static String printDuration(long uptime, boolean precise) { 121 if (uptime <= 0) { 122 return "0ms"; 123 } 124 125 StringBuilder sb = new StringBuilder(); 126 127 long seconds = uptime / 1000; 128 long minutes = seconds / 60; 129 long hours = minutes / 60; 130 long days = hours / 24; 131 long millis = 0; 132 if (uptime > 1000) { 133 millis = uptime % 1000; 134 } else if (uptime < 1000) { 135 millis = uptime; 136 } 137 138 if (days > 0) { 139 sb.append(days).append("d").append(hours % 24).append("h"); 140 if (precise) { 141 sb.append(minutes % 60).append("m").append(seconds % 60).append("s"); 142 } 143 } else if (hours > 0) { 144 sb.append(hours % 24).append("h").append(minutes % 60).append("m"); 145 if (precise) { 146 sb.append(seconds % 60).append("s"); 147 } 148 } else if (minutes > 0) { 149 sb.append(minutes % 60).append("m").append(seconds % 60).append("s"); 150 if (precise) { 151 sb.append(millis).append("ms"); 152 } 153 } else if (seconds > 0) { 154 sb.append(seconds % 60).append("s"); 155 if (precise) { 156 sb.append(millis).append("ms"); 157 } 158 } else if (millis > 0) { 159 if (!precise) { 160 // less than a second so just report it as zero 161 sb.append("0s"); 162 } else { 163 sb.append(millis).append("ms"); 164 } 165 } 166 167 return sb.toString(); 168 } 169 170 /** 171 * Converts to duration. 172 * 173 * @param source duration which can be in text format such as 15s 174 */ 175 public static Duration toDuration(String source) { 176 return Duration.ofMillis(toMilliSeconds(source)); 177 } 178 179 /** 180 * Converts to milliseconds. 181 * 182 * @param source duration which can be in text format such as 15s 183 * @return time in millis, will return 0 if the input is null or empty 184 */ 185 public static long toMilliSeconds(String source) { 186 if (source == null || source.isEmpty()) { 187 return 0; 188 } 189 190 // quick conversion if its only digits 191 boolean digit = true; 192 for (int i = 0; i < source.length(); i++) { 193 char ch = source.charAt(i); 194 // special for fist as it can be negative number 195 if (i == 0 && ch == '-') { 196 continue; 197 } 198 // quick check if its 0..9 199 if (ch < '0' || ch > '9') { 200 digit = false; 201 break; 202 } 203 } 204 if (digit) { 205 return Long.parseLong(source); 206 } 207 208 long days = 0; 209 long hours = 0; 210 long minutes = 0; 211 long seconds = 0; 212 long millis = 0; 213 214 int pos = source.indexOf('d'); 215 if (pos != -1) { 216 String s = source.substring(0, pos); 217 days = Long.parseLong(s); 218 source = source.substring(pos + 1); 219 } 220 221 pos = source.indexOf('h'); 222 if (pos != -1) { 223 String s = source.substring(0, pos); 224 hours = Long.parseLong(s); 225 source = source.substring(pos + 1); 226 } 227 228 pos = source.indexOf('m'); 229 if (pos != -1) { 230 boolean valid; 231 if (source.length() - 1 <= pos) { 232 valid = true; 233 } else { 234 // beware of minutes and not milliseconds 235 valid = source.charAt(pos + 1) != 's'; 236 } 237 if (valid) { 238 String s = source.substring(0, pos); 239 minutes = Long.parseLong(s); 240 source = source.substring(pos + 1); 241 } 242 } 243 244 pos = source.indexOf('s'); 245 // beware of seconds and not milliseconds 246 if (pos != -1 && source.charAt(pos - 1) != 'm') { 247 String s = source.substring(0, pos); 248 seconds = Long.parseLong(s); 249 source = source.substring(pos + 1); 250 } 251 252 pos = source.indexOf("ms"); 253 if (pos != -1) { 254 String s = source.substring(0, pos); 255 millis = Long.parseLong(s); 256 } 257 258 long answer = millis; 259 if (seconds > 0) { 260 answer += 1000 * seconds; 261 } 262 if (minutes > 0) { 263 answer += 60000 * minutes; 264 } 265 if (hours > 0) { 266 answer += 3600000 * hours; 267 } 268 if (days > 0) { 269 answer += 86400000 * days; 270 } 271 272 LOG.trace("source: [{}], milliseconds: {}", source, answer); 273 274 return answer; 275 } 276 277 /** 278 * Elapsed time using milliseconds since epoch. 279 * 280 * @param start the timestamp in milliseconds since epoch 281 * @return the elapsed time in milliseconds 282 * @deprecated Use the Clock API when possible 283 */ 284 @Deprecated(since = "4.4.0") 285 public static long elapsedMillisSince(long start) { 286 return System.currentTimeMillis() - start; 287 } 288 289}