| /********************************************************************** |
| * Copyright (c) 2017 Ericsson |
| * |
| * All rights reserved. This program and the accompanying materials are |
| * made available under the terms of the Eclipse Public License 2.0 which |
| * accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| **********************************************************************/ |
| package org.eclipse.tracecompass.tmf.ui.views; |
| |
| import java.text.NumberFormat; |
| import java.text.SimpleDateFormat; |
| import java.util.Date; |
| import java.util.TimeZone; |
| import java.util.concurrent.TimeUnit; |
| |
| import org.eclipse.tracecompass.common.core.format.DecimalUnitFormat; |
| import org.eclipse.tracecompass.common.core.format.LongToPercentFormat; |
| import org.eclipse.tracecompass.internal.tmf.ui.Messages; |
| import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimePreferences; |
| |
| /** |
| * Format time to be used in different views. |
| * |
| * @author Simon Delisle |
| * @since 3.3 |
| */ |
| public final class FormatTimeUtils { |
| private FormatTimeUtils() { |
| // do nothing |
| } |
| |
| /** Time format for dates and timestamp */ |
| public enum TimeFormat { |
| /** Relative to the start of the trace */ |
| RELATIVE, |
| |
| /** |
| * Absolute timestamp (ie, relative to the Unix epoch) |
| */ |
| CALENDAR, |
| |
| /** |
| * Timestamp displayed as a simple number |
| */ |
| NUMBER, |
| |
| /** |
| * Timestamp displayed as cycles |
| */ |
| CYCLES, |
| |
| /** |
| * Value displayed as percentage |
| * @since 4.0 |
| */ |
| PERCENTAGE |
| } |
| |
| /** |
| * Timestamp resolution |
| */ |
| public enum Resolution { |
| /** seconds */ |
| SECONDS, |
| |
| /** milliseconds */ |
| MILLISEC, |
| |
| /** microseconds */ |
| MICROSEC, |
| |
| /** nanoseconds */ |
| NANOSEC |
| } |
| |
| private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss"); //$NON-NLS-1$ |
| private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); //$NON-NLS-1$ |
| private static final long HOURS_PER_DAY = 24; |
| private static final long MIN_PER_HOUR = 60; |
| private static final long SEC_PER_MIN = 60; |
| private static final long SEC_IN_NS = 1000000000; |
| private static final long MILLISEC_IN_NS = 1000000; |
| |
| /** |
| * Update the time and date formats to use the current time zone |
| */ |
| public static void updateTimeZone() { |
| TimeZone timeZone = TmfTimePreferences.getTimeZone(); |
| TIME_FORMAT.setTimeZone(timeZone); |
| DATE_FORMAT.setTimeZone(timeZone); |
| } |
| |
| /** |
| * Formats time in format: MM:SS:NNN |
| * |
| * @param time |
| * time |
| * @param format |
| * 0: MMMM:ss:nnnnnnnnn, 1: HH:MM:ss MMM.mmmm.nnn |
| * @param resolution |
| * the resolution |
| * @return the formatted time |
| */ |
| public static String formatTime(long time, TimeFormat format, Resolution resolution) { |
| switch (format) { |
| case CALENDAR: |
| return formatTimeAbs(time, resolution); |
| case NUMBER: |
| return NumberFormat.getInstance().format(time); |
| case CYCLES: |
| return NumberFormat.getInstance().format(time) + Messages.Utils_ClockCyclesUnit; |
| case RELATIVE: |
| return formatTimeRelative(time, resolution); |
| case PERCENTAGE: |
| return LongToPercentFormat.getInstance().format(time); |
| default: |
| } |
| |
| StringBuilder str = new StringBuilder(); |
| long t = time; |
| boolean neg = t < 0; |
| if (neg) { |
| t = -t; |
| str.append('-'); |
| } |
| |
| long sec = t / SEC_IN_NS; |
| str.append(sec); |
| String ns = formatNs(t, resolution); |
| if (!ns.isEmpty()) { |
| str.append('.'); |
| str.append(ns); |
| } |
| |
| return str.toString(); |
| } |
| |
| /** |
| * From input time in nanoseconds, convert to Date format YYYY-MM-dd |
| * |
| * @param absTime |
| * The source time, in ns |
| * @return the formatted date |
| */ |
| public static String formatDate(long absTime) { |
| return DATE_FORMAT.format(new Date(absTime / MILLISEC_IN_NS)); |
| } |
| |
| /** |
| * Formats time in ns to Calendar format: HH:MM:SS MMM.mmm.nnn |
| * |
| * @param time |
| * The source time, in ns |
| * @param res |
| * The resolution to use |
| * @return the formatted time |
| */ |
| public static String formatTimeAbs(long time, Resolution res) { |
| // format time from nanoseconds to calendar time HH:MM:SS |
| String stime = TIME_FORMAT.format(new Date(time / MILLISEC_IN_NS)); |
| StringBuilder str = new StringBuilder(stime); |
| String ns = formatNs(time, res); |
| if (!ns.isEmpty()) { |
| str.append('.'); |
| /* |
| * append the Milliseconds, MicroSeconds and NanoSeconds as specified in the |
| * Resolution |
| */ |
| str.append(ns); |
| } |
| return str.toString(); |
| } |
| |
| /** |
| * Formats time delta |
| * |
| * @param delta |
| * The time delta, in ns |
| * @param format |
| * The time format to use |
| * @param resolution |
| * The resolution to use |
| * @return the formatted time delta |
| */ |
| public static String formatDelta(long delta, TimeFormat format, Resolution resolution) { |
| if (format == TimeFormat.CALENDAR) { |
| return formatDeltaAbs(delta, resolution); |
| } |
| return formatTime(delta, format, resolution); |
| } |
| |
| /** |
| * Formats relative time to second |
| * |
| * @param time |
| * The relative time in ns |
| * @param resolution |
| * The resolution to use |
| * @return The formatted time in second |
| */ |
| private static String formatTimeRelative(long time, Resolution resolution) { |
| StringBuilder str = new StringBuilder(); |
| if (time < 0) { |
| str.append('-'); |
| } |
| |
| long ns = Math.abs(time); |
| long seconds = TimeUnit.NANOSECONDS.toSeconds(ns); |
| str.append(seconds); |
| str.append('.'); |
| // append the ms, us and ns as specified in the resolution |
| str.append(formatNs(time, resolution)); |
| str.append('s'); |
| if (seconds == 0) { |
| str.append(" ("); //$NON-NLS-1$ |
| str.append(new DecimalUnitFormat(1.0 / SEC_IN_NS).format(time)); |
| str.append("s)"); //$NON-NLS-1$ |
| } |
| return str.toString(); |
| } |
| |
| /** |
| * Formats time delta in ns to Calendar format, only formatting the years, days, |
| * hours or minutes if necessary. |
| * |
| * @param delta |
| * The time delta, in ns |
| * @param resolution |
| * The resolution to use |
| * @return the formatted time delta |
| */ |
| public static String formatDeltaAbs(long delta, Resolution resolution) { |
| StringBuilder str = new StringBuilder(); |
| if (delta < 0) { |
| str.append('-'); |
| } |
| long ns = Math.abs(delta); |
| long seconds = TimeUnit.NANOSECONDS.toSeconds(ns); |
| long minutes = TimeUnit.NANOSECONDS.toMinutes(ns); |
| long hours = TimeUnit.NANOSECONDS.toHours(ns); |
| long days = TimeUnit.NANOSECONDS.toDays(ns); |
| if (days > 0) { |
| str.append(days); |
| str.append("d "); //$NON-NLS-1$ |
| } |
| if (hours > 0) { |
| str.append(hours % HOURS_PER_DAY); |
| str.append("h "); //$NON-NLS-1$ |
| } |
| if (minutes > 0) { |
| str.append(minutes % MIN_PER_HOUR); |
| str.append("m "); //$NON-NLS-1$ |
| } |
| str.append(seconds % SEC_PER_MIN); |
| str.append('.'); |
| // append the ms, us and ns as specified in the resolution |
| str.append(formatNs(delta, resolution)); |
| str.append("s"); //$NON-NLS-1$ |
| if (seconds == 0) { |
| str.append(" ("); //$NON-NLS-1$ |
| str.append(new DecimalUnitFormat(1.0 / SEC_IN_NS).format(delta)); |
| str.append("s)"); //$NON-NLS-1$ |
| } |
| return str.toString(); |
| } |
| |
| /** |
| * Obtains the remainder fraction on unit Seconds of the entered value in |
| * nanoseconds. e.g. input: 1241207054171080214 ns The number of fraction |
| * seconds can be obtained by removing the last 9 digits: 1241207054 the |
| * fractional portion of seconds, expressed in ns is: 171080214 |
| * |
| * @param srcTime |
| * The source time in ns |
| * @param res |
| * The Resolution to use |
| * @return the formatted nanosec |
| */ |
| public static String formatNs(long srcTime, Resolution res) { |
| StringBuilder str = new StringBuilder(); |
| long ns = Math.abs(srcTime % SEC_IN_NS); |
| String nanos = Long.toString(ns); |
| str.append("000000000".substring(nanos.length())); //$NON-NLS-1$ |
| str.append(nanos); |
| |
| if (res == Resolution.MILLISEC) { |
| return str.substring(0, 3); |
| } else if (res == Resolution.MICROSEC) { |
| return str.substring(0, 6); |
| } else if (res == Resolution.NANOSEC) { |
| return str.substring(0, 9); |
| } |
| return ""; //$NON-NLS-1$ |
| } |
| |
| } |