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    public static String printDuration(Duration uptime) {
039        return printDuration(uptime.toMillis(), true);
040    }
041
042    /**
043     * Prints the duration in a human readable format as X days Y hours Z minutes etc.
044     *
045     * @param  uptime the uptime in millis
046     * @return        the time used for displaying on screen or in logs
047     */
048    public static String printDuration(long uptime) {
049        return printDuration(uptime, false);
050    }
051
052    /**
053     * Prints the duration in a human readable format as X days Y hours Z minutes etc.
054     *
055     * @param  uptime  the uptime in millis
056     * @param  precise whether to be precise and include all details including milli seconds
057     * @return         the time used for displaying on screen or in logs
058     */
059    public static String printDuration(long uptime, boolean precise) {
060        if (uptime <= 0) {
061            return "0ms";
062        }
063
064        StringBuilder sb = new StringBuilder();
065
066        long seconds = uptime / 1000;
067        long minutes = seconds / 60;
068        long hours = minutes / 60;
069        long days = hours / 24;
070        long millis = 0;
071        if (uptime > 1000) {
072            millis = uptime % 1000;
073        } else if (uptime < 1000) {
074            millis = uptime;
075        }
076
077        if (days > 0) {
078            sb.append(days).append("d").append(hours % 24).append("h").append(minutes % 60).append("m").append(seconds % 60)
079                    .append("s");
080        } else if (hours > 0) {
081            sb.append(hours % 24).append("h").append(minutes % 60).append("m").append(seconds % 60).append("s");
082        } else if (minutes > 0) {
083            sb.append(minutes % 60).append("m").append(seconds % 60).append("s");
084        } else if (seconds > 0) {
085            sb.append(seconds % 60).append("s");
086            // lets include millis when there are only seconds by default
087            precise = true;
088        } else if (millis > 0) {
089            precise = false;
090            sb.append(millis).append("ms");
091        }
092
093        if (precise & millis > 0) {
094            sb.append(millis).append("ms");
095        }
096
097        return sb.toString();
098    }
099
100    public static Duration toDuration(String source) throws IllegalArgumentException {
101        return Duration.ofMillis(toMilliSeconds(source));
102    }
103
104    public static long toMilliSeconds(String source) throws IllegalArgumentException {
105        // quick conversion if its only digits
106        boolean digit = true;
107        for (int i = 0; i < source.length(); i++) {
108            char ch = source.charAt(i);
109            // special for fist as it can be negative number
110            if (i == 0 && ch == '-') {
111                continue;
112            }
113            // quick check if its 0..9
114            if (ch < '0' || ch > '9') {
115                digit = false;
116                break;
117            }
118        }
119        if (digit) {
120            return Long.parseLong(source);
121        }
122
123        long days = 0;
124        long hours = 0;
125        long minutes = 0;
126        long seconds = 0;
127        long millis = 0;
128
129        int pos = source.indexOf('d');
130        if (pos != -1) {
131            String s = source.substring(0, pos);
132            days = Long.parseLong(s);
133            source = source.substring(pos + 1);
134        }
135
136        pos = source.indexOf('h');
137        if (pos != -1) {
138            String s = source.substring(0, pos);
139            hours = Long.parseLong(s);
140            source = source.substring(pos + 1);
141        }
142
143        pos = source.indexOf('m');
144        if (pos != -1) {
145            boolean valid;
146            if (source.length() - 1 <= pos) {
147                valid = true;
148            } else {
149                // beware of minutes and not milli seconds
150                valid = source.charAt(pos + 1) != 's';
151            }
152            if (valid) {
153                String s = source.substring(0, pos);
154                minutes = Long.parseLong(s);
155                source = source.substring(pos + 1);
156            }
157        }
158
159        pos = source.indexOf('s');
160        // beware of seconds and not milli seconds
161        if (pos != -1 && source.charAt(pos - 1) != 'm') {
162            String s = source.substring(0, pos);
163            seconds = Long.parseLong(s);
164            source = source.substring(pos + 1);
165        }
166
167        pos = source.indexOf("ms");
168        if (pos != -1) {
169            String s = source.substring(0, pos);
170            millis = Long.parseLong(s);
171        }
172
173        long answer = millis;
174        if (seconds > 0) {
175            answer += 1000 * seconds;
176        }
177        if (minutes > 0) {
178            answer += 60000 * minutes;
179        }
180        if (hours > 0) {
181            answer += 3600000 * hours;
182        }
183        if (days > 0) {
184            answer += 86400000 * days;
185        }
186
187        LOG.trace("source: [{}], milliseconds: {}", source, answer);
188
189        return answer;
190    }
191
192}