View Javadoc

1   /**
2    * Copyright 2010-2012 The Kuali Foundation
3    *
4    * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
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  package org.kuali.common.util;
17  
18  import java.text.NumberFormat;
19  import java.text.ParseException;
20  import java.text.SimpleDateFormat;
21  import java.util.ArrayList;
22  import java.util.Arrays;
23  import java.util.Date;
24  import java.util.List;
25  
26  import org.apache.commons.lang3.StringUtils;
27  
28  /**
29   * Format time, bytes, counts, dates, and transfer rates into human friendly form
30   * 
31   * @author Jeff Caddel
32   * @since May 27, 2010 6:46:17 PM
33   */
34  public class FormatUtils {
35  	private static final double SECOND = 1000;
36  	private static final double MINUTE = 60 * SECOND;
37  	private static final double HOUR = 60 * MINUTE;
38  	private static final double DAY = 24 * HOUR;
39  	private static final double YEAR = 365 * DAY;
40  	private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ";
41  
42  	private static final List<String> TIME_TOKENS = Arrays.asList("ms", "s", "m", "h", "d", "y");
43  	private static final List<Long> TIME_MULTIPLIERS = getTimeMultipliers();
44  
45  	private static final List<String> SIZE_TOKENS = Arrays.asList("b", "k", "m", "g", "t", "p", "e");
46  	private static final int BASE = 1024;
47  
48  	private static NumberFormat largeSizeFormatter = NumberFormat.getInstance();
49  	private static NumberFormat sizeFormatter = NumberFormat.getInstance();
50  	private static NumberFormat timeFormatter = NumberFormat.getInstance();
51  	private static NumberFormat rateFormatter = NumberFormat.getInstance();
52  	private static NumberFormat countFormatter = NumberFormat.getInstance();
53  
54  	static {
55  		sizeFormatter.setGroupingUsed(false);
56  		sizeFormatter.setMaximumFractionDigits(1);
57  		sizeFormatter.setMinimumFractionDigits(1);
58  		largeSizeFormatter.setGroupingUsed(false);
59  		largeSizeFormatter.setMaximumFractionDigits(3);
60  		largeSizeFormatter.setMinimumFractionDigits(3);
61  		timeFormatter.setGroupingUsed(false);
62  		timeFormatter.setMaximumFractionDigits(3);
63  		timeFormatter.setMinimumFractionDigits(3);
64  		rateFormatter.setGroupingUsed(false);
65  		rateFormatter.setMaximumFractionDigits(3);
66  		rateFormatter.setMinimumFractionDigits(3);
67  		countFormatter.setGroupingUsed(true);
68  		countFormatter.setMaximumFractionDigits(0);
69  		countFormatter.setMinimumFractionDigits(0);
70  	}
71  
72  	/**
73  	 * Parse bytes from a size string that ends with a unit of measure. If no unit of measure is provided, bytes is assumed. Unit of measure is case insensitive.
74  	 * 
75  	 * <pre>
76  	 *   1  == 1 byte
77  	 *   1b == 1 byte
78  	 *   1k == 1 kilobyte == 1024   bytes ==                     1,024 bytes
79  	 *   1m == 1 megabyte == 1024^2 bytes ==                 1,048,576 bytes
80  	 *   1g == 1 gigabyte == 1024^3 bytes ==             1,073,741,824 bytes
81  	 *   1t == 1 terabyte == 1024^4 bytes ==         1,099,511,627,776 bytes
82  	 *   1p == 1 petabyte == 1024^5 bytes ==     1,125,899,906,842,624 bytes
83  	 *   1e == 1 exabyte  == 1024^6 bytes == 1,152,921,504,606,846,976 bytes
84  	 * </pre>
85  	 */
86  	public static long getBytes(String size) {
87  		return getBytes(size, SIZE_TOKENS, BASE);
88  	}
89  
90  	public static long getBytes(String size, List<String> tokens, int base) {
91  		Assert.notBlank(size);
92  		for (int i = 0; i < tokens.size(); i++) {
93  			String token = tokens.get(i);
94  			long multiplier = (long) Math.pow(base, i);
95  			if (StringUtils.endsWithIgnoreCase(size, token)) {
96  				return getByteValue(size, token, multiplier);
97  			}
98  		}
99  		// Assume bytes
100 		return getByteValue(size, "", 1);
101 	}
102 
103 	protected static long getByteValue(String time, String suffix, long multiplier) {
104 		int len = StringUtils.length(time);
105 		String substring = StringUtils.substring(time, 0, len - suffix.length());
106 		Double value = new Double(substring);
107 		value = value * multiplier;
108 		return value.longValue();
109 	}
110 
111 	/**
112 	 * Parse milliseconds from a time string that ends with a unit of measure. If no unit of measure is provided, milliseconds is assumed. Unit of measure is case insensitive.
113 	 * 
114 	 * <pre>
115 	 *   1   == 1 millisecond
116 	 *   1ms == 1 millisecond
117 	 *   1s  == 1 second ==           1000 milliseconds
118 	 *   1m  == 1 minute ==         60,000 milliseconds
119 	 *   1h  == 1 hour   ==      3,600,000 milliseconds 
120 	 *   1d  == 1 day    ==     86,400,000 milliseconds
121 	 *   1y  == 1 year   == 31,536,000,000 milliseconds
122 	 * </pre>
123 	 */
124 	public static long getMillis(String time) {
125 		return getMillis(time, TIME_TOKENS, TIME_MULTIPLIERS);
126 	}
127 
128 	public static long getMillis(String time, List<String> tokens, List<Long> multipliers) {
129 		Assert.notBlank(time);
130 		Assert.isTrue(tokens.size() == multipliers.size());
131 		for (int i = 0; i < tokens.size(); i++) {
132 			String token = tokens.get(i);
133 			long multiplier = multipliers.get(i);
134 			if (StringUtils.endsWithIgnoreCase(time, token)) {
135 				return getTimeValue(time, token, multiplier);
136 			}
137 		}
138 		// Assume milliseconds
139 		return getTimeValue(time, "", 1);
140 	}
141 
142 	protected static long getTimeValue(String time, String suffix, long multiplier) {
143 		int len = StringUtils.length(time);
144 		String substring = StringUtils.substring(time, 0, len - suffix.length());
145 		Double value = new Double(substring);
146 		value = value * multiplier;
147 		return value.longValue();
148 	}
149 
150 	/**
151 	 * Parse a date from the string. The string must be in the same format returned by the getDate() methods
152 	 */
153 	public static Date parseDate(String date) {
154 		try {
155 			SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
156 			return sdf.parse(date);
157 		} catch (ParseException e) {
158 			throw new IllegalArgumentException("Can't parse [" + date + "]", e);
159 		}
160 	}
161 
162 	/**
163 	 * Return a formatted date
164 	 */
165 	public static String getDate(long millis) {
166 		return getDate(new Date(millis));
167 	}
168 
169 	/**
170 	 * Return a formatted date
171 	 */
172 	public static String getDate(Date date) {
173 		SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
174 		return sdf.format(date);
175 	}
176 
177 	/**
178 	 * 
179 	 */
180 	public static String getThroughputInSeconds(long millis, long count, String label) {
181 		double seconds = millis / SECOND;
182 		double countPerSecond = count / seconds;
183 		return countFormatter.format(countPerSecond) + " " + label;
184 	}
185 
186 	/**
187 	 * Given a number of bytes and the number of milliseconds it took to transfer that number of bytes, return bytes/s, KB/s, MB/s, GB/s, TB/s, PB/s, or EB/s as appropriate
188 	 */
189 	public static String getRate(long millis, long bytes) {
190 		double seconds = millis / SECOND;
191 		double bytesPerSecond = bytes / seconds;
192 		Size bandwidthLevel = getSizeEnum(bytesPerSecond);
193 		double transferRate = bytesPerSecond / bandwidthLevel.getValue();
194 		return rateFormatter.format(transferRate) + " " + bandwidthLevel.getRateLabel();
195 	}
196 
197 	/**
198 	 * Return a formatted <code>count</code>
199 	 */
200 	public static String getCount(long count) {
201 		return countFormatter.format(count);
202 	}
203 
204 	/**
205 	 * Given milliseconds, return milliseconds, seconds, minutes, hours, days, or year as appropriate. Note that years is approximate since the logic always assumes there are
206 	 * exactly 365 days per year.
207 	 */
208 	public static String getTime(long millis) {
209 		long abs = Math.abs(millis);
210 		if (abs < SECOND) {
211 			return millis + "ms";
212 		} else if (abs < MINUTE) {
213 			return timeFormatter.format(millis / SECOND) + "s";
214 		} else if (abs < HOUR) {
215 			return timeFormatter.format(millis / MINUTE) + "m";
216 		} else if (abs < DAY) {
217 			return timeFormatter.format(millis / HOUR) + "h";
218 		} else if (abs < YEAR) {
219 			return timeFormatter.format(millis / DAY) + "d";
220 		} else {
221 			return timeFormatter.format(millis / YEAR) + "y";
222 		}
223 	}
224 
225 	/**
226 	 * Given a number of bytes return bytes, kilobytes, megabytes, gigabytes, terabytes, petabytes, or exabytes as appropriate.
227 	 */
228 	public static String getSize(long bytes) {
229 		return getSize(bytes, null);
230 	}
231 
232 	/**
233 	 * Given a number of bytes return a string formatted into the unit of measure indicated
234 	 */
235 	public static String getSize(long bytes, Size unitOfMeasure) {
236 		unitOfMeasure = (unitOfMeasure == null) ? getSizeEnum(bytes) : unitOfMeasure;
237 		StringBuilder sb = new StringBuilder();
238 		sb.append(getFormattedSize(bytes, unitOfMeasure));
239 		sb.append(unitOfMeasure.getSizeLabel());
240 		return sb.toString();
241 	}
242 
243 	public static String getFormattedSize(long bytes, Size size) {
244 		switch (size) {
245 		case BYTE:
246 			return bytes + "";
247 		case KB:
248 		case MB:
249 		case GB:
250 			return sizeFormatter.format(bytes / (double) size.getValue());
251 		default:
252 			return largeSizeFormatter.format(bytes / (double) size.getValue());
253 		}
254 	}
255 
256 	public static Size getSizeEnum(double bytes) {
257 		bytes = Math.abs(bytes);
258 		if (bytes < Size.KB.getValue()) {
259 			return Size.BYTE;
260 		} else if (bytes < Size.MB.getValue()) {
261 			return Size.KB;
262 		} else if (bytes < Size.GB.getValue()) {
263 			return Size.MB;
264 		} else if (bytes < Size.TB.getValue()) {
265 			return Size.GB;
266 		} else if (bytes < Size.PB.getValue()) {
267 			return Size.TB;
268 		} else if (bytes < Size.EB.getValue()) {
269 			return Size.PB;
270 		} else {
271 			return Size.EB;
272 		}
273 	}
274 
275 	protected static final List<Long> getTimeMultipliers() {
276 		List<Long> m = new ArrayList<Long>();
277 		m.add(1L);
278 		m.add(new Double(SECOND).longValue());
279 		m.add(new Double(MINUTE).longValue());
280 		m.add(new Double(HOUR).longValue());
281 		m.add(new Double(DAY).longValue());
282 		m.add(new Double(YEAR).longValue());
283 		return m;
284 	}
285 }