//******************************************************************************************************
// Ticks.cs - Gbtc
//
// Copyright © 2014, Grid Protection Alliance. All Rights Reserved.
//
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
// the NOTICE file distributed with this work for additional information regarding copyright ownership.
// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may
// not use this file except in compliance with the License. You may obtain a copy of the License at:
//
// http://www.opensource.org/licenses/MIT
//
// Unless agreed to in writing, the subject software distributed under the License is distributed on an
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
// License for the specific language governing permissions and limitations.
//
// Code Modification History:
// ----------------------------------------------------------------------------------------------------
// 11/12/2004 - J. Ritchie Carroll
// Initial version of source generated.
// 08/04/2009 - Josh L. Patterson
// Edited Code Comments.
// 09/14/2009 - Stephen C. Wills
// Added new header and license agreement.
// 12/14/2012 - Starlynn Danyelle Gilliam
// Modified Header.
// 02/16/2014 - Steven E. Chisholm
// In-lined a large portion of the smaller methods. Also fixed errors
// in Equals(object) and CompareTo(object)
// 02/18/2014 - J. Ritchie Carroll
// Added sub-second distribution functions for common use.
//
//******************************************************************************************************
#region [ Contributor License Agreements ]
/**************************************************************************\
Copyright © 2009 - J. Ritchie Carroll
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\**************************************************************************/
#endregion
using System;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Runtime.CompilerServices;
using GSF.Units;
namespace GSF
{
#region [ Enumerations ]
///
/// Time intervals enumeration used by method.
///
public enum BaselineTimeInterval
{
///
/// Baseline timestamp to the second (i.e., starting at zero milliseconds).
///
Second,
///
/// Baseline timestamp to the minute (i.e., starting at zero seconds and milliseconds).
///
Minute,
///
/// Baseline timestamp to the hour (i.e., starting at zero minutes, seconds and milliseconds).
///
Hour,
///
/// Baseline timestamp to the day (i.e., starting at zero hours, minutes, seconds and milliseconds).
///
Day,
///
/// Baseline timestamp to the month (i.e., starting at day one, zero hours, minutes, seconds and milliseconds).
///
Month,
///
/// Baseline timestamp to the year (i.e., starting at month one, day one, zero hours, minutes, seconds and milliseconds).
///
Year
}
#endregion
///
/// Represents an instant in time, or time period, as a 64-bit signed integer with a value that is expressed as the number
/// of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001.
///
///
///
/// can represent an "instant in time" and therefore can be used exactly like a .
/// The difference between and is that is essentially a long
/// integer (i.e., an ) which represents the number of ticks that have elapsed since 12:00:00 midnight,
/// January 1, 0001 with each tick having a resolution of 100-nanoseconds. You would use in places where
/// you needed to directly represent time in high-resolution, i.e., time with sub-second accuracy, using an object that will
/// act like a long integer but handle time conversions. can also represent a "time period" (e.g., the
/// number of ticks elapsed since a process started) and thus can also be used like a ; when used in
/// this manner the method can be used to convert the value
/// into a handy textual representation of elapsed years, days, hours, minutes and seconds or sub-seconds.
///
///
/// This class behaves just like an representing a time in ticks; it is implicitly castable to and from
/// an and therefore can be generally used "as" an Int64 directly. It is also implicitly castable to and
/// from a , a , an and a .
///
///
// ReSharper disable RedundantNameQualifier
[Serializable]
public struct Ticks : IComparable, IFormattable, IConvertible, IComparable, IComparable, IComparable, IComparable, IEquatable, IEquatable, IEquatable, IEquatable
{
#region [ Members ]
// Constants
///
/// Number of 100-nanosecond ticks in one second.
///
public const long PerSecond = 10000000L;
///
/// Number of 100-nanosecond ticks in one millisecond.
///
public const long PerMillisecond = (long)(Ticks.PerSecond * SI.Milli);
///
/// Number of 100-nanosecond ticks in one microsecond.
///
public const long PerMicrosecond = (long)(Ticks.PerSecond * SI.Micro);
///
/// Number of 100-nanosecond ticks in one minute.
///
public const long PerMinute = 60L * Ticks.PerSecond;
///
/// Number of 100-nanosecond ticks in one hour.
///
public const long PerHour = 60L * Ticks.PerMinute;
///
/// Number of 100-nanosecond ticks in one day.
///
public const long PerDay = 24L * Ticks.PerHour;
// Fields
///
/// Time value stored in ticks.
///
public readonly long Value;
#endregion
#region [ Constructors ]
///
/// Creates a new .
///
/// New time value in ticks.
public Ticks(long value)
{
Value = value;
}
///
/// Creates a new .
///
/// New time value as a .
public Ticks(DateTime value)
{
Value = value.Ticks;
}
///
/// Creates a new .
///
/// New time value as a .
public Ticks(TimeSpan value)
{
Value = value.Ticks;
}
#endregion
#region [ Methods ]
///
/// Gets the value in equivalent number of days.
///
/// Value of in days.
///
/// If value represents an instant in time, returned value will represent the number of days
/// that have elapsed since 12:00:00 midnight, January 1, 0001.
///
public double ToDays()
{
return ToSeconds() / Time.SecondsPerDay;
}
///
/// Gets the value in equivalent number of hours.
///
/// Value of in hours.
///
/// If value represents an instant in time, returned value will represent the number of hours
/// that have elapsed since 12:00:00 midnight, January 1, 0001.
///
public double ToHours()
{
return ToSeconds() / Time.SecondsPerHour;
}
///
/// Gets the value in equivalent number of minutes.
///
/// Value of in minutes.
///
/// If value represents an instant in time, returned value will represent the number of minutes
/// that have elapsed since 12:00:00 midnight, January 1, 0001.
///
public double ToMinutes()
{
return ToSeconds() / Time.SecondsPerMinute;
}
///
/// Gets the value in equivalent number of seconds.
///
/// Value of in seconds.
///
/// If value represents an instant in time, returned value will represent the number of seconds
/// that have elapsed since 12:00:00 midnight, January 1, 0001.
///
public double ToSeconds()
{
return Value / (double)Ticks.PerSecond;
}
///
/// Gets the value in equivalent number of milliseconds.
///
/// Value of in milliseconds.
///
/// If value represents an instant in time, returned value will represent the number of milliseconds
/// that have elapsed since 12:00:00 midnight, January 1, 0001.
///
public double ToMilliseconds()
{
return Value / (double)Ticks.PerMillisecond;
}
///
/// Gets the value in equivalent number of microseconds.
///
/// Value of in microseconds.
///
/// If value represents an instant in time, returned value will represent the number of microseconds
/// that have elapsed since 12:00:00 midnight, January 1, 0001.
///
public double ToMicroseconds()
{
return Value / (double)Ticks.PerMicrosecond;
}
///
/// Determines if time, represented by value in UTC time, is valid by comparing it to
/// the system clock.
///
/// The allowed lag time, in seconds, before assuming time is too old to be valid.
/// The allowed lead time, in seconds, before assuming time is too advanced to be valid.
/// True, if UTC time represented by value, is within the specified range.
///
/// Time, represented by value, is considered valid if it exists within the specified
/// and range of system clock time in UTC. Note
/// that and must be greater than zero, but can be set
/// to sub-second intervals.
///
///
/// and must be greater than zero, but can be less than one.
///
public bool UtcTimeIsValid(double lagTime, double leadTime)
{
return TimeIsValid(DateTime.UtcNow.Ticks, lagTime, leadTime);
}
///
/// Determines if time, represented by value in UTC time, is valid by comparing it to
/// the system clock.
///
/// The allowed lag time, in ticks, before assuming time is too old to be valid.
/// The allowed lead time, in ticks, before assuming time is too advanced to be valid.
/// True, if UTC time represented by value, is within the specified range.
///
/// Time, represented by value, is considered valid if it exists within the specified
/// and range of system clock time in UTC. Note
/// that and must be greater than zero.
///
///
/// and must be greater than zero.
///
public bool UtcTimeIsValid(Ticks lagTime, Ticks leadTime)
{
return TimeIsValid(DateTime.UtcNow.Ticks, lagTime, leadTime);
}
///
/// Determines if time, represented by value in local time, is valid by comparing it to
/// the system clock.
///
/// The allowed lag time, in seconds, before assuming time is too old to be valid.
/// The allowed lead time, in seconds, before assuming time is too advanced to be valid.
/// True, if local time represented by value, is within the specified range.
///
/// Time, represented by value, is considered valid if it exists within the specified
/// and range of local system clock time. Note
/// that and must be greater than zero, but can be set
/// to sub-second intervals.
///
///
/// and must be greater than zero, but can be less than one.
///
public bool LocalTimeIsValid(double lagTime, double leadTime)
{
return TimeIsValid(DateTime.Now.Ticks, lagTime, leadTime);
}
///
/// Determines if time, represented by value in local time, is valid by comparing it to
/// the system clock.
///
/// The allowed lag time, in ticks, before assuming time is too old to be valid.
/// The allowed lead time, in ticks, before assuming time is too advanced to be valid.
/// True, if local time represented by value, is within the specified range.
///
/// Time, represented by value, is considered valid if it exists within the specified
/// and range of local system clock time. Note
/// that and must be greater than zero.
///
///
/// and must be greater than zero.
///
public bool LocalTimeIsValid(Ticks lagTime, Ticks leadTime)
{
return TimeIsValid(DateTime.Now.Ticks, lagTime, leadTime);
}
///
/// Determines if time, represented by value, is valid by comparing it to the specified
/// current time.
///
/// Specified current time (e.g., could be DateTime.Now.Ticks).
/// The allowed lag time, in seconds, before assuming time is too old to be valid.
/// The allowed lead time, in seconds, before assuming time is too advanced to be valid.
/// True, if time represented by value, is within the specified range.
///
/// Time, represented by value, is considered valid if it exists within the specified
/// and range of . Note
/// that and must be greater than zero, but can be set
/// to sub-second intervals.
///
///
/// and must be greater than zero, but can be less than one.
///
public bool TimeIsValid(Ticks currentTime, double lagTime, double leadTime)
{
if (lagTime <= 0)
throw new ArgumentOutOfRangeException(nameof(lagTime), "lagTime must be greater than zero, but it can be less than one");
if (leadTime <= 0)
throw new ArgumentOutOfRangeException(nameof(leadTime), "leadTime must be greater than zero, but it can be less than one");
double distance = (currentTime.Value - Value) / (double)Ticks.PerSecond;
return (distance >= -leadTime && distance <= lagTime);
}
///
/// Determines if time, represented by value, is valid by comparing it to the specified
/// current time.
///
/// Specified current time (e.g., could be DateTime.Now.Ticks).
/// The allowed lag time, in ticks, before assuming time is too old to be valid.
/// The allowed lead time, in ticks, before assuming time is too advanced to be valid.
/// True, if time represented by value, is within the specified range.
///
/// Time, represented by value, is considered valid if it exists within the specified
/// and range of . Note
/// that and must be greater than zero.
///
///
/// and must be greater than zero.
///
public bool TimeIsValid(Ticks currentTime, Ticks lagTime, Ticks leadTime)
{
if (lagTime.Value <= 0)
throw new ArgumentOutOfRangeException(nameof(lagTime), "lagTime must be greater than zero");
if (leadTime.Value <= 0)
throw new ArgumentOutOfRangeException(nameof(leadTime), "leadTime must be greater than zero");
long distance = (currentTime.Value - Value);
return (distance >= -leadTime.Value && distance <= lagTime.Value);
}
///
/// Gets the distance, in 100-nanoseconds intervals, beyond the top of the second in the timestamp
/// represented by the .
///
///
/// Number of 100-nanoseconds intervals value is from the top of the second.
///
public Ticks DistanceBeyondSecond()
{
// Calculate the number of ticks past the top of the second
return Value - (Value - Value % Ticks.PerSecond);
}
///
/// Creates a new value that represents a base-lined timestamp, in 100-nanoseconds
/// intervals, that begins at the beginning of the specified time interval.
///
///
/// to which timestamp should be base-lined.
///
///
/// A new value that represents a base-lined timestamp, in 100-nanoseconds intervals,
/// that begins at the specified .
///
///
/// Base-lining to the would return the
/// value starting at zero milliseconds.
/// Base-lining to the would return the
/// value starting at zero seconds and milliseconds.
/// Base-lining to the would return the
/// value starting at zero minutes, seconds and milliseconds.
/// Base-lining to the would return the
/// value starting at zero hours, minutes, seconds and milliseconds.
/// Base-lining to the would return the
/// value starting at day one, zero hours, minutes, seconds and milliseconds.
/// Base-lining to the would return the
/// value starting at month one, day one, zero hours, minutes, seconds and milliseconds.
///
public Ticks BaselinedTimestamp(BaselineTimeInterval interval)
{
switch (interval)
{
case BaselineTimeInterval.Second:
return Value - Value % Ticks.PerSecond;
case BaselineTimeInterval.Minute:
return Value - Value % Ticks.PerMinute;
case BaselineTimeInterval.Hour:
return Value - Value % Ticks.PerHour;
case BaselineTimeInterval.Day:
return Value - Value % Ticks.PerDay;
case BaselineTimeInterval.Month:
DateTime toMonth = new DateTime(Value);
return new DateTime(toMonth.Year, toMonth.Month, 1, 0, 0, 0, 0).Ticks;
case BaselineTimeInterval.Year:
return new DateTime((new DateTime(Value)).Year, 1, 1, 0, 0, 0, 0).Ticks;
default:
return this;
}
}
///
/// Converts the value of the value to its equivalent string representation.
///
/// A string representation of the value.
public override string ToString()
{
return ((DateTime)this).ToString();
}
///
/// Converts the value to its equivalent string representation, using
/// the specified format.
///
/// A format string.
///
/// The string representation of the value of this instance as specified by format.
///
public string ToString(string format)
{
return ((DateTime)this).ToString(format);
}
///
/// Converts the value to its equivalent string representation, using
/// the specified culture-specific format information.
///
///
/// A that supplies culture-specific formatting information.
///
///
/// The string representation of the value of this instance as specified by provider.
///
public string ToString(IFormatProvider provider)
{
return ((DateTime)this).ToString(provider);
}
///
/// Converts the value to its equivalent string representation, using
/// specified format and culture-specific format information.
///
/// A format specification.
///
/// A that supplies culture-specific formatting information.
///
///
/// The string representation of the value of this instance as specified by format and provider.
///
public string ToString(string format, IFormatProvider provider)
{
return ((DateTime)this).ToString(format, provider);
}
///
/// Converts the value into a textual representation of years, days, hours,
/// minutes and seconds.
///
///
/// Note that this ToElapsedTimeString overload will not display fractional seconds. To allow
/// display of fractional seconds, or completely remove second resolution from the textual
/// representation, use the overload instead.
///
///
/// The string representation of the value of this instance, consisting of the number of
/// years, days, hours, minutes and seconds represented by this value.
///
public string ToElapsedTimeString()
{
return Time.ToElapsedTimeString(ToSeconds(), 0);
}
///
/// Converts the value into a textual representation of years, days, hours,
/// minutes and seconds with the specified number of fractional digits.
///
/// Number of fractional digits to display for seconds.
///
/// Minimum sub-second resolution to display. Defaults to .
///
///
/// Set to -1 to suppress seconds display, this will
/// force minimum resolution of time display to minutes.
///
///
/// The string representation of the value of this instance, consisting of the number of
/// years, days, hours, minutes and seconds represented by this value.
///
///
/// is not less than or equal to or
/// is not defined in array.
///
public string ToElapsedTimeString(int secondPrecision, double minimumSubSecondResolution = SI.Milli)
{
return Time.ToElapsedTimeString(ToSeconds(), secondPrecision, null, minimumSubSecondResolution);
}
///
/// Converts the value into a textual representation of years, days, hours,
/// minutes and seconds with the specified number of fractional digits given string array of
/// time names.
///
/// Number of fractional digits to display for seconds.
/// Time names array to use during textual conversion.
///
/// Minimum sub-second resolution to display. Defaults to .
///
///
///
/// Set to -1 to suppress seconds display, this will
/// force minimum resolution of time display to minutes.
///
///
/// array needs one string entry for each of the following names:
/// " year", " years", " day", " days", " hour", " hours", " minute", " minutes", " second", " seconds", "less than ".
///
///
///
/// The string representation of the value of this instance, consisting of the number of
/// years, days, hours, minutes and seconds represented by this value.
///
///
/// is not less than or equal to or
/// is not defined in array.
///
public string ToElapsedTimeString(int secondPrecision, string[] timeNames, double minimumSubSecondResolution = SI.Milli)
{
return Time.ToElapsedTimeString(ToSeconds(), secondPrecision, timeNames, minimumSubSecondResolution);
}
#region [ Numeric Interface Implementations ]
///
/// Compares this instance to a specified object and returns an indication of their relative values.
///
/// An object to compare, or null.
///
/// A signed number indicating the relative values of this instance and value. Returns less than zero
/// if this instance is less than value, zero if this instance is equal to value, or greater than zero
/// if this instance is greater than value.
///
/// value is not an or .
public int CompareTo(object value)
{
if ((object)value == null)
return 1;
long num;
if (value is long)
num = (long)value;
else if (value is Ticks)
num = ((Ticks)value).Value;
else if (value is DateTime)
num = ((DateTime)value).Ticks;
else if (value is TimeSpan)
num = ((TimeSpan)value).Ticks;
else
throw new ArgumentException("Argument must be an Int64 or a Ticks");
return (Value < num ? -1 : (Value > num ? 1 : 0));
}
///
/// Compares this instance to a specified and returns an indication of their
/// relative values.
///
/// A to compare.
///
/// A signed number indicating the relative values of this instance and value. Returns less than zero
/// if this instance is less than value, zero if this instance is equal to value, or greater than zero
/// if this instance is greater than value.
///
public int CompareTo(Ticks value)
{
return CompareTo(value.Value);
}
///
/// Compares this instance to a specified and returns an indication of their
/// relative values.
///
/// A to compare.
///
/// A signed number indicating the relative values of this instance and value. Returns less than zero
/// if this instance is less than value, zero if this instance is equal to value, or greater than zero
/// if this instance is greater than value.
///
public int CompareTo(DateTime value)
{
return CompareTo(value.Ticks);
}
///
/// Compares this instance to a specified and returns an indication of their
/// relative values.
///
/// A to compare.
///
/// A signed number indicating the relative values of this instance and value. Returns less than zero
/// if this instance is less than value, zero if this instance is equal to value, or greater than zero
/// if this instance is greater than value.
///
public int CompareTo(TimeSpan value)
{
return CompareTo(value.Ticks);
}
///
/// Compares this instance to a specified and returns an indication of their
/// relative values.
///
/// An to compare.
///
/// A signed number indicating the relative values of this instance and value. Returns less than zero
/// if this instance is less than value, zero if this instance is equal to value, or greater than zero
/// if this instance is greater than value.
///
public int CompareTo(long value)
{
return (Value < value ? -1 : (Value > value ? 1 : 0));
}
///
/// Returns a value indicating whether this instance is equal to a specified object.
///
/// An object to compare, or null.
///
/// True if obj is an instance of or and equals the value of this instance;
/// otherwise, False.
///
public override bool Equals(object obj)
{
if (obj is long)
return Value == (long)obj;
if (obj is Ticks)
return Value == ((Ticks)obj).Value;
if (obj is DateTime)
return Value == ((DateTime)obj).Ticks;
if (obj is TimeSpan)
return Value == ((TimeSpan)obj).Ticks;
return false;
}
///
/// Returns a value indicating whether this instance is equal to a specified value.
///
/// A value to compare to this instance.
///
/// True if obj has the same value as this instance; otherwise, False.
///
public bool Equals(Ticks obj)
{
return (Value == obj.Value);
}
///
/// Returns a value indicating whether this instance is equal to a specified value.
///
/// A value to compare to this instance.
///
/// True if obj has the same value as this instance; otherwise, False.
///
public bool Equals(DateTime obj)
{
return (Value == obj.Ticks);
}
///
/// Returns a value indicating whether this instance is equal to a specified value.
///
/// A value to compare to this instance.
///
/// True if obj has the same value as this instance; otherwise, False.
///
public bool Equals(TimeSpan obj)
{
return (Value == obj.Ticks);
}
///
/// Returns a value indicating whether this instance is equal to a specified value.
///
/// An value to compare to this instance.
///
/// True if obj has the same value as this instance; otherwise, False.
///
public bool Equals(long obj)
{
return (Value == obj);
}
///
/// Returns the hash code for this instance.
///
///
/// A 32-bit signed integer hash code.
///
public override int GetHashCode()
{
return Value.GetHashCode();
}
///
/// Returns the for value type .
///
/// The enumerated constant, .
public TypeCode GetTypeCode()
{
return TypeCode.Int64;
}
#region [ Explicit IConvertible Implementation ]
// These are explicitly implemented on the native System.Int64 implementations, so we do the same...
bool IConvertible.ToBoolean(IFormatProvider provider)
{
return Convert.ToBoolean(Value, provider);
}
char IConvertible.ToChar(IFormatProvider provider)
{
return Convert.ToChar(Value, provider);
}
sbyte IConvertible.ToSByte(IFormatProvider provider)
{
return Convert.ToSByte(Value, provider);
}
byte IConvertible.ToByte(IFormatProvider provider)
{
return Convert.ToByte(Value, provider);
}
short IConvertible.ToInt16(IFormatProvider provider)
{
return Convert.ToInt16(Value, provider);
}
ushort IConvertible.ToUInt16(IFormatProvider provider)
{
return Convert.ToUInt16(Value, provider);
}
int IConvertible.ToInt32(IFormatProvider provider)
{
return Convert.ToInt32(Value, provider);
}
uint IConvertible.ToUInt32(IFormatProvider provider)
{
return Convert.ToUInt32(Value, provider);
}
long IConvertible.ToInt64(IFormatProvider provider)
{
return Value;
}
ulong IConvertible.ToUInt64(IFormatProvider provider)
{
return Convert.ToUInt64(Value, provider);
}
float IConvertible.ToSingle(IFormatProvider provider)
{
return Convert.ToSingle(Value, provider);
}
double IConvertible.ToDouble(IFormatProvider provider)
{
return Convert.ToDouble(Value, provider);
}
decimal IConvertible.ToDecimal(IFormatProvider provider)
{
return Convert.ToDecimal(Value, provider);
}
DateTime IConvertible.ToDateTime(IFormatProvider provider)
{
return Convert.ToDateTime(Value, provider);
}
object IConvertible.ToType(Type type, IFormatProvider provider)
{
return Convert.ChangeType(Value, type, provider);
}
#endregion
#endregion
#endregion
#region [ Operators ]
#region [ Comparison Operators ]
///
/// Compares the two values for equality.
///
/// left hand operand.
/// right hand operand.
/// value representing the result.
public static bool operator ==(Ticks value1, Ticks value2)
{
return value1.Value == value2.Value;
}
///
/// Compares the two values for inequality.
///
/// left hand operand.
/// right hand operand.
/// value representing the result.
public static bool operator !=(Ticks value1, Ticks value2)
{
return value1.Value != value2.Value;
}
///
/// Returns true if left value is less than right value.
///
/// left hand operand.
/// right hand operand.
/// value representing the result.
public static bool operator <(Ticks value1, Ticks value2)
{
return value1.Value < value2.Value;
}
///
/// Returns true if left value is less or equal to than right value.
///
/// left hand operand.
/// right hand operand.
/// value representing the result.
public static bool operator <=(Ticks value1, Ticks value2)
{
return value1.Value <= value2.Value;
}
///
/// Returns true if left value is greater than right value.
///
/// left hand operand.
/// right hand operand.
/// value representing the result.
public static bool operator >(Ticks value1, Ticks value2)
{
return value1.Value > value2.Value;
}
///
/// Returns true if left value is greater than or equal to right value.
///
/// left hand operand.
/// right hand operand.
/// value representing the result.
public static bool operator >=(Ticks value1, Ticks value2)
{
return value1.Value >= value2.Value;
}
#endregion
#region [ Type Conversion Operators ]
///
/// Implicitly converts value, represented in ticks, to a .
///
/// value to convert.
/// value representing the result.
public static implicit operator Ticks(Int64 value)
{
return new Ticks(value);
}
///
/// Implicitly converts value, represented as a , to a .
///
/// value to convert.
/// value representing the result.
public static implicit operator Ticks(DateTime value)
{
return new Ticks(value);
}
///
/// Implicitly converts value, represented as a , to a .
///
/// value to convert.
/// value representing the result.
public static implicit operator Ticks(TimeSpan value)
{
return new Ticks(value);
}
///
/// Implicitly converts value, represented as a , to a .
///
/// value to convert.
/// value representing the result.
public static implicit operator Ticks(TimeTagBase value)
{
return new Ticks(value.ToDateTime());
}
///
/// Implicitly converts , represented in ticks, to an .
///
/// value to convert.
/// value representing the result.
public static implicit operator Int64(Ticks value)
{
return value.Value;
}
///
/// Implicitly converts , represented in ticks, to a .
///
/// value to convert.
/// value representing the result.
public static implicit operator DateTime(Ticks value)
{
return new DateTime(value.Value);
}
///
/// Implicitly converts , represented in ticks, to a .
///
/// value to convert.
/// value representing the result.
public static implicit operator TimeSpan(Ticks value)
{
return new TimeSpan(value.Value);
}
///
/// Implicitly converts , represented in ticks, to an .
///
/// value to convert.
/// value representing the result.
public static implicit operator NtpTimeTag(Ticks value)
{
return new NtpTimeTag(new DateTime(value.Value));
}
///
/// Implicitly converts , represented in ticks, to a .
///
/// value to convert.
/// value representing the result.
public static implicit operator UnixTimeTag(Ticks value)
{
return new UnixTimeTag(new DateTime(value.Value));
}
#endregion
#region [ Boolean and Bitwise Operators ]
///
/// Returns true if value is not zero.
///
/// value to evaluate.
/// value representing the result.
public static bool operator true(Ticks value)
{
return (value.Value != 0);
}
///
/// Returns true if value is equal to zero.
///
/// value to evaluate.
/// value representing the result.
public static bool operator false(Ticks value)
{
return (value.Value == 0);
}
///
/// Returns bitwise complement of value.
///
/// value to evaluate.
/// value representing the result.
public static Ticks operator ~(Ticks value)
{
return new Ticks(~value.Value);
}
///
/// Returns logical bitwise AND of values.
///
/// left hand operand.
/// right hand operand.
/// value representing the result.
public static Ticks operator &(Ticks value1, Ticks value2)
{
return new Ticks(value1.Value & value2.Value);
}
///
/// Returns logical bitwise OR of values.
///
/// left hand operand.
/// right hand operand.
/// value representing the result.
public static Ticks operator |(Ticks value1, Ticks value2)
{
return new Ticks(value1.Value | value2.Value);
}
///
/// Returns logical bitwise exclusive-OR of values.
///
/// left hand operand.
/// right hand operand.
/// value representing the result.
public static Ticks operator ^(Ticks value1, Ticks value2)
{
return new Ticks(value1.Value ^ value2.Value);
}
///
/// Returns value after right shifts of first value by the number of bits specified by second value.
///
/// value to shift.
/// number of bits to shift.
/// value representing the result.
public static Ticks operator >>(Ticks value, int shifts)
{
return new Ticks((value.Value >> shifts));
}
///
/// Returns value after left shifts of first value by the number of bits specified by second value.
///
/// value to shift.
/// number of bits to shift.
/// value representing the result.
public static Ticks operator <<(Ticks value, int shifts)
{
return new Ticks((value.Value << shifts));
}
#endregion
#region [ Arithmetic Operators ]
///
/// Returns computed remainder after dividing first value by the second.
///
/// Left hand operand.
/// Right hand operand.
/// value representing the result.
public static Ticks operator %(Ticks value1, Ticks value2)
{
return new Ticks(value1.Value % value2.Value);
}
///
/// Returns computed sum of values.
///
/// Left hand operand.
/// Right hand operand.
/// value representing the result.
public static Ticks operator +(Ticks value1, Ticks value2)
{
return new Ticks(value1.Value + value2.Value);
}
///
/// Returns computed difference of values.
///
/// Left hand operand.
/// Right hand operand.
/// value representing the result.
public static Ticks operator -(Ticks value1, Ticks value2)
{
return new Ticks(value1.Value - value2.Value);
}
///
/// Returns computed product of values.
///
/// Left hand operand.
/// Right hand operand.
/// value representing the result.
public static Ticks operator *(Ticks value1, Ticks value2)
{
return new Ticks(value1.Value * value2.Value);
}
// Integer division operators
///
/// Returns computed division of values.
///
/// Left hand operand.
/// Right hand operand.
/// value representing the result.
public static Ticks operator /(Ticks value1, Ticks value2)
{
return new Ticks(value1.Value / value2.Value);
}
// C# doesn't expose an exponent operator but some other .NET languages do,
// so we expose the operator via its native special IL function name
///
/// Returns result of first value raised to power of second value.
///
/// Left hand operand.
/// Right hand operand.
/// value representing the result.
[EditorBrowsable(EditorBrowsableState.Advanced), SpecialName]
public static double op_Exponent(Ticks value1, Ticks value2)
{
return Math.Pow((double)value1.Value, (double)value2.Value);
}
#endregion
#endregion
#region [ Static ]
// Static Fields
///
/// Represents the largest possible value of a . This field is constant.
///
public static readonly Ticks MaxValue = (Ticks)long.MaxValue;
///
/// Represents the smallest possible value of a . This field is constant.
///
public static readonly Ticks MinValue = (Ticks)long.MinValue;
// Static Methods
///
/// Converts , in 100-nanosecond tick intervals, to seconds.
///
/// Number of ticks to convert to seconds.
/// Number seconds represented by specified in ticks.
///
/// If represents an instant in time, returned value will represent the number of seconds
/// that have elapsed since 12:00:00 midnight, January 1, 0001.
///
public static double ToSeconds(Ticks value)
{
return value / (double)Ticks.PerSecond;
}
///
/// Converts , in 100-nanosecond tick intervals, to milliseconds.
///
/// Number of ticks to convert to milliseconds.
/// Number milliseconds represented by specified in ticks.
///
/// If represents an instant in time, returned value will represent the number of milliseconds
/// that have elapsed since 12:00:00 midnight, January 1, 0001.
///
public static double ToMilliseconds(Ticks value)
{
return value / (double)Ticks.PerMillisecond;
}
///
/// Converts , in 100-nanosecond tick intervals, to microseconds.
///
/// Number of ticks to convert to microseconds.
/// Number microseconds represented by specified in ticks.
///
/// If represents an instant in time, returned value will represent the number of microseconds
/// that have elapsed since 12:00:00 midnight, January 1, 0001.
///
public static double ToMicroseconds(Ticks value)
{
return value / (double)Ticks.PerMicrosecond;
}
///
/// Creates a new from the specified in seconds.
///
/// New value in seconds.
/// New object from the specified in seconds.
public static Ticks FromSeconds(double value)
{
return new Ticks((long)(value * Ticks.PerSecond));
}
///
/// Creates a new from the specified in milliseconds.
///
/// New value in milliseconds.
/// New object from the specified in milliseconds.
public static Ticks FromMilliseconds(double value)
{
return new Ticks((long)(value * Ticks.PerMillisecond));
}
///
/// Creates a new from the specified in microseconds.
///
/// New value in microseconds.
/// New object from the specified in microseconds.
public static Ticks FromMicroseconds(double value)
{
return new Ticks((long)(value * Ticks.PerMicrosecond));
}
///
/// Converts the string representation of a number to its equivalent.
///
/// A string containing a number to convert.
///
/// A equivalent to the number contained in s.
///
/// s is null.
///
/// s represents a number less than or greater than .
///
/// s is not in the correct format.
public static Ticks Parse(string s)
{
return (Ticks)long.Parse(s);
}
///
/// Converts the string representation of a number in a specified style to its equivalent.
///
/// A string containing a number to convert.
///
/// A bitwise combination of System.Globalization.NumberStyles values that indicates the permitted format of s.
///
///
/// A equivalent to the number contained in s.
///
///
/// style is not a System.Globalization.NumberStyles value. -or- style is not a combination of
/// System.Globalization.NumberStyles.AllowHexSpecifier and System.Globalization.NumberStyles.HexNumber values.
///
/// s is null.
///
/// s represents a number less than or greater than .
///
/// s is not in a format compliant with style.
public static Ticks Parse(string s, NumberStyles style)
{
return (Ticks)long.Parse(s, style);
}
///
/// Converts the string representation of a number in a specified culture-specific format to its equivalent.
///
/// A string containing a number to convert.
///
/// A that supplies culture-specific formatting information about s.
///
///
/// A equivalent to the number contained in s.
///
/// s is null.
///
/// s represents a number less than or greater than .
///
/// s is not in the correct format.
public static Ticks Parse(string s, IFormatProvider provider)
{
return (Ticks)long.Parse(s, provider);
}
///
/// Converts the string representation of a number in a specified style and culture-specific format to its equivalent.
///
/// A string containing a number to convert.
///
/// A bitwise combination of System.Globalization.NumberStyles values that indicates the permitted format of s.
///
///
/// A that supplies culture-specific formatting information about s.
///
///
/// A equivalent to the number contained in s.
///
///
/// style is not a System.Globalization.NumberStyles value. -or- style is not a combination of
/// System.Globalization.NumberStyles.AllowHexSpecifier and System.Globalization.NumberStyles.HexNumber values.
///
/// s is null.
///
/// s represents a number less than or greater than .
///
/// s is not in a format compliant with style.
public static Ticks Parse(string s, NumberStyles style, IFormatProvider provider)
{
return (Ticks)long.Parse(s, style, provider);
}
///
/// Converts the string representation of a number to its equivalent. A return value
/// indicates whether the conversion succeeded or failed.
///
/// A string containing a number to convert.
///
/// When this method returns, contains the value equivalent to the number contained in s,
/// if the conversion succeeded, or zero if the conversion failed. The conversion fails if the s parameter is null,
/// is not of the correct format, or represents a number less than or greater than .
/// This parameter is passed uninitialized.
///
/// true if s was converted successfully; otherwise, false.
public static bool TryParse(string s, out Ticks result)
{
long parseResult;
bool parseResponse;
parseResponse = long.TryParse(s, out parseResult);
result = parseResult;
return parseResponse;
}
///
/// Converts the string representation of a number in a specified style and culture-specific format to its
/// equivalent. A return value indicates whether the conversion succeeded or failed.
///
/// A string containing a number to convert.
///
/// A bitwise combination of System.Globalization.NumberStyles values that indicates the permitted format of s.
///
///
/// When this method returns, contains the value equivalent to the number contained in s,
/// if the conversion succeeded, or zero if the conversion failed. The conversion fails if the s parameter is null,
/// is not in a format compliant with style, or represents a number less than or
/// greater than . This parameter is passed uninitialized.
///
///
/// A object that supplies culture-specific formatting information about s.
///
/// true if s was converted successfully; otherwise, false.
///
/// style is not a System.Globalization.NumberStyles value. -or- style is not a combination of
/// System.Globalization.NumberStyles.AllowHexSpecifier and System.Globalization.NumberStyles.HexNumber values.
///
public static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out Ticks result)
{
long parseResult;
bool parseResponse;
parseResponse = long.TryParse(s, style, provider, out parseResult);
result = parseResult;
return parseResponse;
}
///
/// Gets a sub-second time distribution in for the specified .
///
/// Samples per second.
/// Array of sub-second time distribution in .
public static Ticks[] SubsecondDistribution(int samplesPerSecond)
{
Ticks[] sampleTimes = new Ticks[samplesPerSecond];
double sampleFraction = 1.0D / samplesPerSecond;
for (int i = 0; i < samplesPerSecond; i++)
sampleTimes[i] = new Ticks((long)(Ticks.PerSecond * (i * sampleFraction)));
return sampleTimes;
}
///
/// Gets a sub-second time distribution in milliseconds for the specified .
///
/// Samples per second.
/// Array of sub-second time distribution in milliseconds.
public static int[] MillisecondDistribution(int samplesPerSecond)
{
return SubsecondDistribution(samplesPerSecond).Select(ticks => (int)ticks.ToMilliseconds()).ToArray();
}
///
/// Gets a sub-second time distribution in microseconds for the specified .
///
/// Samples per second.
/// Array of sub-second time distribution in microseconds.
public static int[] MicrosecondDistribution(int samplesPerSecond)
{
return SubsecondDistribution(samplesPerSecond).Select(ticks => (int)ticks.ToMicroseconds()).ToArray();
}
///
/// Returns a floor-aligned sub-second distribution timestamp for given .
///
/// Timestamp to align.
/// Samples per second to use for distribution.
/// Defines the time resolution to use when aligning to its proper distribution timestamp.
/// A floor-aligned sub-second distribution timestamp for given .
///
/// Time resolution value is typically a power of 10 based on the number of ticks per the desired resolution. The following table defines
/// common resolutions and their respective values:
///
///
/// Resolution
/// Time Resolution Value
///
/// -
/// Seconds
///
///
/// -
/// Milliseconds
///
///
/// -
/// Microseconds
///
///
/// -
/// Ticks
/// 0
///
///
/// If source timestamps have variation, i.e., they are not aligned within common distributions, the
/// can be adjusted to include slack to accommodate the variance. When including slack in the time resolution, the value will depend
/// on the , for example: you could use 330,000 for 30 samples per second, 160,000 for 60 samples
/// per second, and 80,000 for 120 samples per second. Actual slack value may need to be more or less depending on the size of the
/// source timestamp variation.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Ticks AlignToSubsecondDistribution(Ticks timestamp, int samplesPerSecond, long timeResolution)
{
// Calculate destination ticks for this frame
long ticks = timestamp.Value, baseTicks, ticksBeyondSecond, frameIndex, destinationTicks, nextDestinationTicks;
// Baseline timestamp to the top of the second
baseTicks = ticks - ticks % Ticks.PerSecond;
// Remove the seconds from ticks
ticksBeyondSecond = ticks - baseTicks;
// Calculate a frame index between 0 and m_framesPerSecond-1, corresponding to ticks
// rounded down to the nearest frame
frameIndex = (long)(ticksBeyondSecond / (Ticks.PerSecond / (double)samplesPerSecond));
// Calculate the timestamp of the nearest frame rounded up
nextDestinationTicks = (frameIndex + 1) * Ticks.PerSecond / samplesPerSecond;
// Determine whether the desired frame is the nearest
// frame rounded down or the nearest frame rounded up
if (timeResolution <= 1)
{
if (nextDestinationTicks <= ticksBeyondSecond)
destinationTicks = nextDestinationTicks;
else
destinationTicks = frameIndex * Ticks.PerSecond / samplesPerSecond;
}
else
{
// If, after translating nextDestinationTicks to the time resolution, it is less than
// or equal to ticks, nextDestinationTicks corresponds to the desired frame
if ((nextDestinationTicks / timeResolution) * timeResolution <= ticksBeyondSecond)
destinationTicks = nextDestinationTicks;
else
destinationTicks = frameIndex * Ticks.PerSecond / samplesPerSecond;
}
// Recover the seconds that were removed
destinationTicks += baseTicks;
return new Ticks(destinationTicks);
}
///
/// Returns a floor-aligned millisecond distribution timestamp for given .
///
/// Timestamp to align.
/// Samples per second to use for distribution.
/// A floor-aligned millisecond distribution timestamp for given .
public static Ticks AlignToMillisecondDistribution(Ticks timestamp, int samplesPerSecond)
{
return AlignToSubsecondDistribution(timestamp, samplesPerSecond, Ticks.PerMillisecond);
}
///
/// Returns a floor-aligned microsecond distribution timestamp for given .
///
/// Timestamp to align.
/// Samples per second to use for distribution.
/// A floor-aligned microsecond distribution timestamp for given .
public static Ticks AlignToMicrosecondDistribution(Ticks timestamp, int samplesPerSecond)
{
return AlignToSubsecondDistribution(timestamp, samplesPerSecond, Ticks.PerMicrosecond);
}
///
/// Returns the nearest sub-second distribution timestamp for given .
///
/// Timestamp to align.
/// Samples per second to use for distribution.
/// The nearest sub-second distribution timestamp for given .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Ticks RoundToSubsecondDistribution(Ticks timestamp, int samplesPerSecond)
{
// Calculate destination ticks for this frame
long ticks = timestamp.Value, baseTicks, ticksBeyondSecond, frameIndex, destinationTicks;
// Baseline timestamp to the top of the second
baseTicks = ticks - ticks % Ticks.PerSecond;
// Remove the seconds from ticks
ticksBeyondSecond = ticks - baseTicks;
// Calculate a frame index between 0 and m_framesPerSecond-1,
// corresponding to ticks rounded to the nearest frame
frameIndex = (long)Math.Round(ticksBeyondSecond / (Ticks.PerSecond / (double)samplesPerSecond));
// Calculate the timestamp of the nearest frame
destinationTicks = frameIndex * Ticks.PerSecond / samplesPerSecond;
// Recover the seconds that were removed
destinationTicks += baseTicks;
return new Ticks(destinationTicks);
}
///
/// Returns the nearest distribution timestamp for given .
///
/// Timestamp to align.
/// Samples per second to use for distribution.
/// Starting Timestamp of the Distribution.
/// The nearest distribution timestamp for given .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Ticks RoundToSecondDistribution(Ticks timestamp, double samplesPerSecond, Ticks Baseline)
{
// Calculate destination ticks for this frame
long ticks = timestamp.Value;
long baseTicks, ticksBeyondSecond, destinationTicks;
double frameIndex;
// Baseline timestamp based on start Time
baseTicks = ticks - ticks % Baseline;
// Remove the seconds from ticks
ticksBeyondSecond = ticks - baseTicks;
// Calculate a frame index between 0 and m_framesPerSecond-1,
// corresponding to ticks rounded to the nearest frame
frameIndex = Math.Round((double)ticksBeyondSecond / (double)(Ticks.PerSecond / (double)samplesPerSecond));
// Calculate the timestamp of the nearest frame
destinationTicks = (long)(frameIndex * Ticks.PerSecond / samplesPerSecond);
// Recover the seconds that were removed
destinationTicks += baseTicks;
return new Ticks(destinationTicks);
}
///
/// Returns the distribution timestamp for given or if there is no TS within the specified Tolerance.
///
/// Timestamp to align.
/// Samples per second to use for distribution.
/// Tolerance of the TS in ticks.
/// Starting Timestamp of the Distribution.
/// The distribution timestamp for given or .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Ticks ToSecondDistribution(Ticks timestamp, double samplesPerSecond, Ticks baseline, int tolerance)
{
Ticks result = RoundToSecondDistribution(timestamp, samplesPerSecond, baseline);
if (Math.Abs(result.Value - timestamp.Value) > tolerance)
return Ticks.MinValue;
return result;
}
#endregion
}
}