1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.logging.log4j.core.appender.rolling.action;
19
20 import java.io.Serializable;
21 import java.util.Objects;
22 import java.util.regex.Matcher;
23 import java.util.regex.Pattern;
24
25
26
27
28
29
30
31
32
33
34
35 public class Duration implements Serializable, Comparable<Duration> {
36 private static final long serialVersionUID = -3756810052716342061L;
37
38
39
40
41 public static final Duration ZERO = new Duration(0);
42
43
44
45
46 private static final int HOURS_PER_DAY = 24;
47
48
49
50 private static final int MINUTES_PER_HOUR = 60;
51
52
53
54 private static final int SECONDS_PER_MINUTE = 60;
55
56
57
58 private static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
59
60
61
62 private static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;
63
64
65
66
67 private static final Pattern PATTERN = Pattern.compile("P?(?:([0-9]+)D)?"
68 + "(T?(?:([0-9]+)H)?(?:([0-9]+)M)?(?:([0-9]+)?S)?)?", Pattern.CASE_INSENSITIVE);
69
70
71
72
73 private final long seconds;
74
75
76
77
78
79
80 private Duration(final long seconds) {
81 super();
82 this.seconds = seconds;
83 }
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117 public static Duration parse(final CharSequence text) {
118 Objects.requireNonNull(text, "text");
119 final Matcher matcher = PATTERN.matcher(text);
120 if (matcher.matches()) {
121
122 if ("T".equals(matcher.group(2)) == false) {
123 final String dayMatch = matcher.group(1);
124 final String hourMatch = matcher.group(3);
125 final String minuteMatch = matcher.group(4);
126 final String secondMatch = matcher.group(5);
127 if (dayMatch != null || hourMatch != null || minuteMatch != null || secondMatch != null) {
128 final long daysAsSecs = parseNumber(text, dayMatch, SECONDS_PER_DAY, "days");
129 final long hoursAsSecs = parseNumber(text, hourMatch, SECONDS_PER_HOUR, "hours");
130 final long minsAsSecs = parseNumber(text, minuteMatch, SECONDS_PER_MINUTE, "minutes");
131 final long seconds = parseNumber(text, secondMatch, 1, "seconds");
132 try {
133 return create(daysAsSecs, hoursAsSecs, minsAsSecs, seconds);
134 } catch (final ArithmeticException ex) {
135 throw new IllegalArgumentException("Text cannot be parsed to a Duration (overflow) " + text, ex);
136 }
137 }
138 }
139 }
140 throw new IllegalArgumentException("Text cannot be parsed to a Duration: " + text);
141 }
142
143 private static long parseNumber(final CharSequence text, final String parsed, final int multiplier,
144 final String errorText) {
145
146 if (parsed == null) {
147 return 0;
148 }
149 try {
150 final long val = Long.parseLong(parsed);
151 return val * multiplier;
152 } catch (final Exception ex) {
153 throw new IllegalArgumentException("Text cannot be parsed to a Duration: " + errorText + " (in " + text
154 + ")", ex);
155 }
156 }
157
158 private static Duration create(final long daysAsSecs, final long hoursAsSecs, final long minsAsSecs, final long secs) {
159 return create(daysAsSecs + hoursAsSecs + minsAsSecs + secs);
160 }
161
162
163
164
165
166
167 private static Duration create(final long seconds) {
168 if ((seconds) == 0) {
169 return ZERO;
170 }
171 return new Duration(seconds);
172 }
173
174
175
176
177
178
179 public long toMillis() {
180 return seconds * 1000L;
181 }
182
183 @Override
184 public boolean equals(final Object obj) {
185 if (obj == this) {
186 return true;
187 }
188 if (!(obj instanceof Duration)) {
189 return false;
190 }
191 final Duration other = (Duration) obj;
192 return other.seconds == this.seconds;
193 }
194
195 @Override
196 public int hashCode() {
197 return (int) (seconds ^ (seconds >>> 32));
198 }
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218 @Override
219 public String toString() {
220 if (this == ZERO) {
221 return "PT0S";
222 }
223 final long days = seconds / SECONDS_PER_DAY;
224 final long hours = (seconds % SECONDS_PER_DAY) / SECONDS_PER_HOUR;
225 final int minutes = (int) ((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);
226 final int secs = (int) (seconds % SECONDS_PER_MINUTE);
227 final StringBuilder buf = new StringBuilder(24);
228 buf.append("P");
229 if (days != 0) {
230 buf.append(days).append('D');
231 }
232 if ((hours | minutes | secs) != 0) {
233 buf.append('T');
234 }
235 if (hours != 0) {
236 buf.append(hours).append('H');
237 }
238 if (minutes != 0) {
239 buf.append(minutes).append('M');
240 }
241 if (secs == 0 && buf.length() > 0) {
242 return buf.toString();
243 }
244 buf.append(secs).append('S');
245 return buf.toString();
246 }
247
248
249
250
251
252
253 @Override
254 public int compareTo(final Duration other) {
255 return Long.signum(toMillis() - other.toMillis());
256 }
257 }