1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.tradefed.util; 18 19 import com.google.common.math.LongMath; 20 21 import java.util.regex.Matcher; 22 import java.util.regex.Pattern; 23 24 /** 25 * This is a sentinel type which wraps a {@code Long}. It exists solely as a hint to the options 26 * parsing machinery that a particular value should be parsed as if it were a string representing a 27 * time value. 28 * 29 * @deprecated use {@link java.time.Duration} instead. 30 */ 31 @SuppressWarnings("serial") 32 @Deprecated 33 public class TimeVal extends Number implements Comparable<Long> { 34 private static final Pattern TIME_PATTERN = 35 Pattern.compile("(?i)" + // case insensitive 36 "(?:(?<d>\\d+)d)?" + // a number followed by "d" 37 "(?:(?<h>\\d+)h)?" + 38 "(?:(?<m>\\d+)m)?" + 39 "(?:(?<s>\\d+)s)?" + 40 "(?:(?<ms>\\d+)(?:ms)?)?"); // a number followed by "ms" 41 42 private Long mValue = null; 43 44 /** 45 * Constructs a newly allocated TimeVal object that represents the specified Long argument 46 */ TimeVal(Long value)47 public TimeVal(Long value) { 48 mValue = value; 49 } 50 51 /** 52 * Constructs a newly allocated TimeVal object that represents the <emph>timestamp</emph> 53 * indicated by the String parameter. The string is converted to a TimeVal in exactly the 54 * manner used by the {@link #fromString(String)} method. 55 */ TimeVal(String value)56 public TimeVal(String value) throws NumberFormatException { 57 mValue = fromString(value); 58 } 59 60 /** 61 * @return the wrapped {@code Long} value. 62 */ asLong()63 public Long asLong() { 64 return mValue; 65 } 66 67 /** 68 * Parses the string as a hierarchical time value 69 * <p /> 70 * The default unit is millis. The parser will accept {@code s} for seconds (1000 millis), 71 * {@code m} for minutes (60 seconds), {@code h} for hours (60 minutes), or {@code d} for days 72 * (24 hours). 73 * <p /> 74 * Units may be mixed and matched, so long as each unit appears at most once, and so long as 75 * all units which do appear are listed in decreasing order of scale. So, for instance, 76 * {@code h} may only appear before {@code m}, and may only appear after {@code d}. As a 77 * specific example, "1d2h3m4s5ms" would be a valid time value, as would "4" or "4ms". All 78 * embedded whitespace is discarded. 79 * <p /> 80 * Do note that this method rejects overflows. So the output number is guaranteed to be 81 * non-negative, and to fit within the {@code long} type. 82 */ fromString(String value)83 public static long fromString(String value) throws NumberFormatException { 84 if (value == null) throw new NumberFormatException("value is null"); 85 86 try { 87 value = value.replaceAll("\\s+", ""); 88 Matcher m = TIME_PATTERN.matcher(value); 89 if (m.matches()) { 90 // This works by, essentially, modifying the units of timeValue, from the 91 // largest supported unit, until we've dropped down to millis. 92 long timeValue = 0; 93 timeValue = val(m.group("d")); 94 95 // 1 day == 24 hours 96 timeValue = LongMath.checkedMultiply(timeValue, 24); 97 timeValue = LongMath.checkedAdd(timeValue, val(m.group("h"))); 98 99 // 1 hour == 60 minutes 100 timeValue = LongMath.checkedMultiply(timeValue, 60); 101 timeValue = LongMath.checkedAdd(timeValue, val(m.group("m"))); 102 103 // 1 hour == 60 seconds 104 timeValue = LongMath.checkedMultiply(timeValue, 60); 105 timeValue = LongMath.checkedAdd(timeValue, val(m.group("s"))); 106 107 // 1 second == 1000 millis 108 timeValue = LongMath.checkedMultiply(timeValue, 1000); 109 timeValue = LongMath.checkedAdd(timeValue, val(m.group("ms"))); 110 111 return timeValue; 112 } 113 } catch (ArithmeticException e) { 114 throw new NumberFormatException(String.format( 115 "Failed to parse value %s as a time value: %s", value, e.getMessage())); 116 } 117 118 throw new NumberFormatException( 119 String.format("Failed to parse value %s as a time value", value)); 120 } 121 val(String str)122 static long val(String str) throws NumberFormatException { 123 if (str == null) return 0; 124 125 Long value = Long.parseLong(str); 126 return value; 127 } 128 129 130 // implementing interfaces 131 /** 132 * {@inheritDoc} 133 */ 134 @Override doubleValue()135 public double doubleValue() { 136 return mValue.doubleValue(); 137 } 138 139 /** 140 * {@inheritDoc} 141 */ 142 @Override floatValue()143 public float floatValue() { 144 return mValue.floatValue(); 145 } 146 147 /** 148 * {@inheritDoc} 149 */ 150 @Override intValue()151 public int intValue() { 152 return mValue.intValue(); 153 } 154 155 /** 156 * {@inheritDoc} 157 */ 158 @Override longValue()159 public long longValue() { 160 return mValue.longValue(); 161 } 162 163 /** 164 * {@inheritDoc} 165 */ 166 @Override compareTo(Long other)167 public int compareTo(Long other) { 168 return mValue.compareTo(other); 169 } 170 } 171