Skip to content

Commit

Permalink
Added byte rate calculation functons, closes Humanizr#296
Browse files Browse the repository at this point in the history
  • Loading branch information
GeorgeHahn authored and Borzoo committed Dec 23, 2014
1 parent 759fca6 commit 303abd4
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 2 deletions.
18 changes: 18 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,24 @@ ByteSize.Parse("1.55 tB");
ByteSize.Parse("1.55 tb");
```

Finally, if you need to calculate the rate at which a quantity of bytes has been transferred, you can use the `Per` method of `ByteSize`. The `Per` method accepts one argument - the measurement interval for the bytes; this is the amount of time it took to transfer the bytes.

The `Per` method returns a `ByteRate` class which has a `Humanize` method. By default, rates are given in seconds (eg, MB/s). However, if desired, a TimeUnit may be passed to `Humanize` for an alternate interval. Valid intervals are `TimeUnit.Second`, `TimeUnit.Minute`, and `TimeUnit.Hour`. Examples of each interval and example byte rate usage is below.

```
var size = ByteSize.FromMegabytes(10);
var measurementInterval = TimeSpan.FromSeconds(1);
var text = size.Per(measurementInterval).Humanize();
// 10 MB/s
text = size.Per(measurementInterval).Humanize(TimeUnit.Minute);
// 600 MB/min
text = size.Per(measurementInterval).Humanize(TimeUnit.Hour);
// 35.15625 GB/hour
```

##<a id="mix-this-into-your-framework-to-simplify-your-life">Mix this into your framework to simplify your life</a>
This is just a baseline and you can use this to simplify your day to day job. For example, in Asp.Net MVC we keep chucking `Display` attribute on ViewModel properties so `HtmlHelper` can generate correct labels for us; but, just like enums, in vast majority of cases we just need a space between the words in property name - so why not use `"string".Humanize` for that?!

Expand Down
1 change: 1 addition & 0 deletions release_notes.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
###In Development
- [#320](https://github.com/MehdiK/Humanizer/pull/320): Fixed Dehumanize actually humanizing an already dehumanized string
- [#322](https://github.com/MehdiK/Humanizer/pull/322): DefaultFormatter.TimeSpanHumanize throws a more meaningful exception when called with TimeUnits larger than TimeUnit.Week
- [#314](https://github.com/MehdiK/Humanizer/pull/314): Added ByteRate class and supporting members to facilitate calculation of byte transfer rates

[Commits](https://github.com/MehdiK/Humanizer/compare/v1.28.0...master)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
public struct ByteSize
public class ByteRate
{
public ByteRate(Humanizer.Bytes.ByteSize size, System.TimeSpan interval) { }
public System.TimeSpan Interval { get; set; }
public Humanizer.Bytes.ByteSize Size { get; set; }
public string Humanize(Humanizer.Localisation.TimeUnit timeUnit) { }
}

public struct ByteSize
{
public long BitsInByte;
public string BitSymbol;
Expand Down Expand Up @@ -85,6 +93,7 @@ public class ByteSizeExtensions
public Humanizer.Bytes.ByteSize Megabytes(int input) { }
public Humanizer.Bytes.ByteSize Megabytes(uint input) { }
public Humanizer.Bytes.ByteSize Megabytes(double input) { }
public Humanizer.Bytes.ByteRate Per(Humanizer.Bytes.ByteSize size, System.TimeSpan interval) { }
public Humanizer.Bytes.ByteSize Terabytes(byte input) { }
public Humanizer.Bytes.ByteSize Terabytes(sbyte input) { }
public Humanizer.Bytes.ByteSize Terabytes(short input) { }
Expand Down
67 changes: 67 additions & 0 deletions src/Humanizer.Tests/Bytes/ByteRateTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System;
using Humanizer.Bytes;
using Humanizer.Localisation;
using Xunit;
using Xunit.Extensions;

namespace Humanizer.Tests.Bytes
{
public class ByteRateTests : AmbientCulture
{
public ByteRateTests() : base("en") { }

[Theory]
[InlineData(400, 1, "400 B/s")]
[InlineData(4 * 1024, 1, "4 KB/s")]
[InlineData(4 * 1024 * 1024, 1, "4 MB/s")]
[InlineData(4 * 2 * 1024 * 1024, 2, "4 MB/s")]
[InlineData(4 * 1024, 0.1, "40 KB/s")]
[InlineData(15 * 60 * 1024 * 1024, 60, "15 MB/s")]
public void HumanizesRates(long inputBytes, double perSeconds, string expectedValue)
{
var size = new ByteSize(inputBytes);
var interval = TimeSpan.FromSeconds(perSeconds);

var rate = size.Per(interval).Humanize();

Assert.Equal(expectedValue, rate);
}

[Theory]
[InlineData(1, 1, TimeUnit.Second, "1 MB/s")]
[InlineData(1, 60, TimeUnit.Minute, "1 MB/min")]
[InlineData(1, 60 * 60, TimeUnit.Hour, "1 MB/hour")]
[InlineData(10, 1, TimeUnit.Second, "10 MB/s")]
[InlineData(10, 60, TimeUnit.Minute, "10 MB/min")]
[InlineData(10, 60 * 60, TimeUnit.Hour, "10 MB/hour")]
[InlineData(1, 10 * 1, TimeUnit.Second, "102.4 KB/s")]
[InlineData(1, 10 * 60, TimeUnit.Minute, "102.4 KB/min")]
[InlineData(1, 10 * 60 * 60, TimeUnit.Hour, "102.4 KB/hour")]
public void TimeUnitTests(long megabytes, double measurementIntervalSeconds, TimeUnit displayInterval, string expectedValue)
{
var size = ByteSize.FromMegabytes(megabytes);
var measurementInterval = TimeSpan.FromSeconds(measurementIntervalSeconds);

var rate = size.Per(measurementInterval);
var text = rate.Humanize(displayInterval);

Assert.Equal(expectedValue, text);
}

[Theory]
[InlineData(TimeUnit.Millisecond)]
[InlineData(TimeUnit.Day)]
[InlineData(TimeUnit.Month)]
[InlineData(TimeUnit.Week)]
[InlineData(TimeUnit.Year)]
public void ThowsOnUnsupportedData(TimeUnit units)
{
var dummyRate = ByteSize.FromBits(1).Per(TimeSpan.FromSeconds(1));

Assert.Throws<NotSupportedException>(() =>
{
dummyRate.Humanize(units);
});
}
}
}
1 change: 1 addition & 0 deletions src/Humanizer.Tests/Humanizer.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Bytes\ByteRateTests.cs" />
<Compile Include="Bytes\ComparingTests.cs" />
<Compile Include="Bytes\CreatingTests.cs" />
<Compile Include="Bytes\ByteSizeExtensionsTests.cs" />
Expand Down
66 changes: 66 additions & 0 deletions src/Humanizer/Bytes/ByteRate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System;
using Humanizer.Localisation;

namespace Humanizer.Bytes
{

/// <summary>
/// Class to hold a ByteSize and a measurement interval, for the purpose of calculating the rate of transfer
/// </summary>
public class ByteRate
{
/// <summary>
/// Quantity of bytes
/// </summary>
/// <returns></returns>
public ByteSize Size { get; private set;}

/// <summary>
/// Interval that bytes were transferred in
/// </summary>
/// <returns></returns>
public TimeSpan Interval { get; private set; }

/// <summary>
/// Create a ByteRate with given quantity of bytes across an interval
/// </summary>
/// <param name="size"></param>
/// <param name="interval"></param>
public ByteRate(ByteSize size, TimeSpan interval)
{
this.Size = size;
this.Interval = interval;
}

/// <summary>
/// Calculate rate for the quantity of bytes and interval defined by this instance
/// </summary>
/// <param name="timeUnit">Unit of time to calculate rate for (defaults is per second)</param>
/// <returns></returns>
public string Humanize(TimeUnit timeUnit = TimeUnit.Second)
{
TimeSpan displayInterval;
string displayUnit;

if (timeUnit == TimeUnit.Second)
{
displayInterval = TimeSpan.FromSeconds(1);
displayUnit = "s";
}
else if (timeUnit == TimeUnit.Minute)
{
displayInterval = TimeSpan.FromMinutes(1);
displayUnit = "min";
}
else if (timeUnit == TimeUnit.Hour)
{
displayInterval = TimeSpan.FromHours(1);
displayUnit = "hour";
}
else
throw new NotSupportedException("timeUnit must be Second, Minute, or Hour");

return (new ByteSize(Size.Bytes / Interval.TotalSeconds * displayInterval.TotalSeconds)).Humanize() + '/' + displayUnit;
}
}
}
14 changes: 13 additions & 1 deletion src/Humanizer/Bytes/ByteSizeExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Humanizer.Bytes;
using System;
using Humanizer.Bytes;

// ReSharper disable once CheckNamespace
namespace Humanizer
Expand Down Expand Up @@ -438,5 +439,16 @@ public static string Humanize(this ByteSize input, string format = null)
{
return string.IsNullOrWhiteSpace(format) ? input.ToString() : input.ToString(format);
}

/// <summary>
/// Turns a quantity of bytes in a given interval into a rate that can be manipulated
/// </summary>
/// <param name="size">Quantity of bytes</param>
/// <param name="interval">Interval to create rate for</param>
/// <returns></returns>
public static ByteRate Per(this ByteSize size, TimeSpan interval)
{
return new ByteRate(size, interval);
}
}
}
1 change: 1 addition & 0 deletions src/Humanizer/Humanizer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
<AssemblyOriginatorKeyFile>Humanizer.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Compile Include="Bytes\ByteRate.cs" />
<Compile Include="CollectionHumanizeExtensions.cs" />
<Compile Include="Configuration\CollectionFormatterRegistry.cs" />
<Compile Include="Localisation\CollectionFormatters\DefaultCollectionFormatter.cs" />
Expand Down

0 comments on commit 303abd4

Please sign in to comment.