#region License
// The PostgreSQL License
//
// Copyright (C) 2015 The Npgsql Development Team
//
// Permission to use, copy, modify, and distribute this software and its
// documentation for any purpose, without fee, and without a written
// agreement is hereby granted, provided that the above copyright notice
// and this paragraph and the following two paragraphs appear in all copies.
//
// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
//
// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Npgsql;
// ReSharper disable once CheckNamespace
namespace NpgsqlTypes
{
///
/// Represents the PostgreSQL interval datatype.
///
/// PostgreSQL differs from .NET in how it's interval type doesn't assume 24 hours in a day
/// (to deal with 23- and 25-hour days caused by daylight savings adjustments) and has a concept
/// of months that doesn't exist in .NET's class. (Neither datatype
/// has any concessions for leap-seconds).
/// For most uses just casting to and from TimeSpan will work correctly — in particular,
/// the results of subtracting one or the PostgreSQL date, time and
/// timestamp types from another should be the same whether you do so in .NET or PostgreSQL —
/// but if the handling of days and months in PostgreSQL is important to your application then you
/// should use this class instead of .
/// If you don't know whether these differences are important to your application, they
/// probably arent! Just use and do not use this class directly ☺
/// To avoid forcing unnecessary provider-specific concerns on users who need not be concerned
/// with them a call to on a field containing an
/// value will return a rather than an
/// . If you need the extra functionality of
/// then use .
///
///
///
///
///
#if !DNXCORE50
[Serializable]
#endif
public struct NpgsqlTimeSpan : IComparable, IComparer, IEquatable, IComparable,
IComparer
{
#region Constants
///
/// Represents the number of ticks (100ns periods) in one microsecond. This field is constant.
///
public const long TicksPerMicrosecond = TimeSpan.TicksPerMillisecond / 1000;
///
/// Represents the number of ticks (100ns periods) in one millisecond. This field is constant.
///
public const long TicksPerMillsecond = TimeSpan.TicksPerMillisecond;
///
/// Represents the number of ticks (100ns periods) in one second. This field is constant.
///
public const long TicksPerSecond = TimeSpan.TicksPerSecond;
///
/// Represents the number of ticks (100ns periods) in one minute. This field is constant.
///
public const long TicksPerMinute = TimeSpan.TicksPerMinute;
///
/// Represents the number of ticks (100ns periods) in one hour. This field is constant.
///
public const long TicksPerHour = TimeSpan.TicksPerHour;
///
/// Represents the number of ticks (100ns periods) in one day. This field is constant.
///
public const long TicksPerDay = TimeSpan.TicksPerDay;
///
/// Represents the number of hours in one day (assuming no daylight savings adjustments). This field is constant.
///
public const int HoursPerDay = 24;
///
/// Represents the number of days assumed in one month if month justification or unjustifcation is performed.
/// This is set to 30 for consistency with PostgreSQL. Note that this is means that month adjustments cause
/// a year to be taken as 30 × 12 = 360 rather than 356/366 days.
///
public const int DaysPerMonth = 30;
///
/// Represents the number of ticks (100ns periods) in one day, assuming 30 days per month.
///
public const long TicksPerMonth = TicksPerDay * DaysPerMonth;
///
/// Represents the number of months in a year. This field is constant.
///
public const int MonthsPerYear = 12;
///
/// Represents the maximum . This field is read-only.
///
public static readonly NpgsqlTimeSpan MaxValue = new NpgsqlTimeSpan(long.MaxValue);
///
/// Represents the minimum . This field is read-only.
///
public static readonly NpgsqlTimeSpan MinValue = new NpgsqlTimeSpan(long.MinValue);
///
/// Represents the zero . This field is read-only.
///
public static readonly NpgsqlTimeSpan Zero = new NpgsqlTimeSpan(0);
#endregion
private readonly int _months;
private readonly int _days;
private readonly long _ticks;
#region Constructors
///
/// Initializes a new to the specified number of ticks.
///
/// A time period expressed in 100ns units.
public NpgsqlTimeSpan(long ticks)
: this(new TimeSpan(ticks))
{
}
///
/// Initializes a new to hold the same time as a
///
/// A time period expressed in a
public NpgsqlTimeSpan(TimeSpan timespan)
: this(0, timespan.Days, timespan.Ticks - (TicksPerDay * timespan.Days))
{
}
///
/// Initializes a new to the specified number of months, days
/// & ticks.
///
/// Number of months.
/// Number of days.
/// Number of 100ns units.
public NpgsqlTimeSpan(int months, int days, long ticks)
{
_months = months;
_days = days;
_ticks = ticks;
}
///
/// Initializes a new to the specified number of
/// days, hours, minutes & seconds.
///
/// Number of days.
/// Number of hours.
/// Number of minutes.
/// Number of seconds.
public NpgsqlTimeSpan(int days, int hours, int minutes, int seconds)
: this(0, days, new TimeSpan(hours, minutes, seconds).Ticks)
{
}
///
/// Initializes a new to the specified number of
/// days, hours, minutes, seconds & milliseconds.
///
/// Number of days.
/// Number of hours.
/// Number of minutes.
/// Number of seconds.
/// Number of milliseconds.
public NpgsqlTimeSpan(int days, int hours, int minutes, int seconds, int milliseconds)
: this(0, days, new TimeSpan(0, hours, minutes, seconds, milliseconds).Ticks)
{
}
///
/// Initializes a new to the specified number of
/// months, days, hours, minutes, seconds & milliseconds.
///
/// Number of months.
/// Number of days.
/// Number of hours.
/// Number of minutes.
/// Number of seconds.
/// Number of milliseconds.
public NpgsqlTimeSpan(int months, int days, int hours, int minutes, int seconds, int milliseconds)
: this(months, days, new TimeSpan(0, hours, minutes, seconds, milliseconds).Ticks)
{
}
///
/// Initializes a new to the specified number of
/// years, months, days, hours, minutes, seconds & milliseconds.
/// Years are calculated exactly equivalent to 12 months.
///
/// Number of years.
/// Number of months.
/// Number of days.
/// Number of hours.
/// Number of minutes.
/// Number of seconds.
/// Number of milliseconds.
public NpgsqlTimeSpan(int years, int months, int days, int hours, int minutes, int seconds, int milliseconds)
: this(years * 12 + months, days, new TimeSpan(0, hours, minutes, seconds, milliseconds).Ticks)
{
}
#endregion
#region Whole Parts
///
/// The total number of ticks(100ns units) contained. This is the resolution of the
/// type. This ignores the number of days and
/// months held. If you want them included use first.
/// The resolution of the PostgreSQL
/// interval type is by default 1µs = 1,000 ns. It may be smaller as follows:
///
/// -
/// interval(0)
/// resolution of 1s (1 second)
///
/// -
/// interval(1)
/// resolution of 100ms = 0.1s (100 milliseconds)
///
/// -
/// interval(2)
/// resolution of 10ms = 0.01s (10 milliseconds)
///
/// -
/// interval(3)
/// resolution of 1ms = 0.001s (1 millisecond)
///
/// -
/// interval(4)
/// resolution of 100µs = 0.0001s (100 microseconds)
///
/// -
/// interval(5)
/// resolution of 10µs = 0.00001s (10 microseconds)
///
/// -
/// interval(6) or interval
/// resolution of 1µs = 0.000001s (1 microsecond)
///
///
/// As such, if the 100-nanosecond resolution is significant to an application, a PostgreSQL interval will
/// not suffice for those purposes.
/// In more frequent cases though, the resolution of the interval suffices.
/// will always suffice to handle the resolution of any interval value, and upon
/// writing to the database, will be rounded to the resolution used.
///
/// The number of ticks in the instance.
///
public long Ticks
{
get { return _ticks; }
}
///
/// Gets the number of whole microseconds held in the instance.
/// An in the range [-999999, 999999].
///
public int Microseconds
{
get { return (int)((_ticks / 10) % 1000000); }
}
///
/// Gets the number of whole milliseconds held in the instance.
/// An in the range [-999, 999].
///
public int Milliseconds
{
get { return (int)((_ticks / TicksPerMillsecond) % 1000); }
}
///
/// Gets the number of whole seconds held in the instance.
/// An in the range [-59, 59].
///
public int Seconds
{
get { return (int)((_ticks / TicksPerSecond) % 60); }
}
///
/// Gets the number of whole minutes held in the instance.
/// An in the range [-59, 59].
///
public int Minutes
{
get { return (int)((_ticks / TicksPerMinute) % 60); }
}
///
/// Gets the number of whole hours held in the instance.
/// Note that this can be less than -23 or greater than 23 unless
/// has been used to produce this instance.
///
public int Hours
{
get { return (int)(_ticks / TicksPerHour); }
}
///
/// Gets the number of days held in the instance.
/// Note that this does not pay attention to a time component with -24 or less hours or
/// 24 or more hours, unless has been called to produce this instance.
///
public int Days
{
get { return _days; }
}
///
/// Gets the number of months held in the instance.
/// Note that this does not pay attention to a day component with -30 or less days or
/// 30 or more days, unless has been called to produce this instance.
///
public int Months
{
get { return _months; }
}
///
/// Returns a representing the time component of the instance.
/// Note that this may have a value beyond the range ±23:59:59.9999999 unless
/// has been called to produce this instance.
///
public TimeSpan Time
{
get { return new TimeSpan(_ticks); }
}
#endregion
#region Total Parts
///
/// The total number of ticks (100ns units) in the instance, assuming 24 hours in each day and
/// 30 days in a month.
///
public long TotalTicks
{
get { return Ticks + Days * TicksPerDay + Months * TicksPerMonth; }
}
///
/// The total number of microseconds in the instance, assuming 24 hours in each day and
/// 30 days in a month.
///
public double TotalMicroseconds
{
get { return TotalTicks / 10d; }
}
///
/// The total number of milliseconds in the instance, assuming 24 hours in each day and
/// 30 days in a month.
///
public double TotalMilliseconds
{
get { return TotalTicks / (double)TicksPerMillsecond; }
}
///
/// The total number of seconds in the instance, assuming 24 hours in each day and
/// 30 days in a month.
///
public double TotalSeconds
{
get { return TotalTicks / (double)TicksPerSecond; }
}
///
/// The total number of minutes in the instance, assuming 24 hours in each day and
/// 30 days in a month.
///
public double TotalMinutes
{
get { return TotalTicks / (double)TicksPerMinute; }
}
///
/// The total number of hours in the instance, assuming 24 hours in each day and
/// 30 days in a month.
///
public double TotalHours
{
get { return TotalTicks / (double)TicksPerHour; }
}
///
/// The total number of days in the instance, assuming 24 hours in each day and
/// 30 days in a month.
///
public double TotalDays
{
get { return TotalTicks / (double)TicksPerDay; }
}
///
/// The total number of months in the instance, assuming 24 hours in each day and
/// 30 days in a month.
///
public double TotalMonths
{
get { return TotalTicks / (double)TicksPerMonth; }
}
#endregion
#region Create From Part
///
/// Creates an from a number of ticks.
///
/// The number of ticks (100ns units) in the interval.
/// A d with the given number of ticks.
public static NpgsqlTimeSpan FromTicks(long ticks)
{
return new NpgsqlTimeSpan(ticks).Canonicalize();
}
///
/// Creates an from a number of microseconds.
///
/// The number of microseconds in the interval.
/// A d with the given number of microseconds.
public static NpgsqlTimeSpan FromMicroseconds(double micro)
{
return FromTicks((long)(micro * TicksPerMicrosecond));
}
///
/// Creates an from a number of milliseconds.
///
/// The number of milliseconds in the interval.
/// A d with the given number of milliseconds.
public static NpgsqlTimeSpan FromMilliseconds(double milli)
{
return FromTicks((long)(milli * TicksPerMillsecond));
}
///
/// Creates an from a number of seconds.
///
/// The number of seconds in the interval.
/// A d with the given number of seconds.
public static NpgsqlTimeSpan FromSeconds(double seconds)
{
return FromTicks((long)(seconds * TicksPerSecond));
}
///
/// Creates an from a number of minutes.
///
/// The number of minutes in the interval.
/// A d with the given number of minutes.
public static NpgsqlTimeSpan FromMinutes(double minutes)
{
return FromTicks((long)(minutes * TicksPerMinute));
}
///
/// Creates an from a number of hours.
///
/// The number of hours in the interval.
/// A d with the given number of hours.
public static NpgsqlTimeSpan FromHours(double hours)
{
return FromTicks((long)(hours * TicksPerHour));
}
///
/// Creates an from a number of days.
///
/// The number of days in the interval.
/// A d with the given number of days.
public static NpgsqlTimeSpan FromDays(double days)
{
return FromTicks((long)(days * TicksPerDay));
}
///
/// Creates an from a number of months.
///
/// The number of months in the interval.
/// A d with the given number of months.
public static NpgsqlTimeSpan FromMonths(double months)
{
return FromTicks((long)(months * TicksPerMonth));
}
#endregion
#region Arithmetic
///
/// Adds another interval to this instance and returns the result.
///
/// An to add to this instance.
/// An whose values are the sums of the two instances.
public NpgsqlTimeSpan Add(NpgsqlTimeSpan interval)
{
return new NpgsqlTimeSpan(Months + interval.Months, Days + interval.Days, Ticks + interval.Ticks);
}
///
/// Subtracts another interval from this instance and returns the result.
///
/// An to subtract from this instance.
/// An whose values are the differences of the two instances.
public NpgsqlTimeSpan Subtract(NpgsqlTimeSpan interval)
{
return new NpgsqlTimeSpan(Months - interval.Months, Days - interval.Days, Ticks - interval.Ticks);
}
///
/// Returns an whose value is the negated value of this instance.
///
/// An whose value is the negated value of this instance.
public NpgsqlTimeSpan Negate()
{
return new NpgsqlTimeSpan(-Months, -Days, -Ticks);
}
///
/// This absolute value of this instance. In the case of some, but not all, components being negative,
/// the rules used for justification are used to determine if the instance is positive or negative.
///
/// An whose value is the absolute value of this instance.
public NpgsqlTimeSpan Duration()
{
return UnjustifyInterval().Ticks < 0 ? Negate() : this;
}
#endregion
#region Justification
///
/// Equivalent to PostgreSQL's justify_days function.
///
/// An based on this one, but with any hours outside of the range [-23, 23]
/// converted into days.
public NpgsqlTimeSpan JustifyDays()
{
return new NpgsqlTimeSpan(Months, Days + (int)(Ticks / TicksPerDay), Ticks % TicksPerDay);
}
///
/// Opposite to PostgreSQL's justify_days function.
///
/// An based on this one, but with any days converted to multiples of ±24hours.
public NpgsqlTimeSpan UnjustifyDays()
{
return new NpgsqlTimeSpan(Months, 0, Ticks + Days * TicksPerDay);
}
///
/// Equivalent to PostgreSQL's justify_months function.
///
/// An based on this one, but with any days outside of the range [-30, 30]
/// converted into months.
public NpgsqlTimeSpan JustifyMonths()
{
return new NpgsqlTimeSpan(Months + Days / DaysPerMonth, Days % DaysPerMonth, Ticks);
}
///
/// Opposite to PostgreSQL's justify_months function.
///
/// An based on this one, but with any months converted to multiples of ±30days.
public NpgsqlTimeSpan UnjustifyMonths()
{
return new NpgsqlTimeSpan(0, Days + Months * DaysPerMonth, Ticks);
}
///
/// Equivalent to PostgreSQL's justify_interval function.
///
/// An based on this one,
/// but with any months converted to multiples of ±30days
/// and then with any days converted to multiples of ±24hours
public NpgsqlTimeSpan JustifyInterval()
{
return JustifyMonths().JustifyDays();
}
///
/// Opposite to PostgreSQL's justify_interval function.
///
/// An based on this one, but with any months converted to multiples of ±30days and then any days converted to multiples of ±24hours;
public NpgsqlTimeSpan UnjustifyInterval()
{
return new NpgsqlTimeSpan(Ticks + Days * TicksPerDay + Months * DaysPerMonth * TicksPerDay);
}
///
/// Produces a canonical NpgslInterval with 0 months and hours in the range of [-23, 23].
///
///
/// While the fact that for many purposes, two different instances could be considered
/// equivalent (e.g. one with 2days, 3hours and one with 1day 27hours) there are different possible canonical forms.
///
/// E.g. we could move all excess hours into days and all excess days into months and have the most readable form,
/// or we could move everything into the ticks and have the form that allows for the easiest arithmetic) the form
/// chosen has two important properties that make it the best choice.
/// First, it is closest two how
/// objects are most often represented. Second, it is compatible with results of many
/// PostgreSQL functions, particularly with age() and the results of subtracting one date, time or timestamp from
/// another.
///
/// Note that the results of casting a to is
/// canonicalised.
///
///
/// An based on this one, but with months converted to multiples of ±30days and with any hours outside of the range [-23, 23]
/// converted into days.
public NpgsqlTimeSpan Canonicalize()
{
return new NpgsqlTimeSpan(0, Days + Months * DaysPerMonth + (int)(Ticks / TicksPerDay), Ticks % TicksPerDay);
}
#endregion
#region Casts
///
/// Implicit cast of a to an
///
/// A
/// An eqivalent, canonical, .
public static implicit operator NpgsqlTimeSpan(TimeSpan timespan)
{
return new NpgsqlTimeSpan(timespan).Canonicalize();
}
///
/// Explicit cast of an to a .
///
/// A .
/// An equivalent .
public static explicit operator TimeSpan(NpgsqlTimeSpan interval)
{
return new TimeSpan(interval.Ticks + interval.Days * TicksPerDay + interval.Months * DaysPerMonth * TicksPerDay);
}
#endregion
#region Comparison
///
/// Returns true if another is exactly the same as this instance.
///
/// An for comparison.
/// true if the two instances are exactly the same,
/// false otherwise.
public bool Equals(NpgsqlTimeSpan other)
{
return Ticks == other.Ticks && Days == other.Days && Months == other.Months;
}
///
/// Returns true if another object is an , that is exactly the same as
/// this instance
///
/// An for comparison.
/// true if the argument is an and is exactly the same
/// as this one, false otherwise.
public override bool Equals(object obj)
{
if (obj is NpgsqlTimeSpan) {
return Equals((NpgsqlTimeSpan)obj);
}
return false;
}
///
/// Compares two instances.
///
/// The first .
/// The second .
/// 0 if the two are equal or equivalent. A value greater than zero if x is greater than y,
/// a value less than zero if x is less than y.
public static int Compare(NpgsqlTimeSpan x, NpgsqlTimeSpan y)
{
return x.CompareTo(y);
}
int IComparer.Compare(NpgsqlTimeSpan x, NpgsqlTimeSpan y)
{
return x.CompareTo(y);
}
int IComparer.Compare(object x, object y)
{
if (x == null) {
return y == null ? 0 : 1;
}
if (y == null) {
return -1;
}
try {
return ((IComparable)x).CompareTo(y);
} catch (Exception) {
throw new ArgumentException();
}
}
///
/// A hash code suitable for uses with hashing algorithms.
///
/// An signed integer.
public override int GetHashCode()
{
return UnjustifyInterval().Ticks.GetHashCode();
}
///
/// Compares this instance with another/
///
/// An to compare this with.
/// 0 if the instances are equal or equivalent. A value less than zero if
/// this instance is less than the argument. A value greater than zero if this instance
/// is greater than the instance.
public int CompareTo(NpgsqlTimeSpan other)
{
return UnjustifyInterval().Ticks.CompareTo(other.UnjustifyInterval().Ticks);
}
///
/// Compares this instance with another/
///
/// An object to compare this with.
/// 0 if the argument is an and the instances are equal or equivalent.
/// A value less than zero if the argument is an and
/// this instance is less than the argument.
/// A value greater than zero if the argument is an and this instance
/// is greater than the instance.
/// A value greater than zero if the argument is null.
/// The argument is not an .
public int CompareTo(object other)
{
if (other == null) {
return 1;
} else if (other is NpgsqlTimeSpan) {
return CompareTo((NpgsqlTimeSpan)other);
} else {
throw new ArgumentException();
}
}
#endregion
#region String Conversions
///
/// Parses a and returns a instance.
/// Designed to use the formats generally returned by PostgreSQL.
///
/// The to parse.
/// An represented by the argument.
/// The string was null.
/// A value obtained from parsing the string exceeded the values allowed for the relevant component.
/// The string was not in a format that could be parsed to produce an .
public static NpgsqlTimeSpan Parse(string str)
{
if (str == null) {
throw new ArgumentNullException("str");
}
str = str.Replace('s', ' '); //Quick and easy way to catch plurals.
try {
int years = 0;
int months = 0;
int days = 0;
int hours = 0;
int minutes = 0;
decimal seconds = 0m;
int idx = str.IndexOf("year");
if (idx > 0) {
years = int.Parse(str.Substring(0, idx));
str = SafeSubstring(str, idx + 5);
}
idx = str.IndexOf("mon");
if (idx > 0) {
months = int.Parse(str.Substring(0, idx));
str = SafeSubstring(str, idx + 4);
}
idx = str.IndexOf("day");
if (idx > 0) {
days = int.Parse(str.Substring(0, idx));
str = SafeSubstring(str, idx + 4).Trim();
}
if (str.Length > 0) {
bool isNegative = str[0] == '-';
string[] parts = str.Split(':');
switch (parts.Length) //One of those times that fall-through would actually be good.
{
case 1:
hours = int.Parse(parts[0]);
break;
case 2:
hours = int.Parse(parts[0]);
minutes = int.Parse(parts[1]);
break;
default:
hours = int.Parse(parts[0]);
minutes = int.Parse(parts[1]);
seconds = decimal.Parse(parts[2], System.Globalization.CultureInfo.InvariantCulture.NumberFormat);
break;
}
if (isNegative) {
minutes *= -1;
seconds *= -1;
}
}
long ticks = hours * TicksPerHour + minutes * TicksPerMinute + (long)(seconds * TicksPerSecond);
return new NpgsqlTimeSpan(years * MonthsPerYear + months, days, ticks);
} catch (OverflowException) {
throw;
} catch (Exception) {
throw new FormatException();
}
}
private static string SafeSubstring(string s, int startIndex)
{
if (startIndex >= s.Length)
return string.Empty;
else
return s.Substring(startIndex);
}
///
/// Attempt to parse a to produce an .
///
/// The to parse.
/// (out) The produced, or if the parsing failed.
/// true if the parsing succeeded, false otherwise.
public static bool TryParse(string str, out NpgsqlTimeSpan result)
{
try {
result = Parse(str);
return true;
} catch (Exception) {
result = Zero;
return false;
}
}
///
/// Create a representation of the instance.
/// The format returned is of the form:
/// [M mon[s]] [d day[s]] [HH:mm:ss[.f[f[f[f[f[f[f[f[f]]]]]]]]]]
/// A zero is represented as 00:00:00
///
/// Ticks are 100ns, Postgress resolution is only to 1µs at most. Hence we lose 1 or more decimal
/// precision in storing values in the database. Despite this, this method will output that extra
/// digit of precision. It's forward-compatible with any future increases in resolution up to 100ns,
/// and also makes this ToString() more applicable to any other use-case.
///
///
/// The representation.
public override string ToString()
{
StringBuilder sb = new StringBuilder();
if (Months != 0) {
sb.Append(Months).Append(Math.Abs(Months) == 1 ? " mon " : " mons ");
}
if (Days != 0) {
if (Months < 0 && Days > 0) {
sb.Append('+');
}
sb.Append(Days).Append(Math.Abs(Days) == 1 ? " day " : " days ");
}
if (Ticks != 0 || sb.Length == 0) {
if (Ticks < 0) {
sb.Append('-');
} else if (Days < 0 || (Days == 0 && Months < 0)) {
sb.Append('+');
}
// calculate total seconds and then subtract total whole minutes in seconds to get just the seconds and fractional part
decimal seconds = _ticks / (decimal)TicksPerSecond - (_ticks / TicksPerMinute) * 60;
sb.Append(Math.Abs(Hours).ToString("D2")).Append(':').Append(Math.Abs(Minutes).ToString("D2")).Append(':').Append(Math.Abs(seconds).ToString("0#.######", System.Globalization.CultureInfo.InvariantCulture.NumberFormat));
}
if (sb[sb.Length - 1] == ' ') {
sb.Remove(sb.Length - 1, 1);
}
return sb.ToString();
}
#endregion
#region Common Operators
///
/// Adds two together.
///
/// The first to add.
/// The second to add.
/// An whose values are the sum of the arguments.
public static NpgsqlTimeSpan operator +(NpgsqlTimeSpan x, NpgsqlTimeSpan y)
{
return x.Add(y);
}
///
/// Subtracts one from another.
///
/// The to subtract the other from.
/// The to subtract from the other.
/// An whose values are the difference of the arguments
public static NpgsqlTimeSpan operator -(NpgsqlTimeSpan x, NpgsqlTimeSpan y)
{
return x.Subtract(y);
}
///
/// Returns true if two are exactly the same.
///
/// The first to compare.
/// The second to compare.
/// true if the two arguments are exactly the same, false otherwise.
public static bool operator ==(NpgsqlTimeSpan x, NpgsqlTimeSpan y)
{
return x.Equals(y);
}
///
/// Returns false if two are exactly the same.
///
/// The first to compare.
/// The second to compare.
/// false if the two arguments are exactly the same, true otherwise.
public static bool operator !=(NpgsqlTimeSpan x, NpgsqlTimeSpan y)
{
return !(x == y);
}
///
/// Compares two instances to see if the first is less than the second
///
/// The first to compare.
/// The second to compare.
/// true if the first is less than second, false otherwise.
public static bool operator <(NpgsqlTimeSpan x, NpgsqlTimeSpan y)
{
return x.UnjustifyInterval().Ticks < y.UnjustifyInterval().Ticks;
}
///
/// Compares two instances to see if the first is less than or equivalent to the second
///
/// The first to compare.
/// The second to compare.
/// true if the first is less than or equivalent to second, false otherwise.
public static bool operator <=(NpgsqlTimeSpan x, NpgsqlTimeSpan y)
{
return x.UnjustifyInterval().Ticks <= y.UnjustifyInterval().Ticks;
}
///
/// Compares two instances to see if the first is greater than the second
///
/// The first to compare.
/// The second to compare.
/// true if the first is greater than second, false otherwise.
public static bool operator >(NpgsqlTimeSpan x, NpgsqlTimeSpan y)
{
return !(x <= y);
}
///
/// Compares two instances to see if the first is greater than or equivalent the second
///
/// The first to compare.
/// The second to compare.
/// true if the first is greater than or equivalent to the second, false otherwise.
public static bool operator >=(NpgsqlTimeSpan x, NpgsqlTimeSpan y)
{
return !(x < y);
}
///
/// Returns the instance.
///
/// An .
/// The argument.
public static NpgsqlTimeSpan operator +(NpgsqlTimeSpan x)
{
return x;
}
///
/// Negates an instance.
///
/// An .
/// The negation of the argument.
public static NpgsqlTimeSpan operator -(NpgsqlTimeSpan x)
{
return x.Negate();
}
#endregion
}
}