/** * Oshi (https://github.com/oshi/oshi) * * Copyright (c) 2010 - 2017 The Oshi Project Team * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Maintainers: * dblock[at]dblock[dot]org * widdis[at]gmail[dot]com * enrico.bianchi[at]gmail[dot]com * * Contributors: * https://github.com/oshi/oshi/graphs/contributors */ package oshi.util; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Iterator; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.threeten.bp.LocalDate; import org.threeten.bp.format.DateTimeFormatter; import org.threeten.bp.format.DateTimeParseException; /** * Formatting utility for appending units or converting between number types. * * @author dblock[at]dblock[dot]org */ public class FormatUtil { private static Logger LOG = LoggerFactory.getLogger(FormatUtil.class); /** * Binary prefixes, used in IEC Standard for naming bytes. * (http://en.wikipedia.org/wiki/International_Electrotechnical_Commission) * * Should be used for most representations of bytes */ private static final long KIBI = 1L << 10; private static final long MEBI = 1L << 20; private static final long GIBI = 1L << 30; private static final long TEBI = 1L << 40; private static final long PEBI = 1L << 50; private static final long EXBI = 1L << 60; /** * Decimal prefixes, used for Hz and other metric units and for bytes by * hard drive manufacturers */ private static final long KILO = 1000L; private static final long MEGA = 1000000L; private static final long GIGA = 1000000000L; private static final long TERA = 1000000000000L; private static final long PETA = 1000000000000000L; private static final long EXA = 1000000000000000000L; private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("MM/dd/yyyy"); /* * Two's complement reference: 2^64. */ private static final BigInteger TWOS_COMPLEMENT_REF = BigInteger.ONE.shiftLeft(64); private FormatUtil() { } /** * Format bytes into a rounded string representation using IEC standard * (matches Mac/Linux). For hard drive capacities, use @link * {@link #formatBytesDecimal(long)}. For Windows displays for KB, MB and * GB, in JEDEC units, edit the returned string to remove the 'i' to display * the (incorrect) JEDEC units. * * @param bytes * Bytes. * @return Rounded string representation of the byte size. */ public static String formatBytes(long bytes) { if (bytes == 1L) { // bytes return String.format("%d byte", bytes); } else if (bytes < KIBI) { // bytes return String.format("%d bytes", bytes); } else if (bytes < MEBI) { // KiB return formatUnits(bytes, KIBI, "KiB"); } else if (bytes < GIBI) { // MiB return formatUnits(bytes, MEBI, "MiB"); } else if (bytes < TEBI) { // GiB return formatUnits(bytes, GIBI, "GiB"); } else if (bytes < PEBI) { // TiB return formatUnits(bytes, TEBI, "TiB"); } else if (bytes < EXBI) { // PiB return formatUnits(bytes, PEBI, "PiB"); } else { // EiB return formatUnits(bytes, EXBI, "EiB"); } } /** * Format units as exact integer or fractional decimal based on the prefix, * appending the appropriate units * * @param value * The value to format * @param prefix * The divisor of the unit multiplier * @param unit * A string representing the units * @return A string with the value */ private static String formatUnits(long value, long prefix, String unit) { if (value % prefix == 0) { return String.format("%d %s", value / prefix, unit); } return String.format("%.1f %s", (double) value / prefix, unit); } /** * Format bytes into a rounded string representation using decimal SI units. * These are used by hard drive manufacturers for capacity. Most other * storage should use {@link #formatBytes(long)}. * * @param bytes * Bytes. * @return Rounded string representation of the byte size. */ public static String formatBytesDecimal(long bytes) { if (bytes == 1L) { // bytes return String.format("%d byte", bytes); } else if (bytes < KILO) { // bytes return String.format("%d bytes", bytes); } else { return formatValue(bytes, "B"); } } /** * Format hertz into a string to a rounded string representation. * * @param hertz * Hertz. * @return Rounded string representation of the hertz size. */ public static String formatHertz(long hertz) { return formatValue(hertz, "Hz"); } /** * Format arbitrary units into a string to a rounded string representation. * * @param value * The value * @param unit * Units to append metric prefix to * @return Rounded string representation of the value with metric prefix to * extension */ public static String formatValue(long value, String unit) { if (value < KILO) { return String.format("%d %s", value, unit); } else if (value < MEGA) { // K return formatUnits(value, KILO, "K" + unit); } else if (value < GIGA) { // M return formatUnits(value, MEGA, "M" + unit); } else if (value < TERA) { // G return formatUnits(value, GIGA, "G" + unit); } else if (value < PETA) { // T return formatUnits(value, TERA, "T" + unit); } else if (value < EXA) { // P return formatUnits(value, PETA, "P" + unit); } else { // E return formatUnits(value, EXA, "E" + unit); } } /** * Formats an elapsed time in seconds as days, hh:mm:ss. * * @param secs * Elapsed seconds * @return A string representation of elapsed time */ public static String formatElapsedSecs(long secs) { long eTime = secs; final long days = TimeUnit.SECONDS.toDays(eTime); eTime -= TimeUnit.DAYS.toSeconds(days); final long hr = TimeUnit.SECONDS.toHours(eTime); eTime -= TimeUnit.HOURS.toSeconds(hr); final long min = TimeUnit.SECONDS.toMinutes(eTime); eTime -= TimeUnit.MINUTES.toSeconds(min); final long sec = eTime; return String.format("%d days, %02d:%02d:%02d", days, hr, min, sec); } /** * Round to certain number of decimals. * * @param d * Number to be rounded * @param decimalPlace * Number of decimal places to round to * @return rounded result */ public static float round(float d, int decimalPlace) { final BigDecimal bd = new BigDecimal(Float.toString(d)).setScale(decimalPlace, BigDecimal.ROUND_HALF_UP); return bd.floatValue(); } /** * Convert unsigned int to signed long. * * @param x * Signed int representing an unsigned integer * @return long value of x unsigned */ public static long getUnsignedInt(int x) { return x & 0x00000000ffffffffL; } /** * Convert a java date to a MM-dd-yyyy string representation * * @param date * the date to convert * @return a string in the form MM/dd/yyyy */ public static String formatDate(LocalDate date) { return date == null ? "null" : date.format(DATE_FORMATTER); } /** * Convert a MM-dd-yyyy string representation to a java LocalDate * * @param date * a string in the form MM/dd/yyyy * @return the corresponding LocalDate */ public static LocalDate formatStringDate(String date) { try { return date == null ? null : LocalDate.parse(date, DATE_FORMATTER); } catch (DateTimeParseException dtpe) { LOG.warn("Date parse error: " + dtpe); return null; } } /** * Represent a 32 bit value as if it were an unsigned integer. * * This is a Java 7 implementation of Java 8's Integer.toUnsignedString. * * @param i * a 32 bit value * @return the string representation of the unsigned integer */ public static String toUnsignedString(int i) { if (i >= 0) { return Integer.toString(i); } return Long.toString(getUnsignedInt(i)); } /** * Represent a 64 bit value as if it were an unsigned long. * * This is a Java 7 implementation of Java 8's Long.toUnsignedString. * * @param l * a 64 bit value * @return the string representation of the unsigned long */ public static String toUnsignedString(long l) { if (l >= 0) { return Long.toString(l); } return BigInteger.valueOf(l).add(TWOS_COMPLEMENT_REF).toString(); } /** * Returns a new String composed of copies of the CharSequence elements * joined together with a copy of the specified delimiter. * * This is a Java 7 implementation of Java 8's String.join * * @param delimiter * the delimiter that separates each element * @param elements * the elements to join together. * @return a new String that is composed of the elements separated by the * delimiter */ public static String join(CharSequence delimiter, CharSequence... elements) { StringBuilder sb = new StringBuilder(); boolean first = true; for (CharSequence cs : elements) { if (first) { first = false; } else { sb.append(delimiter); } sb.append(cs); } return sb.toString(); } /** * Returns a new String composed of copies of the CharSequence elements * joined together with a copy of the specified delimiter. * * This is a Java 7 implementation of Java 8's String.join * * @param delimiter * a sequence of characters that is used to separate each of the * elements in the resulting String * @param elements * an Iterable that will have its elements joined together. * @return a new String that is composed from the elements argument */ public static String join(CharSequence delimiter, Iterable<? extends CharSequence> elements) { StringBuilder sb = new StringBuilder(); Iterator<?> iter = elements.iterator(); if (iter.hasNext()) { sb.append(iter.next().toString()); } while (iter.hasNext()) { sb.append(delimiter); sb.append(iter.next().toString()); } return sb.toString(); } }