// Copyright Keysight Technologies 2012-2019
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at http://mozilla.org/MPL/2.0/.
using System.Globalization;
using System;
namespace OpenTap
{
///
/// Takes care of printing and parsing time spans like '1 s' or '15.3 ms'. Supports seconds, milliseconds, microseconds and nanoseconds.
///
struct ShortTimeSpan
{
public enum UnitKind{
Seconds,
Milliseconds,
Microseconds,
Nanoseconds
};
UnitKind unit;
public UnitKind Unit => unit;
public double Value { get; set; }
public double Seconds
{
get { return Value * Scale; }
}
public static ShortTimeSpan FromSeconds(double seconds)
{
var s = seconds;
UnitKind unit = UnitKind.Seconds;
if (s < 1)
{
s = seconds * 1e3;
unit = UnitKind.Milliseconds;
if (s < 1)
{
s = seconds * 1e6;
unit = UnitKind.Microseconds;
if (s < 1)
{
s = seconds * 1e9;
unit = UnitKind.Nanoseconds;
if (s < 1) // treat < 0 ns as 0 s.
return default(ShortTimeSpan);
}
}
}
return new ShortTimeSpan { unit = unit, Value = Math.Round(s, 3) };
}
///
/// For formating of timespans longer than 1 minute like "1 d 1 h 14m" instead of "90840 s"
///
///
///
public static string LongTimeSpanFormat(TimeSpan timeSpan)
{
string result = "";
if (timeSpan.TotalMinutes < 1)
{
var (timeString, unit) = FromSeconds(timeSpan.TotalSeconds).ToStringParts();
return FormatTimeStringParts(timeString, unit);
}
if (timeSpan.Days > 0)
{
result += $"{timeSpan.Days} d ";
}
if (timeSpan.Hours > 0)
{
result += $"{timeSpan.Hours} h ";
}
if (timeSpan.Minutes > 0)
{
result += $"{timeSpan.Minutes} m ";
}
if (timeSpan.Seconds > 0)
{
result += $"{timeSpan.Seconds} s ";
}
return result.Trim();
}
private static string FormatTimeStringParts(string timeString, string unit)
{
var formattedString = $"{timeString,5:0} {unit,-4}";
return formattedString;
}
public static ShortTimeSpan FromString(string str)
{
str = str.Trim();
UnitKind scale = UnitKind.Seconds;
if (str.EndsWith("ms"))
{
scale = UnitKind.Milliseconds;
}
else if (str.EndsWith("μs") || str.EndsWith("us")) // support mu symbol for forward compatibility use
{
scale = UnitKind.Microseconds;
}
else if (str.EndsWith("ns"))
{
scale = UnitKind.Nanoseconds;
}
else if (str.EndsWith("s"))
{
}
int index = 0;
for (; index < str.Length; index++)
{
if (char.IsNumber(str[index]) || str[index] == '.')
continue;
else
break;
}
str = str.Substring(0, index);
var val = double.Parse(str, NumberStyles.Any, CultureInfo.InvariantCulture);
return new ShortTimeSpan { Value = val, unit = scale };
}
static string getUnitString(UnitKind unit)
{
switch (unit)
{
case UnitKind.Microseconds:
return "us"; // "μs" support this notation at a later time.
case UnitKind.Milliseconds:
return "ms";
case UnitKind.Nanoseconds:
return "ns";
default:
return "s";
}
}
public double Scale
{
get
{
switch (unit)
{
case UnitKind.Milliseconds:
return 1e-3;
case UnitKind.Microseconds:
return 1e-6;
case UnitKind.Nanoseconds:
return 1e-9;
default:
return 1;
}
}
}
public override string ToString()
{
if (Value < 10)
return string.Format(CultureInfo.InvariantCulture, "{0:0.00} {1}", Math.Floor(Value * 100) * 0.01, getUnitString(Unit));
else if (Value < 100)
return string.Format(CultureInfo.InvariantCulture, "{0:0.0} {1}", Math.Round(Value * 10) * 0.1, getUnitString(Unit));
else
return string.Format(CultureInfo.InvariantCulture, "{0} {1}", Math.Floor(Value), getUnitString(Unit));
}
/// To avoid generating extra garbage during formatting, this can be used with StringBuilder.
///
public void ToString(System.Text.StringBuilder output)
{
if (Value < 0.01)
{
output.Append("0 ns");
return;
};
if (Value < 10)
output.Append((Math.Floor(Value * 100) * 0.01).ToString("0.00", CultureInfo.InvariantCulture));
else if (Value < 100)
output.Append((Math.Floor(Value * 10) * 0.1).ToString("0.0", CultureInfo.InvariantCulture));
else
output.Append(Math.Floor(Value).ToString(CultureInfo.InvariantCulture));
output.Append(' ');
output.Append(getUnitString(Unit));
}
public (string, string) ToStringParts()
{
if (Value < 10)
return (string.Format(CultureInfo.InvariantCulture, "{0:0.00}", Math.Floor(Value * 100) * 0.01), getUnitString(Unit));
else if (Value < 100)
return (string.Format(CultureInfo.InvariantCulture, "{0:0.0}", Math.Floor(Value * 10) * 0.1), getUnitString(Unit));
else
return (string.Format(CultureInfo.InvariantCulture, "{0:0}", Math.Floor(Value)), getUnitString(Unit));
}
}
}