
co.cask.tracker.utils.TimeMathParser Maven / Gradle / Ivy
/*
* Copyright © 2016 Cask Data, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package co.cask.tracker.utils;
import com.google.common.base.Preconditions;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Utility class for parsing time strings into timestamps, with support for some basic time math.
* Math syntax includes addition and subtraction in minutes, hours, and days.
* The "NOW" keyword translates to the current epoch time in seconds, and can be strung together with
* various additions and subtractions. For example, "NOW" will translate into the current epoch time in seconds.
* "NOW-5SECONDS" is 5 seconds before now, "NOW-1DAY" is one day before now, and "NOW-1DAY+4HOURS" is 20 hours
* before now.
*
*/
public class TimeMathParser {
private static final String NOW = "now";
private static final String VALID_UNITS = "ms|s|m|h|d";
private static final Pattern OP_PATTERN = Pattern.compile("(\\-|\\+)(\\d+)(" + VALID_UNITS + ")");
private static final Pattern RESOLUTION_PATTERN = Pattern.compile("(\\d+)(" + VALID_UNITS + ")");
private static final Pattern TIMESTAMP_PATTERN = Pattern.compile("^(\\d+)$");
private static long convertToMilliseconds(String op, long num, String unitStr) {
long milliseconds;
if ("ms".equals(unitStr)) {
milliseconds = num;
} else if ("s".equals(unitStr)) {
milliseconds = TimeUnit.SECONDS.toMillis(num);
} else if ("m".equals(unitStr)) {
milliseconds = TimeUnit.MINUTES.toMillis(num);
} else if ("h".equals(unitStr)) {
milliseconds = TimeUnit.HOURS.toMillis(num);
} else if ("d".equals(unitStr)) {
milliseconds = TimeUnit.DAYS.toMillis(num);
} else {
throw new IllegalArgumentException("invalid time unit " + unitStr +
", should be one of 'ms', 's', 'm', 'h', 'd'");
}
if ("+".equals(op)) {
return milliseconds;
} else if ("-".equals(op)) {
return 0 - milliseconds;
} else {
throw new IllegalArgumentException("invalid operation " + op + ", should be either '+' or '-'");
}
}
private static long convertToMilliseconds(long num, String unitStr) {
return convertToMilliseconds("+", num, unitStr);
}
/**
* @return the current time in seconds
*/
public static long nowInSeconds() {
return TimeUnit.SECONDS.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
public static int resolutionInSeconds(String resolutionStr) {
Matcher matcher = RESOLUTION_PATTERN.matcher(resolutionStr);
int output = 0;
while (matcher.find()) {
output += TimeUnit.MILLISECONDS.toSeconds(convertToMilliseconds(Long.parseLong(matcher.group(1)),
matcher.group(2)));
}
return output;
}
/**
* Parses a time in String format into a long value. If the input is numeric we assume the input is in seconds.
*
* @param timeStr the string to parse
* @return the parsed time in seconds
*/
public static long parseTimeInSeconds(String timeStr) {
return parseTime(timeStr, TimeUnit.SECONDS);
}
/**
* Parses a time in String format into a long value.
*
* @param timeStr the string to parse
* @param timeUnit the unit of time to return, if timeStr is numeric then it is assumed to be in the unit timeUnit
* @return the parsed time
*/
public static long parseTime(String timeStr, TimeUnit timeUnit) {
return parseTime(System.currentTimeMillis(), timeStr, timeUnit);
}
/**
* Parses a time in String format into a long value. If the input is numeric we assume the input is in seconds.
*
* @param now the present time in seconds
* @param timeStr the string to parse
* @return the parsed time in seconds
*/
public static long parseTimeInSeconds(long now, String timeStr) {
return parseTime(TimeUnit.MILLISECONDS.convert(now, TimeUnit.SECONDS), timeStr, TimeUnit.SECONDS);
}
/**
* Parses a time in String format into a long value.
*
* @param now the present time in milliseconds
* @param timeStr the string to parse
* @param timeUnit the unit of time to return, if timeStr is numeric then it is assumed to be in the unit timeUnit
* @return the parsed time
* @throws IllegalArgumentException if the format of timeStr is bad
*/
public static long parseTime(long now, String timeStr, TimeUnit timeUnit) {
Preconditions.checkNotNull(timeStr);
if (NOW.equals(timeStr.toUpperCase())) {
return now;
}
// if its a numeric timestamp, assume units are correct
Matcher matcher = TIMESTAMP_PATTERN.matcher(timeStr);
if (matcher.matches()) {
return Long.parseLong(timeStr);
}
// if its some time math pattern like now-1d-6h
long output = now;
if (timeStr.startsWith(NOW)) {
matcher = OP_PATTERN.matcher(timeStr);
// start at 3 to take into account the NOW at the start of the string
int prevEndPos = 3;
while (matcher.find()) {
// happens if there are unexpected things in-between, like "now 2h-1m"
if (matcher.start() != prevEndPos) {
throw new IllegalArgumentException("invalid time format " + timeStr);
}
// group 1 should be '+' or '-', group 2 is the number of units, and group 3 is the unit. ex: 6h
output += convertToMilliseconds(matcher.group(1), Long.parseLong(matcher.group(2)), matcher.group(3));
prevEndPos = matcher.end();
}
// happens if the end of the string is invalid, like "now-6h 30m"
if (prevEndPos != timeStr.length()) {
throw new IllegalArgumentException("invalid time format " + timeStr);
}
} else {
throw new IllegalArgumentException("invalid time format " + timeStr);
}
return timeUnit.convert(output, TimeUnit.MILLISECONDS);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy