001: // Copyright (c) 2003-2007, Jodd Team (jodd.sf.net). All Rights Reserved.
002:
003: package jodd.datetime;
004:
005: import java.util.List;
006: import java.util.ArrayList;
007:
008: /**
009: * Nice stopwatch that supports time spans, cumulative times and laps.
010: * Useful for all kind of profilings, time measurements etc.
011: */
012: public class JStopWatch {
013:
014: /**
015: * Optional stopwatch name.
016: */
017: protected String name;
018: /**
019: * Last start time.
020: */
021: protected long startTime;
022: /**
023: * Last stop time.
024: */
025: protected long stopTime;
026: /**
027: * Last elapsed time.
028: */
029: protected long spanTime;
030: /**
031: * Cumulative elapsed time.
032: */
033: protected long totalTime;
034: /**
035: * Running flag.
036: */
037: protected boolean running;
038:
039: // ---------------------------------------------------------------- ctors
040:
041: /**
042: * Starts the stopwatch.
043: */
044: public JStopWatch() {
045: this ("");
046: }
047:
048: /**
049: * Starts the named stopwatch.
050: */
051: public JStopWatch(String name) {
052: this .name = name;
053: start();
054: }
055:
056: /**
057: * Returns stopwatch name.
058: */
059: public String getName() {
060: return name;
061: }
062:
063: /**
064: * Returns <code>true</code> if stopwatch is running.
065: */
066: public boolean isRunning() {
067: return running;
068: }
069:
070: // ---------------------------------------------------------------- basic
071:
072: /**
073: * Starts the stopwatch. {@link #stop()} must be called prior to restart.
074: * Returns starting time in milliseconds.
075: */
076: public long start() {
077: if (running == false) {
078: startTime = System.currentTimeMillis();
079: running = true;
080: }
081: return startTime;
082: }
083:
084: /**
085: * Restarts the stopwatch.
086: */
087: public long restart() {
088: startTime = System.currentTimeMillis();
089: running = true;
090: return startTime;
091: }
092:
093: /**
094: * Stops the stopwatch if running. Returns span time.
095: * If laps are used, marks the last lap.
096: */
097: public long stop() {
098: if (running == true) {
099: stopTime = System.currentTimeMillis();
100: if (laps != null) {
101: lap(stopTime);
102: }
103: spanTime = stopTime - startTime;
104: totalTime += stopTime - startTime;
105: running = false;
106: }
107: return spanTime;
108: }
109:
110: /**
111: * Returns total elapsed time from the {@link #start()} in ms.
112: */
113: public long elapsed() {
114: return System.currentTimeMillis() - startTime;
115: }
116:
117: /**
118: * Stops the stopwatch and returns total cumulative time in ms.
119: */
120: public long total() {
121: stop();
122: return totalTime;
123: }
124:
125: /**
126: * Stops the stopwatch and returns total time span for last
127: * start-stop sequence.
128: */
129: public long span() {
130: stop();
131: return spanTime;
132: }
133:
134: // ---------------------------------------------------------------- laps
135:
136: /**
137: * List of all laps. Contains long arrays in following format:
138: * <ul>
139: * <li>lap time - current lap time,</li>
140: * <li>lap span time - elapsed time from start,</li>
141: * <li>lap millis - lap milliseconds.
142: * </ul>
143: */
144: protected List<long[]> laps;
145:
146: /**
147: * Marks a lap and returns its length. May be called only while stop watch is running.
148: */
149: public long lap() {
150: return lap(System.currentTimeMillis());
151: }
152:
153: protected long lap(long lap) {
154: if (running == false) {
155: return 0;
156: }
157: long lapSpanTime = lap - startTime;
158: long lapTime;
159: if (laps == null) {
160: lapTime = lapSpanTime;
161: laps = new ArrayList<long[]>();
162: } else {
163: long[] previous = laps.get(laps.size() - 1);
164: lapTime = lap - previous[2];
165: }
166: laps.add(new long[] { lapTime, lapSpanTime, lap });
167: return lapTime;
168: }
169:
170: /**
171: * Returns the total number of laps up to this moment.
172: */
173: public int totalLaps() {
174: if (laps == null) {
175: return 0;
176: }
177: return laps.size();
178: }
179:
180: /**
181: * Returns lap times for 1-based lap index.
182: * Returns <code>null</code> if laps are not used or if index is invalid.
183: */
184: public long[] getLapTimes(int index) {
185: if (laps == null) {
186: return null;
187: }
188: if ((index <= 0) || (index > laps.size())) {
189: return null;
190: }
191: return laps.get(index - 1);
192: }
193:
194: // ---------------------------------------------------------------- output
195:
196: /**
197: * Returns total elapsed time as formated string from the last start.
198: */
199: @Override
200: public String toString() {
201: long elapsed = elapsed();
202: StringBuilder sb = new StringBuilder();
203: sb.append("JStopWatch ").append(name).append(
204: running ? " is running." : "").append('\n');
205: if (running == true) {
206: sb.append("elapsed: ").append(formatTimeSpan(elapsed));
207: } else {
208: if (spanTime != totalTime) {
209: sb.append("span: ").append(formatTimeSpan(spanTime))
210: .append('\n');
211: }
212: sb.append("total: ").append(formatTimeSpan(totalTime));
213: }
214: if (laps != null) {
215: if (laps.isEmpty() == false) {
216: sb.append('\n');
217: }
218: for (int i = 0; i < laps.size(); i++) {
219: long[] longs = laps.get(i);
220: sb.append(" lap #").append(i + 1).append(':').append(
221: '\t');
222: sb.append(formatTimeSpan(longs[0])).append('\t');
223: sb.append(formatTimeSpan(longs[1])).append('\n');
224: }
225: }
226: return sb.toString();
227: }
228:
229: /**
230: * Formats time spans.
231: */
232: public static String formatTimeSpan(long millis) {
233: long seconds = 0;
234: long minutes = 0;
235: long hours = 0;
236:
237: if (millis > 1000) {
238: seconds = millis / 1000;
239: millis %= 1000;
240: }
241: if (seconds > 60) {
242: minutes = seconds / 60;
243: seconds %= 60;
244: }
245: if (minutes > 60) {
246: hours = minutes / 60;
247: minutes %= 60;
248: }
249:
250: StringBuilder result = new StringBuilder(20);
251: boolean out = false;
252: if (hours > 0) {
253: result.append(hours).append(':');
254: out = true;
255: }
256: if ((out == true) || (minutes > 0)) {
257: if (minutes < 10) {
258: result.append('0');
259: }
260: result.append(minutes).append(':');
261: }
262:
263: if (seconds < 10) {
264: result.append('0');
265: }
266: result.append(seconds).append('.');
267:
268: if (millis < 10) {
269: result.append('0');
270: }
271: if (millis < 100) {
272: result.append('0');
273: }
274: result.append(millis);
275: return result.toString();
276: }
277: }
|