All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.logging.log4j.core.appender.rolling.action.Duration Maven / Gradle / Ivy

There is a newer version: 3.0.0-beta2
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.logging.log4j.core.appender.rolling.action;

import java.io.Serializable;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Simplified implementation of the ISO-8601 Durations
 * standard. The supported format is {@code PnDTnHnMnS}, with 'P' and 'T' optional. Days are considered to be exactly 24
 * hours.
 * 

* Similarly to the {@code java.time.Duration} class, this class does not support year or month sections in the format. * This implementation does not support fractions or negative values. * * @see #parse(CharSequence) */ public class Duration implements Serializable, Comparable { private static final long serialVersionUID = -3756810052716342061L; /** * Constant for a duration of zero. */ public static final Duration ZERO = new Duration(0); /** * Hours per day. */ private static final int HOURS_PER_DAY = 24; /** * Minutes per hour. */ private static final int MINUTES_PER_HOUR = 60; /** * Seconds per minute. */ private static final int SECONDS_PER_MINUTE = 60; /** * Seconds per hour. */ private static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR; /** * Seconds per day. */ private static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY; /** * The pattern for parsing. */ private static final Pattern PATTERN = Pattern.compile("P?(?:([0-9]+)D)?" + "(T?(?:([0-9]+)H)?(?:([0-9]+)M)?(?:([0-9]+)?S)?)?", Pattern.CASE_INSENSITIVE); /** * The number of seconds in the duration. */ private final long seconds; /** * Constructs an instance of {@code Duration} using seconds. * * @param seconds the length of the duration in seconds, positive or negative */ private Duration(final long seconds) { this.seconds = seconds; } /** * Obtains a {@code Duration} from a text string such as {@code PnDTnHnMnS}. *

* This will parse a textual representation of a duration, including the string produced by {@code toString()}. The * formats accepted are based on the ISO-8601 duration format {@code PnDTnHnMnS} with days considered to be exactly * 24 hours. *

* This implementation does not support negative numbers or fractions (so the smallest non-zero value a Duration can * have is one second). *

* The string optionally starts with the ASCII letter "P" in upper or lower case. There are then four sections, each * consisting of a number and a suffix. The sections have suffixes in ASCII of "D", "H", "M" and "S" for days, * hours, minutes and seconds, accepted in upper or lower case. The suffixes must occur in order. The ASCII letter * "T" may occur before the first occurrence, if any, of an hour, minute or second section. At least one of the four * sections must be present, and if "T" is present there must be at least one section after the "T". The number part * of each section must consist of one or more ASCII digits. The number may not be prefixed by the ASCII negative or * positive symbol. The number of days, hours, minutes and seconds must parse to a {@code long}. *

* Examples: * *

     *    "PT20S" -- parses as "20 seconds"
     *    "PT15M"     -- parses as "15 minutes" (where a minute is 60 seconds)
     *    "PT10H"     -- parses as "10 hours" (where an hour is 3600 seconds)
     *    "P2D"       -- parses as "2 days" (where a day is 24 hours or 86400 seconds)
     *    "P2DT3H4M"  -- parses as "2 days, 3 hours and 4 minutes"
     * 
* * @param text the text to parse, not null * @return the parsed duration, not null * @throws IllegalArgumentException if the text cannot be parsed to a duration */ public static Duration parse(final CharSequence text) { Objects.requireNonNull(text, "text"); final Matcher matcher = PATTERN.matcher(text); if (matcher.matches()) { // check for letter T but no time sections if ("T".equals(matcher.group(2)) == false) { final String dayMatch = matcher.group(1); final String hourMatch = matcher.group(3); final String minuteMatch = matcher.group(4); final String secondMatch = matcher.group(5); if (dayMatch != null || hourMatch != null || minuteMatch != null || secondMatch != null) { final long daysAsSecs = parseNumber(text, dayMatch, SECONDS_PER_DAY, "days"); final long hoursAsSecs = parseNumber(text, hourMatch, SECONDS_PER_HOUR, "hours"); final long minsAsSecs = parseNumber(text, minuteMatch, SECONDS_PER_MINUTE, "minutes"); final long seconds = parseNumber(text, secondMatch, 1, "seconds"); try { return create(daysAsSecs, hoursAsSecs, minsAsSecs, seconds); } catch (final ArithmeticException ex) { throw new IllegalArgumentException("Text cannot be parsed to a Duration (overflow) " + text, ex); } } } } throw new IllegalArgumentException("Text cannot be parsed to a Duration: " + text); } private static long parseNumber(final CharSequence text, final String parsed, final int multiplier, final String errorText) { // regex limits to [0-9]+ if (parsed == null) { return 0; } try { final long val = Long.parseLong(parsed); return val * multiplier; } catch (final Exception ex) { throw new IllegalArgumentException("Text cannot be parsed to a Duration: " + errorText + " (in " + text + ")", ex); } } private static Duration create(final long daysAsSecs, final long hoursAsSecs, final long minsAsSecs, final long secs) { return create(daysAsSecs + hoursAsSecs + minsAsSecs + secs); } /** * Obtains an instance of {@code Duration} using seconds. * * @param seconds the length of the duration in seconds, positive only */ private static Duration create(final long seconds) { if ((seconds) == 0) { return ZERO; } return new Duration(seconds); } /** * Converts this duration to the total length in milliseconds. * * @return the total length of the duration in milliseconds */ public long toMillis() { return seconds * 1000L; } @Override public boolean equals(final Object obj) { if (obj == this) { return true; } if (!(obj instanceof Duration)) { return false; } final Duration other = (Duration) obj; return other.seconds == this.seconds; } @Override public int hashCode() { return (int) (seconds ^ (seconds >>> 32)); } /** * A string representation of this duration using ISO-8601 seconds based representation, such as {@code PT8H6M12S}. *

* The format of the returned string will be {@code PnDTnHnMnS}, where n is the relevant days, hours, minutes or * seconds part of the duration. If a section has a zero value, it is omitted. The hours, minutes and seconds are * all positive. *

* Examples: * *

     *    "20 seconds"                     -- "PT20S
     *    "15 minutes" (15 * 60 seconds)   -- "PT15M"
     *    "10 hours" (10 * 3600 seconds)   -- "PT10H"
     *    "2 days" (2 * 86400 seconds)     -- "P2D"
     * 
* * @return an ISO-8601 representation of this duration, not null */ @Override public String toString() { if (this == ZERO) { return "PT0S"; } final long days = seconds / SECONDS_PER_DAY; final long hours = (seconds % SECONDS_PER_DAY) / SECONDS_PER_HOUR; final int minutes = (int) ((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE); final int secs = (int) (seconds % SECONDS_PER_MINUTE); final StringBuilder buf = new StringBuilder(24); buf.append("P"); if (days != 0) { buf.append(days).append('D'); } if ((hours | minutes | secs) != 0) { buf.append('T'); } if (hours != 0) { buf.append(hours).append('H'); } if (minutes != 0) { buf.append(minutes).append('M'); } if (secs == 0 && buf.length() > 0) { return buf.toString(); } buf.append(secs).append('S'); return buf.toString(); } /* * (non-Javadoc) * * @see java.lang.Comparable#compareTo(java.lang.Object) */ @Override public int compareTo(final Duration other) { return Long.signum(toMillis() - other.toMillis()); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy