001/**
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v1.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.core.util;
015
016import java.util.regex.Matcher;
017import java.util.regex.Pattern;
018
019/**
020 * Duration instances represent a lapse of time. Internally, the duration is
021 * stored in milliseconds. However, whenever a parameter of type Duration is
022 * expected, Joran (logback's configuration system) will automatically convert
023 * strings such as "20 seconds" "3.5 minutes" or "5 hours" into Duration
024 * instances.
025 *
026 * <p>
027 * The recognized units of time are the "millisecond", "second", "minute" "hour"
028 * and "day". The unit name may be followed by an "s". Thus, "2 day" and "2
029 * days" are equivalent. In the absence of a time unit specification,
030 * milliseconds are assumed.
031 * 
032 * <p>
033 * Note: the conversion magic is entirely due to the fact that this class
034 * follows the {@link #valueOf} convention.
035 *
036 * @author Ceki Gulcu
037 */
038public class Duration {
039
040    private final static String DOUBLE_PART = "([0-9]*(.[0-9]+)?)";
041    private final static int DOUBLE_GROUP = 1;
042
043    private final static String UNIT_PART = "(|milli(second)?|second(e)?|minute|hour|day)s?";
044    private final static int UNIT_GROUP = 3;
045
046    private static final Pattern DURATION_PATTERN = Pattern.compile(DOUBLE_PART + "\\s*" + UNIT_PART,
047            Pattern.CASE_INSENSITIVE);
048
049    static final long SECONDS_COEFFICIENT = 1000;
050    static final long MINUTES_COEFFICIENT = 60 * SECONDS_COEFFICIENT;
051    static final long HOURS_COEFFICIENT = 60 * MINUTES_COEFFICIENT;
052    static final long DAYS_COEFFICIENT = 24 * HOURS_COEFFICIENT;
053
054    final long millis;
055
056    public Duration(long millis) {
057        this.millis = millis;
058    }
059
060    public static Duration buildByMilliseconds(double value) {
061        return new Duration((long) (value));
062    }
063
064    public static Duration buildBySeconds(double value) {
065        return new Duration((long) (SECONDS_COEFFICIENT * value));
066    }
067
068    public static Duration buildByMinutes(double value) {
069        return new Duration((long) (MINUTES_COEFFICIENT * value));
070    }
071
072    public static Duration buildByHours(double value) {
073        return new Duration((long) (HOURS_COEFFICIENT * value));
074    }
075
076    public static Duration buildByDays(double value) {
077        return new Duration((long) (DAYS_COEFFICIENT * value));
078    }
079
080    public static Duration buildUnbounded() {
081        return new Duration(Long.MAX_VALUE);
082    }
083
084    public long getMilliseconds() {
085        return millis;
086    }
087
088    public static Duration valueOf(String durationStr) {
089        Matcher matcher = DURATION_PATTERN.matcher(durationStr);
090
091        if (matcher.matches()) {
092            String doubleStr = matcher.group(DOUBLE_GROUP);
093            String unitStr = matcher.group(UNIT_GROUP);
094
095            double doubleValue = Double.valueOf(doubleStr);
096            if (unitStr.equalsIgnoreCase("milli") || unitStr.equalsIgnoreCase("millisecond") || unitStr.length() == 0) {
097                return buildByMilliseconds(doubleValue);
098            } else if (unitStr.equalsIgnoreCase("second") || unitStr.equalsIgnoreCase("seconde")) {
099                return buildBySeconds(doubleValue);
100            } else if (unitStr.equalsIgnoreCase("minute")) {
101                return buildByMinutes(doubleValue);
102            } else if (unitStr.equalsIgnoreCase("hour")) {
103                return buildByHours(doubleValue);
104            } else if (unitStr.equalsIgnoreCase("day")) {
105                return buildByDays(doubleValue);
106            } else {
107                throw new IllegalStateException("Unexpected " + unitStr);
108            }
109        } else {
110            throw new IllegalArgumentException("String value [" + durationStr + "] is not in the expected format.");
111        }
112    }
113
114    @Override
115    public String toString() {
116        if (millis < SECONDS_COEFFICIENT) {
117            return millis + " milliseconds";
118        } else if (millis < MINUTES_COEFFICIENT) {
119            return millis / SECONDS_COEFFICIENT + " seconds";
120        } else if (millis < HOURS_COEFFICIENT) {
121            return millis / MINUTES_COEFFICIENT + " minutes";
122        } else {
123            return millis / HOURS_COEFFICIENT + " hours";
124        }
125
126    }
127}