iothub/service/src/Common/Timestamp.cs (107 lines of code) (raw):
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.Azure.Devices.Common
{
using System;
using System.Diagnostics;
// This is meant to replace DateTime when it is primarily used to determine elapsed time. DateTime is vulnerable to clock jump when
// system wall clock is reset. Stopwatch can be used in similar scenario but it is not optimized for memory foot-print.
//
// This class is immune to clock jump with the following two exceptions:
// - When multi-processor machine has a bug in BIOS/HAL that returns inconsistent clock tick for different processor.
// - When the machine does not support high frequency CPU tick.
struct Timestamp : IComparable<Timestamp>, IEquatable<Timestamp>
{
static readonly double TickFrequency = 10000000.0 / Stopwatch.Frequency;
readonly long timestamp;
public Timestamp(long timestamp)
{
this.timestamp = timestamp;
}
public static Timestamp Now
{
get { return new Timestamp(Stopwatch.GetTimestamp()); }
}
public TimeSpan Elapsed
{
get { return new TimeSpan(this.GetElapsedDateTimeTicks()); }
}
public long ElapsedTicks
{
get
{
return this.GetElapsedDateTimeTicks();
}
}
static long ConvertRawTicksToTicks(long rawTicks)
{
if (Stopwatch.IsHighResolution)
{
double elapsedTicks = rawTicks * TickFrequency;
return (long)elapsedTicks;
}
return rawTicks;
}
long GetRawElapsedTicks()
{
return Stopwatch.GetTimestamp() - this.timestamp;
}
long GetElapsedDateTimeTicks()
{
long rawElapsedTicks = this.GetRawElapsedTicks();
return ConvertRawTicksToTicks(rawElapsedTicks);
}
public int CompareTo(Timestamp other)
{
return this.timestamp.CompareTo(other.timestamp);
}
public bool Equals(Timestamp other)
{
return this.timestamp == other.timestamp;
}
public override int GetHashCode()
{
return this.timestamp.GetHashCode();
}
public override bool Equals(object obj)
{
if (obj is Timestamp)
{
return this.Equals((Timestamp)obj);
}
return false;
}
public static bool operator ==(Timestamp t1, Timestamp t2)
{
return t1.timestamp == t2.timestamp;
}
public static bool operator !=(Timestamp t1, Timestamp t2)
{
return t1.timestamp != t2.timestamp;
}
public static bool operator >(Timestamp t1, Timestamp t2)
{
return t1.timestamp > t2.timestamp;
}
public static bool operator <(Timestamp t1, Timestamp t2)
{
return t1.timestamp < t2.timestamp;
}
public static bool operator >=(Timestamp t1, Timestamp t2)
{
return t1.timestamp >= t2.timestamp;
}
public static bool operator <=(Timestamp t1, Timestamp t2)
{
return t1.timestamp <= t2.timestamp;
}
public static Timestamp operator +(Timestamp t, TimeSpan duration)
{
long timestamp = (long)(t.timestamp + duration.Ticks / TickFrequency);
return new Timestamp(timestamp);
}
public static Timestamp operator -(Timestamp t, TimeSpan duration)
{
long timestamp = (long)(t.timestamp - duration.Ticks / TickFrequency);
return new Timestamp(timestamp);
}
public static TimeSpan operator -(Timestamp t1, Timestamp t2)
{
long rawTicks = t1.timestamp - t2.timestamp;
long ticks = ConvertRawTicksToTicks(rawTicks);
return new TimeSpan(ticks);
}
}
}