1 // NpgsqlTypes\DateDatatypes.cs
4 // Jon Hanna. (jon@hackcraft.net)
6 // Copyright (C) 2007-2008 The Npgsql Development Team
7 // npgsql-general@gborg.postgresql.org
8 // http://gborg.postgresql.org/project/npgsql/projdisplay.php
10 // Permission to use, copy, modify, and distribute this software and its
11 // documentation for any purpose, without fee, and without a written
12 // agreement is hereby granted, provided that the above copyright notice
13 // and this paragraph and the following two paragraphs appear in all copies.
15 // IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
16 // FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
17 // INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
18 // DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
19 // THE POSSIBILITY OF SUCH DAMAGE.
21 // THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
22 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
23 // AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
24 // ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
25 // TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
28 using System
.Collections
;
29 using System
.Collections
.Generic
;
33 //TODO: Lots of convenience methods! There should be nothing you can do with datetime and timestamp that you can't
34 //do just as well with these - and hence no reason not to choose these if they are appropriate.
35 //Similarly, lots of documentation is a must.
40 /// Represents the PostgreSQL interval datatype.
41 /// <remarks>PostgreSQL differs from .NET in how it's interval type doesn't assume 24 hours in a day
42 /// (to deal with 23- and 25-hour days caused by daylight savings adjustments) and has a concept
43 /// of months that doesn't exist in .NET's <see cref="TimeSpan"/> class. (Neither datatype
44 /// has any concessions for leap-seconds).
45 /// <para>For most uses just casting to and from TimeSpan will work correctly — in particular,
46 /// the results of subtracting one <see cref="DateTime"/> or the PostgreSQL date, time and
47 /// timestamp types from another should be the same whether you do so in .NET or PostgreSQL —
48 /// but if the handling of days and months in PostgreSQL is important to your application then you
49 /// should use this class instead of <see cref="TimeSpan"/>.</para>
50 /// <para>If you don't know whether these differences are important to your application, they
51 /// probably arent! Just use <see cref="TimeSpan"/> and do not use this class directly ☺</para>
52 /// <para>To avoid forcing unnecessary provider-specific concerns on users who need not be concerned
53 /// with them a call to <see cref="IDataRecord.GetValue(int)"/> on a field containing an
54 /// <see cref="NpgsqlInterval"/> value will return a <see cref="TimeSpan"/> rather than an
55 /// <see cref="NpgsqlInterval"/>. If you need the extra functionality of <see cref="NpgsqlInterval"/>
56 /// then use <see cref="Npgsql.NpgsqlDataReader.GetInterval(Int32)"/>.</para>
58 /// <seealso cref="Ticks"/>
59 /// <seealso cref="JustifyDays"/>
60 /// <seealso cref="JustifyMonths"/>
61 /// <seealso cref="Canonicalize()"/>
64 public struct NpgsqlInterval
: IComparable
, IComparer
, IEquatable
<NpgsqlInterval
>, IComparable
<NpgsqlInterval
>,
65 IComparer
<NpgsqlInterval
>
70 /// Represents the number of ticks (100ns periods) in one microsecond. This field is constant.
72 public const long TicksPerMicrosecond
= TimeSpan
.TicksPerMillisecond
/1000;
75 /// Represents the number of ticks (100ns periods) in one millisecond. This field is constant.
77 public const long TicksPerMillsecond
= TimeSpan
.TicksPerMillisecond
;
80 /// Represents the number of ticks (100ns periods) in one second. This field is constant.
82 public const long TicksPerSecond
= TimeSpan
.TicksPerSecond
;
85 /// Represents the number of ticks (100ns periods) in one minute. This field is constant.
87 public const long TicksPerMinute
= TimeSpan
.TicksPerMinute
;
90 /// Represents the number of ticks (100ns periods) in one hour. This field is constant.
92 public const long TicksPerHour
= TimeSpan
.TicksPerHour
;
95 /// Represents the number of ticks (100ns periods) in one day. This field is constant.
97 public const long TicksPerDay
= TimeSpan
.TicksPerDay
;
100 /// Represents the number of hours in one day (assuming no daylight savings adjustments). This field is constant.
102 public const int HoursPerDay
= 24;
105 /// Represents the number of days assumed in one month if month justification or unjustifcation is performed.
106 /// This is set to 30 for consistency with PostgreSQL. Note that this is means that month adjustments cause
107 /// a year to be taken as 30 × 12 = 360 rather than 356/366 days.
109 public const int DaysPerMonth
= 30;
112 /// Represents the number of ticks (100ns periods) in one day, assuming 30 days per month. <seealso cref="DaysPerMonth"/>
114 public const long TicksPerMonth
= TicksPerDay
*DaysPerMonth
;
117 /// Represents the number of months in a year. This field is constant.
119 public const int MonthsPerYear
= 12;
122 /// Represents the maximum <see cref="NpgsqlInterval"/>. This field is read-only.
124 public static readonly NpgsqlInterval MaxValue
= new NpgsqlInterval(long.MaxValue
);
127 /// Represents the minimum <see cref="NpgsqlInterval"/>. This field is read-only.
129 public static readonly NpgsqlInterval MinValue
= new NpgsqlInterval(long.MinValue
);
132 /// Represents the zero <see cref="NpgsqlInterval"/>. This field is read-only.
134 public static readonly NpgsqlInterval Zero
= new NpgsqlInterval(0);
138 private readonly int _months
;
139 private readonly int _days
;
140 private readonly long _ticks
;
145 /// Initializes a new <see cref="NpgsqlInterval"/> to the specified number of ticks.
147 /// <param name="ticks">A time period expressed in 100ns units.</param>
148 public NpgsqlInterval(long ticks
)
156 /// Initializes a new <see cref="NpgsqlInterval"/> to hold the same time as a <see cref="TimeSpan"/>
158 /// <param name="timespan">A time period expressed in a <see cref="TimeSpan"/></param>
159 public NpgsqlInterval(TimeSpan timespan
)
160 : this(timespan
.Ticks
)
165 /// Initializes a new <see cref="NpgsqlInterval"/> to the specified number of months, days
168 /// <param name="months">Number of months.</param>
169 /// <param name="days">Number of days.</param>
170 /// <param name="ticks">Number of 100ns units.</param>
171 public NpgsqlInterval(int months
, int days
, long ticks
)
179 /// Initializes a new <see cref="NpgsqlInterval"/> to the specified number of
180 /// days, hours, minutes & seconds.
182 /// <param name="days">Number of days.</param>
183 /// <param name="hours">Number of hours.</param>
184 /// <param name="minutes">Number of minutes.</param>
185 /// <param name="seconds">Number of seconds.</param>
186 public NpgsqlInterval(int days
, int hours
, int minutes
, int seconds
)
187 : this(0, days
, new TimeSpan(hours
, minutes
, seconds
).Ticks
)
192 /// Initializes a new <see cref="NpgsqlInterval"/> to the specified number of
193 /// days, hours, minutes, seconds & milliseconds.
195 /// <param name="days">Number of days.</param>
196 /// <param name="hours">Number of hours.</param>
197 /// <param name="minutes">Number of minutes.</param>
198 /// <param name="seconds">Number of seconds.</param>
199 /// <param name="milliseconds">Number of milliseconds.</param>
200 public NpgsqlInterval(int days
, int hours
, int minutes
, int seconds
, int milliseconds
)
201 : this(0, days
, new TimeSpan(hours
, minutes
, seconds
, milliseconds
).Ticks
)
206 /// Initializes a new <see cref="NpgsqlInterval"/> to the specified number of
207 /// months, days, hours, minutes, seconds & milliseconds.
209 /// <param name="months">Number of months.</param>
210 /// <param name="days">Number of days.</param>
211 /// <param name="hours">Number of hours.</param>
212 /// <param name="minutes">Number of minutes.</param>
213 /// <param name="seconds">Number of seconds.</param>
214 /// <param name="milliseconds">Number of milliseconds.</param>
215 public NpgsqlInterval(int months
, int days
, int hours
, int minutes
, int seconds
, int milliseconds
)
216 : this(months
, days
, new TimeSpan(hours
, minutes
, seconds
, milliseconds
).Ticks
)
221 /// Initializes a new <see cref="NpgsqlInterval"/> to the specified number of
222 /// years, months, days, hours, minutes, seconds & milliseconds.
223 /// <para>Years are calculated exactly equivalent to 12 months.</para>
225 /// <param name="years">Number of years.</param>
226 /// <param name="months">Number of months.</param>
227 /// <param name="days">Number of days.</param>
228 /// <param name="hours">Number of hours.</param>
229 /// <param name="minutes">Number of minutes.</param>
230 /// <param name="seconds">Number of seconds.</param>
231 /// <param name="milliseconds">Number of milliseconds.</param>
232 public NpgsqlInterval(int years
, int months
, int days
, int hours
, int minutes
, int seconds
, int milliseconds
)
233 : this(years
*12 + months
, days
, new TimeSpan(hours
, minutes
, seconds
, milliseconds
).Ticks
)
242 /// The total number of ticks(100ns units) contained. This is the resolution of the
243 /// <see cref="NpgsqlInterval"/> type. This ignores the number of days and
244 /// months held. If you want them included use <see cref="UnjustifyInterval()"/> first.
245 /// <remarks>The resolution of the PostgreSQL
246 /// interval type is by default 1µs = 1,000 ns. It may be smaller as follows:
247 /// <list type="number">
249 /// <term>interval(0)</term>
250 /// <description>resolution of 1s (1 second)</description>
253 /// <term>interval(1)</term>
254 /// <description>resolution of 100ms = 0.1s (100 milliseconds)</description>
257 /// <term>interval(2)</term>
258 /// <description>resolution of 10ms = 0.01s (10 milliseconds)</description>
261 /// <term>interval(3)</term>
262 /// <description>resolution of 1ms = 0.001s (1 millisecond)</description>
265 /// <term>interval(4)</term>
266 /// <description>resolution of 100µs = 0.0001s (100 microseconds)</description>
269 /// <term>interval(5)</term>
270 /// <description>resolution of 10µs = 0.00001s (10 microseconds)</description>
273 /// <term>interval(6) or interval</term>
274 /// <description>resolution of 1µs = 0.000001s (1 microsecond)</description>
277 /// <para>As such, if the 100-nanosecond resolution is significant to an application, a PostgreSQL interval will
278 /// not suffice for those purposes.</para>
279 /// <para>In more frequent cases though, the resolution of the interval suffices.
280 /// <see cref="NpgsqlInterval"/> will always suffice to handle the resolution of any interval value, and upon
281 /// writing to the database, will be rounded to the resolution used.</para>
283 /// <returns>The number of ticks in the instance.</returns>
287 get { return _ticks; }
291 /// Gets the number of whole microseconds held in the instance.
292 /// <returns>An in the range [-999999, 999999].</returns>
294 public int Microseconds
296 get { return (int) (_ticks/10)%1000000; }
300 /// Gets the number of whole milliseconds held in the instance.
301 /// <returns>An in the range [-999, 999].</returns>
303 public int Milliseconds
305 get { return (int) ((_ticks/TicksPerMillsecond)%1000); }
309 /// Gets the number of whole seconds held in the instance.
310 /// <returns>An in the range [-59, 59].</returns>
314 get { return (int) ((_ticks/TicksPerSecond)%60); }
318 /// Gets the number of whole minutes held in the instance.
319 /// <returns>An in the range [-59, 59].</returns>
323 get { return (int) ((_ticks/TicksPerMinute)%60); }
327 /// Gets the number of whole hours held in the instance.
328 /// <remarks>Note that this can be less than -23 or greater than 23 unless <see cref="JustifyDays()"/>
329 /// has been used to produce this instance.</remarks>
333 get { return (int) (_ticks/TicksPerHour); }
337 /// Gets the number of days held in the instance.
338 /// <remarks>Note that this does not pay attention to a time component with -24 or less hours or
339 /// 24 or more hours, unless <see cref="JustifyDays()"/> has been called to produce this instance.</remarks>
343 get { return _days; }
347 /// Gets the number of months held in the instance.
348 /// <remarks>Note that this does not pay attention to a day component with -30 or less days or
349 /// 30 or more days, unless <see cref="JustifyMonths()"/> has been called to produce this instance.</remarks>
353 get { return _months; }
357 /// Returns a <see cref="TimeSpan"/> representing the time component of the instance.
358 /// <remarks>Note that this may have a value beyond the range ±23:59:59.9999999 unless
359 /// <see cref="JustifyDays()"/> has been called to produce this instance.</remarks>
363 get { return new TimeSpan(_ticks); }
371 /// The total number of ticks (100ns units) in the instance, assuming 24 hours in each day and
372 /// 30 days in a month.
374 public long TotalTicks
376 get { return Ticks + Days*TicksPerDay + Months*TicksPerMonth; }
380 /// The total number of microseconds in the instance, assuming 24 hours in each day and
381 /// 30 days in a month.
383 public double TotalMicroseconds
385 get { return TotalTicks/10d; }
389 /// The total number of milliseconds in the instance, assuming 24 hours in each day and
390 /// 30 days in a month.
392 public double TotalMilliseconds
394 get { return TotalTicks/(double) TicksPerMillsecond; }
398 /// The total number of seconds in the instance, assuming 24 hours in each day and
399 /// 30 days in a month.
401 public double TotalSeconds
403 get { return TotalTicks/(double) TicksPerSecond; }
407 /// The total number of minutes in the instance, assuming 24 hours in each day and
408 /// 30 days in a month.
410 public double TotalMinutes
412 get { return TotalTicks/(double) TicksPerMinute; }
416 /// The total number of hours in the instance, assuming 24 hours in each day and
417 /// 30 days in a month.
419 public double TotalHours
421 get { return TotalTicks/(double) TicksPerHour; }
425 /// The total number of days in the instance, assuming 24 hours in each day and
426 /// 30 days in a month.
428 public double TotalDays
430 get { return TotalTicks/(double) TicksPerDay; }
434 /// The total number of months in the instance, assuming 24 hours in each day and
435 /// 30 days in a month.
437 public double TotalMonths
439 get { return TotalTicks/(double) TicksPerMonth; }
444 #region Create From Part
447 /// Creates an <see cref="NpgsqlInterval"/> from a number of ticks.
449 /// <param name="ticks">The number of ticks (100ns units) in the interval.</param>
450 /// <returns>A <see cref="Canonicalize()"/>d <see cref="NpgsqlInterval"/> with the given number of ticks.</returns>
451 public static NpgsqlInterval
FromTicks(long ticks
)
453 return new NpgsqlInterval(ticks
).Canonicalize();
457 /// Creates an <see cref="NpgsqlInterval"/> from a number of microseconds.
459 /// <param name="ticks">The number of microseconds in the interval.</param>
460 /// <returns>A <see cref="Canonicalize()"/>d <see cref="NpgsqlInterval"/> with the given number of microseconds.</returns>
461 public static NpgsqlInterval
FromMicroseconds(double micro
)
463 return FromTicks((long) (micro
*TicksPerMicrosecond
));
467 /// Creates an <see cref="NpgsqlInterval"/> from a number of milliseconds.
469 /// <param name="ticks">The number of milliseconds in the interval.</param>
470 /// <returns>A <see cref="Canonicalize()"/>d <see cref="NpgsqlInterval"/> with the given number of milliseconds.</returns>
471 public static NpgsqlInterval
FromMilliseconds(double milli
)
473 return FromTicks((long) (milli
*TicksPerMillsecond
));
477 /// Creates an <see cref="NpgsqlInterval"/> from a number of seconds.
479 /// <param name="ticks">The number of seconds in the interval.</param>
480 /// <returns>A <see cref="Canonicalize()"/>d <see cref="NpgsqlInterval"/> with the given number of seconds.</returns>
481 public static NpgsqlInterval
FromSeconds(double seconds
)
483 return FromTicks((long) (seconds
*TicksPerSecond
));
487 /// Creates an <see cref="NpgsqlInterval"/> from a number of minutes.
489 /// <param name="ticks">The number of minutes in the interval.</param>
490 /// <returns>A <see cref="Canonicalize()"/>d <see cref="NpgsqlInterval"/> with the given number of minutes.</returns>
491 public static NpgsqlInterval
FromMinutes(double minutes
)
493 return FromTicks((long) (minutes
*TicksPerMinute
));
497 /// Creates an <see cref="NpgsqlInterval"/> from a number of hours.
499 /// <param name="ticks">The number of hours in the interval.</param>
500 /// <returns>A <see cref="Canonicalize()"/>d <see cref="NpgsqlInterval"/> with the given number of hours.</returns>
501 public static NpgsqlInterval
FromHours(double hours
)
503 return FromTicks((long) (hours
*TicksPerHour
));
507 /// Creates an <see cref="NpgsqlInterval"/> from a number of days.
509 /// <param name="ticks">The number of days in the interval.</param>
510 /// <returns>A <see cref="Canonicalize()"/>d <see cref="NpgsqlInterval"/> with the given number of days.</returns>
511 public static NpgsqlInterval
FromDays(double days
)
513 return FromTicks((long) (days
*TicksPerDay
));
517 /// Creates an <see cref="NpgsqlInterval"/> from a number of months.
519 /// <param name="ticks">The number of months in the interval.</param>
520 /// <returns>A <see cref="Canonicalize()"/>d <see cref="NpgsqlInterval"/> with the given number of months.</returns>
521 public static NpgsqlInterval
FromMonths(double months
)
523 return FromTicks((long) (months
*TicksPerMonth
));
531 /// Adds another interval to this instance and returns the result.
533 /// <param name="interval">An <see cref="NpgsqlInterval"/> to add to this instance.</param>
534 /// <returns>An <see cref="NpgsqlInterval"></see> whose values are the sums of the two instances.</returns>
535 public NpgsqlInterval
Add(NpgsqlInterval interval
)
537 return new NpgsqlInterval(Months
+ interval
.Months
, Days
+ interval
.Days
, Ticks
+ interval
.Ticks
);
541 /// Subtracts another interval from this instance and returns the result.
543 /// <param name="interval">An <see cref="NpgsqlInterval"/> to subtract from this instance.</param>
544 /// <returns>An <see cref="NpgsqlInterval"></see> whose values are the differences of the two instances.</returns>
545 public NpgsqlInterval
Subtract(NpgsqlInterval interval
)
547 return new NpgsqlInterval(Months
- interval
.Months
, Days
- interval
.Days
, Ticks
- interval
.Ticks
);
551 /// Returns an <see cref="NpgsqlInterval"/> whose value is the negated value of this instance.
553 /// <returns>An <see cref="NpgsqlInterval"/> whose value is the negated value of this instance.</returns>
554 public NpgsqlInterval
Negate()
556 return new NpgsqlInterval(-Months
, -Days
, -Ticks
);
560 /// This absolute value of this instance. In the case of some, but not all, components being negative,
561 /// the rules used for justification are used to determine if the instance is positive or negative.
563 /// <returns>An <see cref="NpgsqlInterval"/> whose value is the absolute value of this instance.</returns>
564 public NpgsqlInterval
Duration()
566 return UnjustifyInterval().Ticks
< 0 ? Negate() : this;
571 #region Justification
574 /// Equivalent to PostgreSQL's justify_days function.
576 /// <returns>An <see cref="NpgsqlInterval"/> based on this one, but with any hours outside of the range [-23, 23]
577 /// converted into days.</returns>
578 public NpgsqlInterval
JustifyDays()
580 return new NpgsqlInterval(Months
, Days
+ (int) (Ticks
/TicksPerDay
), Ticks
%TicksPerDay
);
584 /// Opposite to PostgreSQL's justify_days function.
586 /// <returns>An <see cref="NpgsqlInterval"/> based on this one, but with any days converted to multiples of ±24hours.</returns>
587 public NpgsqlInterval
UnjustifyDays()
589 return new NpgsqlInterval(Months
, 0, Ticks
+ Days
*TicksPerDay
);
593 /// Equivalent to PostgreSQL's justify_months function.
595 /// <returns>An <see cref="NpgsqlInterval"/> based on this one, but with any days outside of the range [-30, 30]
596 /// converted into months.</returns>
597 public NpgsqlInterval
JustifyMonths()
599 return new NpgsqlInterval(Months
+ Days
/DaysPerMonth
, Days
%DaysPerMonth
, Ticks
);
603 /// Opposite to PostgreSQL's justify_months function.
605 /// <returns>An <see cref="NpgsqlInterval"/> based on this one, but with any months converted to multiples of ±30days.</returns>
606 public NpgsqlInterval
UnjustifyMonths()
608 return new NpgsqlInterval(0, Days
+ Months
*DaysPerMonth
, Ticks
);
612 /// Equivalent to PostgreSQL's justify_interval function.
614 /// <returns>An <see cref="NpgsqlInterval"/> based on this one,
615 /// but with any months converted to multiples of ±30days
616 /// and then with any days converted to multiples of ±24hours</returns>
617 public NpgsqlInterval
JustifyInterval()
619 return JustifyMonths().JustifyDays();
623 /// Opposite to PostgreSQL's justify_interval function.
625 /// <returns>An <see cref="NpgsqlInterval"/> based on this one, but with any months converted to multiples of ±30days and then any days converted to multiples of ±24hours;</returns>
626 public NpgsqlInterval
UnjustifyInterval()
628 return new NpgsqlInterval(Ticks
+ Days
*TicksPerDay
+ Months
*DaysPerMonth
*TicksPerDay
);
632 /// Produces a canonical NpgslInterval with 0 months and hours in the range of [-23, 23].
635 /// While the fact that for many purposes, two different <see cref="NpgsqlInterval"/> instances could be considered
636 /// equivalent (e.g. one with 2days, 3hours and one with 1day 27hours) there are different possible canonical forms.
638 /// E.g. we could move all excess hours into days and all excess days into months and have the most readable form,
639 /// or we could move everything into the ticks and have the form that allows for the easiest arithmetic) the form
640 /// chosen has two important properties that make it the best choice.
641 /// </para><para>First, it is closest two how
642 /// <see cref="TimeSpan"/> objects are most often represented. Second, it is compatible with results of many
643 /// PostgreSQL functions, particularly with age() and the results of subtracting one date, time or timestamp from
646 /// <para>Note that the results of casting a <see cref="TimeSpan"/> to <see cref="NpgsqlInterval"/> is
647 /// canonicalised.</para>
649 /// <returns>An <see cref="NpgsqlInterval"/> based on this one, but with months converted to multiples of ±30days and with any hours outside of the range [-23, 23]
650 /// converted into days.</return>
651 public NpgsqlInterval
Canonicalize()
653 return new NpgsqlInterval(0, Days
+ Months
*DaysPerMonth
+ (int) (Ticks
/TicksPerDay
), Ticks
%TicksPerDay
);
661 /// Implicit cast of a <see cref="TimeSpan"/> to an <see cref="NpgsqlInterval"/>
663 /// <param name="timespan">A <see cref="TimeSpan"/></param>
664 /// <returns>An eqivalent, canonical, <see cref="NpgsqlInterval"/>.</returns>
665 public static implicit operator NpgsqlInterval(TimeSpan timespan
)
667 return new NpgsqlInterval(timespan
).Canonicalize();
671 /// Implicit cast of an <see cref="NpgsqlInterval"/> to a <see cref="TimeSpan"/>.
673 /// <param name="interval">A <see cref="NpgsqlInterval"/>.</param>
674 /// <returns>An equivalent <see cref="TimeSpan"/>.</returns>
675 public static explicit operator TimeSpan(NpgsqlInterval interval
)
677 return new TimeSpan(interval
.Ticks
+ interval
.Days
*TicksPerDay
+ interval
.Months
*DaysPerMonth
*TicksPerDay
);
685 /// Returns true if another <see cref="NpgsqlInterval"/> is exactly the same as this instance.
687 /// <param name="other">An <see cref="NpgsqlInterval"/> for comparison.</param>
688 /// <returns>true if the two <see cref="NpgsqlInterval"/> instances are exactly the same,
689 /// false otherwise.</returns>
690 public bool Equals(NpgsqlInterval other
)
692 return Ticks
== other
.Ticks
&& Days
== other
.Days
&& Months
== other
.Months
;
696 /// Returns true if another object is an <see cref="NpgsqlInterval"/>, that is exactly the same as
699 /// <param name="obj">An <see cref="Object"/> for comparison.</param>
700 /// <returns>true if the argument is an <see cref="NpgsqlInterval"/> and is exactly the same
701 /// as this one, false otherwise.</returns>
702 public override bool Equals(object obj
)
708 if (obj
is NpgsqlInterval
)
710 return Equals((NpgsqlInterval
) obj
);
716 /// Compares two <see cref="NpgsqlInterval"/> instances.
718 /// <param name="x">The first <see cref="NpgsqlInterval"/>.</param>
719 /// <param name="y">The second <see cref="NpgsqlInterval"/>.</param>
720 /// <returns>0 if the two are equal or equivalent. A value greater than zero if x is greater than y,
721 /// a value less than zero if x is less than y.</returns>
722 public static int Compare(NpgsqlInterval x
, NpgsqlInterval y
)
724 return x
.CompareTo(y
);
727 int IComparer
<NpgsqlInterval
>.Compare(NpgsqlInterval x
, NpgsqlInterval y
)
729 return x
.CompareTo(y
);
732 int IComparer
.Compare(object x
, object y
)
736 return y
== null ? 0 : 1;
744 return ((IComparable
) x
).CompareTo(y
);
748 throw new ArgumentException();
753 /// A hash code suitable for uses with hashing algorithms.
755 /// <returns>An signed integer.</returns>
756 public override int GetHashCode()
758 return UnjustifyInterval().Ticks
.GetHashCode();
762 /// Compares this instance with another/
764 /// <param name="other">An <see cref="NpgsqlInterval"/> to compare this with.</param>
765 /// <returns>0 if the instances are equal or equivalent. A value less than zero if
766 /// this instance is less than the argument. A value greater than zero if this instance
767 /// is greater than the instance.</returns>
768 public int CompareTo(NpgsqlInterval other
)
770 return UnjustifyInterval().Ticks
.CompareTo(other
.UnjustifyInterval().Ticks
);
774 /// Compares this instance with another/
776 /// <param name="other">An object to compare this with.</param>
777 /// <returns>0 if the argument is an <see cref="NpgsqlInterval"/> and the instances are equal or equivalent.
778 /// A value less than zero if the argument is an <see cref="NpgsqlInterval"/> and
779 /// this instance is less than the argument.
780 /// A value greater than zero if the argument is an <see cref="NpgsqlInterval"/> and this instance
781 /// is greater than the instance.</returns>
782 /// A value greater than zero if the argument is null.
783 /// <exception cref="ArgumentException">The argument is not an <see cref="NpgsqlInterval"/>.</exception>
784 public int CompareTo(object other
)
790 else if (other
is NpgsqlInterval
)
792 return CompareTo((NpgsqlInterval
) other
);
796 throw new ArgumentException();
802 #region To And From Strings
805 /// Parses a <see cref="String"/> and returns a <see cref="NpgsqlInterval"/> instance.
806 /// Designed to use the formats generally returned by PostgreSQL.
808 /// <param name="str">The <see cref="String"/> to parse.</param>
809 /// <returns>An <see cref="NpgsqlInterval"/> represented by the argument.</returns>
810 /// <exception cref="ArgumentNullException">The string was null.</exception>
811 /// <exception cref="OverflowException">A value obtained from parsing the string exceeded the values allowed for the relevant component.</exception>
812 /// <exception cref="FormatException">The string was not in a format that could be parsed to produce an <see cref="NpgsqlInterval"/>.</exception>
813 public static NpgsqlInterval
Parse(string str
)
817 throw new ArgumentNullException("str");
819 str
= str
.Replace('s', ' '); //Quick and easy way to catch plurals.
827 decimal seconds
= 0m
;
828 int idx
= str
.IndexOf("year");
831 years
= int.Parse(str
.Substring(0, idx
));
832 str
= str
.Substring(idx
+ 5);
834 idx
= str
.IndexOf("mon");
837 months
= int.Parse(str
.Substring(0, idx
));
838 str
= str
.Substring(idx
+ 4);
840 idx
= str
.IndexOf("day");
843 days
= int.Parse(str
.Substring(0, idx
));
844 str
= str
.Substring(idx
+ 4).Trim();
848 string[] parts
= str
.Split(':');
849 switch (parts
.Length
) //One of those times that fall-through would actually be good.
852 hours
= int.Parse(parts
[0]);
855 hours
= int.Parse(parts
[0]);
856 minutes
= int.Parse(parts
[1]);
859 hours
= int.Parse(parts
[0]);
860 minutes
= int.Parse(parts
[1]);
861 seconds
= decimal.Parse(parts
[2]);
865 long ticks
= hours
*TicksPerHour
+ minutes
*TicksPerMinute
+ (long) (seconds
*TicksPerSecond
);
866 return new NpgsqlInterval(years
*MonthsPerYear
+ months
, days
, ticks
);
868 catch (OverflowException
)
874 throw new FormatException();
879 /// Attempt to parse a <see cref="String"/> to produce an <see cref="NpgsqlInterval"/>.
881 /// <param name="str">The <see cref="String"/> to parse.</param>
882 /// <param name="result">(out) The <see cref="NpgsqlInterval"/> produced, or <see cref="Zero"/> if the parsing failed.</param>
883 /// <returns>true if the parsing succeeded, false otherwise.</returns>
884 public static bool TryParse(string str
, out NpgsqlInterval result
)
899 /// Create a <see cref="String"/> representation of the <see cref="NpgsqlInterval"/> instance.
900 /// The format returned is of the form:
901 /// [M mon[s]] [d day[s]] [HH:mm:ss[.f[f[f[f[f[f[f[f[f]]]]]]]]]]
902 /// A zero <see cref="NpgsqlInterval"/> is represented as 00:00:00
904 /// Ticks are 100ns, Postgress resolution is only to 1µs at most. Hence we lose 1 or more decimal
905 /// precision in storing values in the database. Despite this, this method will output that extra
906 /// digit of precision. It's forward-compatible with any future increases in resolution up to 100ns,
907 /// and also makes this ToString() more applicable to any other use-case.
910 /// <returns>The <see cref="String"/> representation.</returns>
911 public override string ToString()
913 StringBuilder sb
= new StringBuilder();
916 sb
.Append(Months
).Append(Math
.Abs(Months
) == 1 ? " mon " : " mons ");
920 if (Months
< 0 && Days
> 0)
924 sb
.Append(Days
).Append(Math
.Abs(Days
) == 1 ? " day " : " days ");
926 if (Ticks
!= 0 || sb
.Length
== 0)
928 if (Days
< 0 || (Days
== 0 && Months
< 0))
932 TimeSpan time
= Time
;
933 sb
.Append(time
.Hours
.ToString("D2")).Append(':').Append(time
.Minutes
.ToString("D2")).Append(':').Append(
934 time
.Seconds
.ToString("D2"));
935 long remainingTicks
= Math
.Abs(Ticks
)%TicksPerSecond
;
936 if (remainingTicks
!= 0)
938 while (remainingTicks
%10 == 0)
940 remainingTicks
/= 10;
942 sb
.Append('.').Append(remainingTicks
);
945 if (sb
[sb
.Length
- 1] == ' ')
947 sb
.Remove(sb
.Length
- 1, 1);
949 return sb
.ToString();
954 #region Common Operators
957 /// Adds two <see cref="NpgsqlInterval"/> together.
959 /// <param name="x">The first <see cref="NpgsqlInterval"/> to add.</param>
960 /// <param name="y">The second <see cref="NpgsqlInterval"/> to add.</param>
961 /// <returns>An <see cref="NpgsqlInterval"/> whose values are the sum of the arguments.</returns>
962 public static NpgsqlInterval
operator +(NpgsqlInterval x
, NpgsqlInterval y
)
968 /// Subtracts one <see cref="NpgsqlInterval"/> from another.
970 /// <param name="x">The <see cref="NpgsqlInterval"/> to subtract the other from.</param>
971 /// <param name="y">The <see cref="NpgsqlInterval"/> to subtract from the other.</param>
972 /// <returns>An <see cref="NpgsqlInterval"/> whose values are the difference of the arguments</returns>
973 public static NpgsqlInterval
operator -(NpgsqlInterval x
, NpgsqlInterval y
)
975 return x
.Subtract(y
);
979 /// Returns true if two <see cref="NpgsqlInterval"/> are exactly the same.
981 /// <param name="x">The first <see cref="NpgsqlInterval"/> to compare.</param>
982 /// <param name="y">The second <see cref="NpgsqlInterval"/> to compare.</param>
983 /// <returns>true if the two arguments are exactly the same, false otherwise.</returns>
984 public static bool operator ==(NpgsqlInterval x
, NpgsqlInterval y
)
990 /// Returns false if two <see cref="NpgsqlInterval"/> are exactly the same.
992 /// <param name="x">The first <see cref="NpgsqlInterval"/> to compare.</param>
993 /// <param name="y">The second <see cref="NpgsqlInterval"/> to compare.</param>
994 /// <returns>false if the two arguments are exactly the same, true otherwise.</returns>
995 public static bool operator !=(NpgsqlInterval x
, NpgsqlInterval y
)
1001 /// Compares two <see cref="NpgsqlInterval"/> instances to see if the first is less than the second
1003 /// <param name="x">The first <see cref="NpgsqlInterval"/> to compare.</param>
1004 /// <param name="y">The second <see cref="NpgsqlInterval"/> to compare.</param>
1005 /// <returns>true if the first <see cref="NpgsqlInterval"/> is less than second, false otherwise.</returns>
1006 public static bool operator <(NpgsqlInterval x
, NpgsqlInterval y
)
1008 return x
.UnjustifyInterval().Ticks
< y
.UnjustifyInterval().Ticks
;
1012 /// Compares two <see cref="NpgsqlInterval"/> instances to see if the first is less than or equivalent to the second
1014 /// <param name="x">The first <see cref="NpgsqlInterval"/> to compare.</param>
1015 /// <param name="y">The second <see cref="NpgsqlInterval"/> to compare.</param>
1016 /// <returns>true if the first <see cref="NpgsqlInterval"/> is less than or equivalent to second, false otherwise.</returns>
1017 public static bool operator <=(NpgsqlInterval x
, NpgsqlInterval y
)
1019 return x
.UnjustifyInterval().Ticks
<= y
.UnjustifyInterval().Ticks
;
1023 /// Compares two <see cref="NpgsqlInterval"/> instances to see if the first is greater than the second
1025 /// <param name="x">The first <see cref="NpgsqlInterval"/> to compare.</param>
1026 /// <param name="y">The second <see cref="NpgsqlInterval"/> to compare.</param>
1027 /// <returns>true if the first <see cref="NpgsqlInterval"/> is greater than second, false otherwise.</returns>
1028 public static bool operator >(NpgsqlInterval x
, NpgsqlInterval y
)
1034 /// Compares two <see cref="NpgsqlInterval"/> instances to see if the first is greater than or equivalent the second
1036 /// <param name="x">The first <see cref="NpgsqlInterval"/> to compare.</param>
1037 /// <param name="y">The second <see cref="NpgsqlInterval"/> to compare.</param>
1038 /// <returns>true if the first <see cref="NpgsqlInterval"/> is greater than or equivalent to the second, false otherwise.</returns>
1039 public static bool operator >=(NpgsqlInterval x
, NpgsqlInterval y
)
1045 /// Returns the instance.
1047 /// <param name="x">An <see cref="NpgsqlInterval"/>.</param>
1048 /// <returns>The argument.</returns>
1049 public static NpgsqlInterval
operator +(NpgsqlInterval x
)
1055 /// Negates an <see cref="NpgsqlInterval"/> instance.
1057 /// <param name="x">An <see cref="NpgsqlInterval"/>.</param>
1058 /// <returns>The negation of the argument.</returns>
1059 public static NpgsqlInterval
operator -(NpgsqlInterval x
)
1068 public struct NpgsqlDate
: IEquatable
<NpgsqlDate
>, IComparable
<NpgsqlDate
>, IComparable
, IComparer
<NpgsqlDate
>,
1071 private static readonly int[] CommonYearDays
= new int[] {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}
;
1072 private static readonly int[] LeapYearDays
= new int[] {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
;
1073 private static readonly int[] CommonYearMaxes
= new int[] {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
;
1074 private static readonly int[] LeapYearMaxes
= new int[] {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
;
1075 public const int MaxYear
= 5874897;
1076 public const int MinYear
= -4714;
1077 public static readonly NpgsqlDate Epoch
= new NpgsqlDate(1970, 1, 1);
1078 public static readonly NpgsqlDate MaxCalculableValue
= new NpgsqlDate(MaxYear
, 12, 31);
1079 public static readonly NpgsqlDate MinCalculableValue
= new NpgsqlDate(MinYear
, 11, 24);
1080 public static readonly NpgsqlDate Era
= new NpgsqlDate(0);
1082 public static NpgsqlDate Now
1084 get { return new NpgsqlDate(DateTime.Now); }
1087 public static NpgsqlDate Today
1092 public static NpgsqlDate Yesterday
1094 get { return Now.AddDays(-1); }
1097 public static NpgsqlDate Tomorrow
1099 get { return Now.AddDays(1); }
1102 public static NpgsqlDate
Parse(string str
)
1106 throw new ArgumentNullException("str");
1111 int idx
= str
.IndexOf('-');
1114 throw new FormatException();
1116 int year
= int.Parse(str
.Substring(0, idx
));
1117 int idxLast
= idx
+ 1;
1118 if ((idx
= str
.IndexOf('-', idxLast
)) == -1)
1120 throw new FormatException();
1122 int month
= int.Parse(str
.Substring(idxLast
, idx
- idxLast
));
1124 if ((idx
= str
.IndexOf(' ', idxLast
)) == -1)
1128 int day
= int.Parse(str
.Substring(idxLast
, idx
- idxLast
));
1129 if (str
.Contains("BC"))
1133 return new NpgsqlDate(year
, month
, day
);
1135 catch (OverflowException
)
1141 throw new FormatException();
1145 public static bool TryParse(string str
, out NpgsqlDate date
)
1159 //Number of days since January 1st CE (January 1st EV). 1 Jan 1 CE = 0, 2 Jan 1 CE = 1, 31 Dec 1 BCE = -1, etc.
1160 private readonly int _daysSinceEra
;
1162 public NpgsqlDate(int days
)
1164 _daysSinceEra
= days
;
1167 public NpgsqlDate(DateTime dateTime
)
1168 : this((int) (dateTime
.Ticks
/TimeSpan
.TicksPerDay
))
1172 public NpgsqlDate(NpgsqlDate copyFrom
)
1173 : this(copyFrom
._daysSinceEra
)
1177 public NpgsqlDate(int year
, int month
, int day
)
1179 if (year
== 0 || year
< MinYear
|| year
> MaxYear
|| month
< 1 || month
> 12 || day
< 1 ||
1180 (day
> (IsLeap(year
) ? 366 : 365)))
1182 throw new ArgumentOutOfRangeException();
1185 _daysSinceEra
= DaysForYears(year
) + (IsLeap(year
) ? LeapYearDays
: CommonYearDays
)[month
- 1] + day
- 1;
1188 private const int DaysInYear
= 365; //Common years
1189 private const int DaysIn4Years
= 4*DaysInYear
+ 1; //Leap year every 4 years.
1190 private const int DaysInCentury
= 25*DaysIn4Years
- 1; //Except no leap year every 100.
1191 private const int DaysIn4Centuries
= 4*DaysInCentury
+ 1; //Except leap year every 400.
1193 private static int DaysForYears(int years
)
1195 //Number of years after 1CE (0 for 1CE, -1 for 1BCE, 1 for 2CE).
1196 int calcYear
= years
< 1 ? years
: years
- 1;
1198 return calcYear
/400*DaysIn4Centuries
//Blocks of 400 years with their leap and common years
1199 + calcYear
%400/100*DaysInCentury
//Remaining blocks of 100 years with their leap and common years
1200 + calcYear
%100/4*DaysIn4Years
//Remaining blocks of 4 years with their leap and common years
1201 + calcYear
%4*DaysInYear
//Remaining years, all common
1202 + (calcYear
< 0 ? -1 : 0); //And 1BCE is leap.
1205 public int DayOfYear
1207 get { return _daysSinceEra - DaysForYears(Year) + 1; }
1214 int guess
= (int) Math
.Round(_daysSinceEra
/365.2425);
1215 int test
= guess
- 1;
1216 while (DaysForYears(++test
) <= _daysSinceEra
)
1229 int target
= DayOfYear
;
1230 int[] array
= IsLeapYear
? LeapYearDays
: CommonYearDays
;
1231 while (target
> array
[i
])
1241 get { return DayOfYear - (IsLeapYear ? LeapYearDays : CommonYearDays)[Month - 1]; }
1244 public DayOfWeek DayOfWeek
1246 get { return (DayOfWeek) ((_daysSinceEra + 1)%7); }
1249 internal int DaysSinceEra
1251 get { return _daysSinceEra; }
1254 public bool IsLeapYear
1256 get { return IsLeap(Year); }
1259 private static bool IsLeap(int year
)
1261 //Every 4 years is a leap year
1262 //Except every 100 years isn't a leap year.
1263 //Except every 400 years is.
1268 return (year
%4 == 0) && ((year
%100 != 0) || (year
%400 == 0));
1271 public NpgsqlDate
AddDays(int days
)
1273 return new NpgsqlDate(_daysSinceEra
+ days
);
1276 public NpgsqlDate
AddYears(int years
)
1278 int newYear
= Year
+ years
;
1279 if (newYear
>= 0 && _daysSinceEra
< 0) //cross 1CE/1BCE divide going up
1283 else if (newYear
<= 0 && _daysSinceEra
>= 0) //cross 1CE/1BCE divide going down
1287 return new NpgsqlDate(newYear
, Month
, Day
);
1290 public NpgsqlDate
AddMonths(int months
)
1292 int newMonthOffset
= Month
- 1 + months
;
1293 int newYear
= Year
+ newMonthOffset
/12;
1294 int maxDay
= (IsLeap(newYear
) ? LeapYearMaxes
: CommonYearMaxes
)[newMonthOffset
];
1295 int newDay
= Day
> maxDay
? maxDay
: Day
;
1296 return new NpgsqlDate(newYear
, newMonthOffset
+ 1, newDay
);
1299 public NpgsqlDate
Add(NpgsqlInterval interval
)
1301 return AddMonths(interval
.Months
).AddDays(interval
.Days
);
1304 internal NpgsqlDate
Add(NpgsqlInterval interval
, int carriedOverflow
)
1306 return AddMonths(interval
.Months
).AddDays(interval
.Days
+ carriedOverflow
);
1309 public int Compare(NpgsqlDate x
, NpgsqlDate y
)
1311 return x
.CompareTo(y
);
1314 public int Compare(object x
, object y
)
1318 return y
== null ? 0 : -1;
1324 if (!(x
is IComparable
) || !(y
is IComparable
))
1326 throw new ArgumentException();
1328 return ((IComparable
) x
).CompareTo(y
);
1331 public bool Equals(NpgsqlDate other
)
1333 return _daysSinceEra
== other
._daysSinceEra
;
1336 public override bool Equals(object obj
)
1338 return obj
!= null && obj
is NpgsqlDate
&& Equals((NpgsqlDate
) obj
);
1341 public int CompareTo(NpgsqlDate other
)
1343 return _daysSinceEra
.CompareTo(other
._daysSinceEra
);
1346 public int CompareTo(object obj
)
1352 if (obj
is NpgsqlDate
)
1354 return CompareTo((NpgsqlDate
) obj
);
1356 throw new ArgumentException();
1359 public override int GetHashCode()
1361 return _daysSinceEra
;
1364 public override string ToString()
1366 //Format of yyyy-MM-dd with " BC" for BCE and optional " AD" for CE which we omit here.
1368 new StringBuilder(Math
.Abs(Year
).ToString("D4")).Append('-').Append(Month
.ToString("D2")).Append('-').Append(
1369 Day
.ToString("D2")).Append(_daysSinceEra
< 0 ? " BC" : "").ToString();
1372 public static bool operator ==(NpgsqlDate x
, NpgsqlDate y
)
1377 public static bool operator !=(NpgsqlDate x
, NpgsqlDate y
)
1382 public static bool operator <(NpgsqlDate x
, NpgsqlDate y
)
1384 return x
._daysSinceEra
< y
._daysSinceEra
;
1387 public static bool operator >(NpgsqlDate x
, NpgsqlDate y
)
1389 return x
._daysSinceEra
> y
._daysSinceEra
;
1392 public static bool operator <=(NpgsqlDate x
, NpgsqlDate y
)
1394 return x
._daysSinceEra
<= y
._daysSinceEra
;
1397 public static bool operator >=(NpgsqlDate x
, NpgsqlDate y
)
1399 return x
._daysSinceEra
>= y
._daysSinceEra
;
1402 public static explicit operator DateTime(NpgsqlDate date
)
1406 return new DateTime(date
._daysSinceEra
*NpgsqlInterval
.TicksPerDay
);
1410 throw new InvalidCastException();
1414 public static explicit operator NpgsqlDate(DateTime date
)
1416 return new NpgsqlDate((int) (date
.Ticks
/NpgsqlInterval
.TicksPerDay
));
1419 public static NpgsqlDate
operator +(NpgsqlDate date
, NpgsqlInterval interval
)
1421 return date
.Add(interval
);
1424 public static NpgsqlDate
operator +(NpgsqlInterval interval
, NpgsqlDate date
)
1426 return date
.Add(interval
);
1429 public static NpgsqlDate
operator -(NpgsqlDate date
, NpgsqlInterval interval
)
1431 return date
.Add(-interval
);
1434 public static NpgsqlInterval
operator -(NpgsqlDate dateX
, NpgsqlDate dateY
)
1436 return new NpgsqlInterval(0, dateX
._daysSinceEra
- dateY
._daysSinceEra
, 0);
1441 public struct NpgsqlTimeZone
: IEquatable
<NpgsqlTimeZone
>, IComparable
<NpgsqlTimeZone
>, IComparable
1443 public static NpgsqlTimeZone UTC
= new NpgsqlTimeZone(0);
1444 private readonly int _totalSeconds
;
1446 public NpgsqlTimeZone(TimeSpan ts
)
1451 private NpgsqlTimeZone(long ticks
)
1453 _totalSeconds
= (int) (ticks
/NpgsqlInterval
.TicksPerSecond
);
1456 public NpgsqlTimeZone(NpgsqlInterval ni
)
1461 public NpgsqlTimeZone(NpgsqlTimeZone copyFrom
)
1463 _totalSeconds
= copyFrom
._totalSeconds
;
1466 public NpgsqlTimeZone(int hours
, int minutes
)
1467 : this(hours
, minutes
, 0)
1471 public NpgsqlTimeZone(int hours
, int minutes
, int seconds
)
1473 _totalSeconds
= hours
*60*60 + minutes
*60 + seconds
;
1476 public static implicit operator NpgsqlTimeZone(NpgsqlInterval interval
)
1478 return new NpgsqlTimeZone(interval
);
1481 public static implicit operator NpgsqlInterval(NpgsqlTimeZone timeZone
)
1483 return new NpgsqlInterval(timeZone
._totalSeconds
*NpgsqlInterval
.TicksPerSecond
);
1486 public static implicit operator NpgsqlTimeZone(TimeSpan interval
)
1488 return new NpgsqlTimeZone(interval
);
1491 public static implicit operator TimeSpan(NpgsqlTimeZone timeZone
)
1493 return new TimeSpan(timeZone
._totalSeconds
*NpgsqlInterval
.TicksPerSecond
);
1496 public static NpgsqlTimeZone
SolarTimeZone(decimal longitude
)
1498 return new NpgsqlTimeZone((long) (longitude
/15m
*NpgsqlInterval
.TicksPerHour
));
1503 get { return _totalSeconds/60/60; }
1508 get { return (_totalSeconds/60)%60; }
1513 get { return _totalSeconds%60; }
1516 public static NpgsqlTimeZone CurrentTimeZone
1518 get { return new NpgsqlTimeZone(TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now)); }
1521 public static NpgsqlTimeZone
LocalTimeZone(NpgsqlDate date
)
1524 if (date
.Year
>= 1902 && date
.Year
<= 2038)
1526 dt
= (DateTime
) date
;
1530 dt
= new DateTime(2000, date
.Month
, date
.Day
);
1532 return new NpgsqlTimeZone(TimeZone
.CurrentTimeZone
.GetUtcOffset(dt
));
1535 public bool Equals(NpgsqlTimeZone other
)
1537 return _totalSeconds
== other
._totalSeconds
;
1540 public override bool Equals(object obj
)
1542 return obj
!= null && obj
is NpgsqlTimeZone
&& Equals((NpgsqlTimeZone
) obj
);
1545 public override string ToString()
1547 StringBuilder sb
= new StringBuilder(_totalSeconds
< 0 ? "-" : "+").Append(Math
.Abs(Hours
).ToString("D2"));
1548 if (Minutes
!= 0 || Seconds
!= 0)
1550 sb
.Append(':').Append(Math
.Abs(Minutes
).ToString("D2"));
1553 sb
.Append(":").Append(Math
.Abs(Seconds
).ToString("D2"));
1556 return sb
.ToString();
1559 public static NpgsqlTimeZone
Parse(string str
)
1563 throw new ArgumentNullException();
1578 throw new FormatException();
1583 string[] parts
= str
.Substring(1).Split(':');
1584 switch (parts
.Length
) //One of those times that fall-through would actually be good.
1587 hours
= int.Parse(parts
[0]);
1588 minutes
= seconds
= 0;
1591 hours
= int.Parse(parts
[0]);
1592 minutes
= int.Parse(parts
[1]);
1596 hours
= int.Parse(parts
[0]);
1597 minutes
= int.Parse(parts
[1]);
1598 seconds
= int.Parse(parts
[2]);
1601 int totalSeconds
= hours
*60*60 + minutes
*60 + seconds
*(neg
? -1 : 1);
1602 return new NpgsqlTimeZone(totalSeconds
*NpgsqlInterval
.TicksPerSecond
);
1604 catch (OverflowException
)
1610 throw new FormatException();
1614 public static bool TryParse(string str
, NpgsqlTimeZone tz
)
1628 public override int GetHashCode()
1630 return _totalSeconds
;
1633 //Note, +01:00 is less than -01:00
1634 public int CompareTo(NpgsqlTimeZone other
)
1636 return -(_totalSeconds
.CompareTo(other
._totalSeconds
));
1639 public int CompareTo(object obj
)
1645 if (obj
is NpgsqlTimeZone
)
1647 return CompareTo((NpgsqlTimeZone
) obj
);
1649 throw new ArgumentException();
1652 public static NpgsqlTimeZone
operator -(NpgsqlTimeZone tz
)
1654 return new NpgsqlTimeZone(-tz
._totalSeconds
);
1657 public static NpgsqlTimeZone
operator +(NpgsqlTimeZone tz
)
1662 public static bool operator ==(NpgsqlTimeZone x
, NpgsqlTimeZone y
)
1667 public static bool operator !=(NpgsqlTimeZone x
, NpgsqlTimeZone y
)
1672 public static bool operator <(NpgsqlTimeZone x
, NpgsqlTimeZone y
)
1674 return x
.CompareTo(y
) < 0;
1677 public static bool operator <=(NpgsqlTimeZone x
, NpgsqlTimeZone y
)
1679 return x
.CompareTo(y
) <= 0;
1682 public static bool operator >(NpgsqlTimeZone x
, NpgsqlTimeZone y
)
1684 return x
.CompareTo(y
) > 0;
1687 public static bool operator >=(NpgsqlTimeZone x
, NpgsqlTimeZone y
)
1689 return x
.CompareTo(y
) >= 0;
1694 public struct NpgsqlTime
: IEquatable
<NpgsqlTime
>, IComparable
<NpgsqlTime
>, IComparable
, IComparer
<NpgsqlTime
>,
1697 public static readonly NpgsqlTime AllBalls
= new NpgsqlTime(0);
1699 public static NpgsqlTime Now
1701 get { return new NpgsqlTime(DateTime.Now.TimeOfDay); }
1704 private readonly long _ticks
;
1706 public NpgsqlTime(long ticks
)
1708 if (ticks
== NpgsqlInterval
.TicksPerDay
)
1714 ticks
%= NpgsqlInterval
.TicksPerDay
;
1715 _ticks
= ticks
< 0 ? ticks
+ NpgsqlInterval
.TicksPerDay
: ticks
;
1719 public NpgsqlTime(TimeSpan time
)
1724 public NpgsqlTime(NpgsqlInterval time
)
1729 public NpgsqlTime(NpgsqlTime copyFrom
)
1730 : this(copyFrom
.Ticks
)
1734 public NpgsqlTime(int hours
, int minutes
, int seconds
)
1735 : this(hours
, minutes
, seconds
, 0)
1739 public NpgsqlTime(int hours
, int minutes
, int seconds
, int microseconds
)
1741 hours
*NpgsqlInterval
.TicksPerHour
+ minutes
*NpgsqlInterval
.TicksPerMinute
+ seconds
*NpgsqlInterval
.TicksPerSecond
+
1742 microseconds
*NpgsqlInterval
.TicksPerMicrosecond
)
1746 public NpgsqlTime(int hours
, int minutes
, decimal seconds
)
1748 hours
*NpgsqlInterval
.TicksPerHour
+ minutes
*NpgsqlInterval
.TicksPerMinute
+
1749 (long) (seconds
*NpgsqlInterval
.TicksPerSecond
))
1753 public NpgsqlTime(int hours
, int minutes
, double seconds
)
1754 : this(hours
, minutes
, (decimal) seconds
)
1759 /// The total number of ticks(100ns units) contained. This is the resolution of the
1760 /// <see cref="NpgsqlTime"/> type.
1761 /// <remarks>The resolution of the PostgreSQL
1762 /// interval type is by default 1µs = 1,000 ns. It may be smaller as follows:
1763 /// <list type="number">
1765 /// <term>time(0)</term>
1766 /// <description>resolution of 1s (1 second)</description>
1769 /// <term>time(1)</term>
1770 /// <description>resolution of 100ms = 0.1s (100 milliseconds)</description>
1773 /// <term>time(2)</term>
1774 /// <description>resolution of 10ms = 0.01s (10 milliseconds)</description>
1777 /// <term>time(3)</term>
1778 /// <description>resolution of 1ms = 0.001s (1 millisecond)</description>
1781 /// <term>time(4)</term>
1782 /// <description>resolution of 100µs = 0.0001s (100 microseconds)</description>
1785 /// <term>time(5)</term>
1786 /// <description>resolution of 10µs = 0.00001s (10 microseconds)</description>
1789 /// <term>time(6) or interval</term>
1790 /// <description>resolution of 1µs = 0.000001s (1 microsecond)</description>
1793 /// <para>As such, if the 100-nanosecond resolution is significant to an application, a PostgreSQL time will
1794 /// not suffice for those purposes.</para>
1795 /// <para>In more frequent cases though, the resolution of time suffices.
1796 /// <see cref="NpgsqlTime"/> will always suffice to handle the resolution of any time value, and upon
1797 /// writing to the database, will be rounded to the resolution used.</para>
1799 /// <returns>The number of ticks in the instance.</returns>
1803 get { return _ticks; }
1807 /// Gets the number of whole microseconds held in the instance.
1808 /// <returns>An integer in the range [0, 999999].</returns>
1810 public int Microseconds
1812 get { return (int) (_ticks/10)%1000000; }
1816 /// Gets the number of whole milliseconds held in the instance.
1817 /// <returns>An integer in the range [0, 999].</returns>
1819 public int Milliseconds
1821 get { return (int) ((_ticks/NpgsqlInterval.TicksPerMillsecond)%1000); }
1825 /// Gets the number of whole seconds held in the instance.
1826 /// <returns>An interger in the range [0, 59].</returns>
1830 get { return (int) ((_ticks/NpgsqlInterval.TicksPerSecond)%60); }
1834 /// Gets the number of whole minutes held in the instance.
1835 /// <returns>An integer in the range [0, 59].</returns>
1839 get { return (int) ((_ticks/NpgsqlInterval.TicksPerMinute)%60); }
1843 /// Gets the number of whole hours held in the instance.
1844 /// <remarks>Note that the time 24:00:00 can be stored for roundtrip compatibility. Any calculations on such a
1845 /// value will normalised it to 00:00:00.</remarks>
1849 get { return (int) (_ticks/NpgsqlInterval.TicksPerHour); }
1853 /// Normalise this time; if it is 24:00:00, convert it to 00:00:00
1855 /// <returns>This time, normalised</returns>
1856 public NpgsqlTime
Normalize()
1858 return new NpgsqlTime(_ticks
%NpgsqlInterval
.TicksPerDay
);
1861 public bool Equals(NpgsqlTime other
)
1863 return Ticks
== other
.Ticks
;
1866 public override bool Equals(object obj
)
1868 return obj
!= null && obj
is NpgsqlTime
&& Equals((NpgsqlTime
) obj
);
1871 public override int GetHashCode()
1873 return Ticks
.GetHashCode();
1876 public override string ToString()
1879 new StringBuilder(Hours
.ToString("D2")).Append(':').Append(Minutes
.ToString("D2")).Append(':').Append(
1880 Seconds
.ToString("D2"));
1881 long remainingTicks
= Math
.Abs(Ticks
)%NpgsqlInterval
.TicksPerSecond
;
1882 if (remainingTicks
!= 0)
1884 while (remainingTicks
%10 == 0)
1886 remainingTicks
/= 10;
1888 sb
.Append('.').Append(remainingTicks
);
1890 return sb
.ToString();
1893 public static NpgsqlTime
Parse(string str
)
1897 throw new ArgumentNullException();
1903 decimal seconds
= 0m
;
1904 string[] parts
= str
.Split(':');
1905 switch (parts
.Length
) //One of those times that fall-through would actually be good.
1908 hours
= int.Parse(parts
[0]);
1911 hours
= int.Parse(parts
[0]);
1912 minutes
= int.Parse(parts
[1]);
1915 hours
= int.Parse(parts
[0]);
1916 minutes
= int.Parse(parts
[1]);
1917 seconds
= decimal.Parse(parts
[2]);
1920 if (hours
< 0 || hours
> 24 || minutes
< 0 || minutes
> 59 || seconds
< 0m
|| seconds
>= 60 ||
1921 (hours
== 24 && (minutes
!= 0 || seconds
!= 0m
)))
1923 throw new OverflowException();
1925 return new NpgsqlTime(hours
, minutes
, seconds
);
1927 catch (OverflowException
)
1933 throw new FormatException();
1937 public static bool TryParse(string str
, out NpgsqlTime time
)
1951 public int CompareTo(NpgsqlTime other
)
1953 return Ticks
.CompareTo(other
.Ticks
);
1956 public int CompareTo(object obj
)
1962 if (obj
is NpgsqlTime
)
1964 return CompareTo((NpgsqlTime
) obj
);
1966 throw new ArgumentException();
1969 public int Compare(NpgsqlTime x
, NpgsqlTime y
)
1971 return x
.CompareTo(y
);
1974 public int Compare(object x
, object y
)
1978 return y
== null ? 0 : -1;
1984 if (!(x
is IComparable
) || !(y
is IComparable
))
1986 throw new ArgumentException();
1988 return ((IComparable
) x
).CompareTo(y
);
1991 public static bool operator ==(NpgsqlTime x
, NpgsqlTime y
)
1996 public static bool operator !=(NpgsqlTime x
, NpgsqlTime y
)
2001 public static bool operator <(NpgsqlTime x
, NpgsqlTime y
)
2003 return x
.Ticks
< y
.Ticks
;
2006 public static bool operator >(NpgsqlTime x
, NpgsqlTime y
)
2008 return x
.Ticks
> y
.Ticks
;
2011 public static bool operator <=(NpgsqlTime x
, NpgsqlTime y
)
2013 return x
.Ticks
<= y
.Ticks
;
2016 public static bool operator >=(NpgsqlTime x
, NpgsqlTime y
)
2018 return x
.Ticks
>= y
.Ticks
;
2021 public static explicit operator NpgsqlInterval(NpgsqlTime time
)
2023 return new NpgsqlInterval(time
.Ticks
);
2026 public static explicit operator NpgsqlTime(NpgsqlInterval interval
)
2028 return new NpgsqlTime(interval
);
2031 public static explicit operator TimeSpan(NpgsqlTime time
)
2033 return new TimeSpan(time
.Ticks
);
2036 public static explicit operator NpgsqlTime(TimeSpan interval
)
2038 return new NpgsqlTime(interval
);
2041 public NpgsqlTime
AddTicks(long ticksAdded
)
2043 return new NpgsqlTime((Ticks
+ ticksAdded
)%NpgsqlInterval
.TicksPerDay
);
2046 private NpgsqlTime
AddTicks(long ticksAdded
, out int overflow
)
2048 long result
= Ticks
+ ticksAdded
;
2049 overflow
= (int) (result
/NpgsqlInterval
.TicksPerDay
);
2050 result
%= NpgsqlInterval
.TicksPerDay
;
2053 --overflow
; //"carry the one"
2055 return new NpgsqlTime(result
);
2058 public NpgsqlTime
Add(NpgsqlInterval interval
)
2060 return AddTicks(interval
.Ticks
);
2063 internal NpgsqlTime
Add(NpgsqlInterval interval
, out int overflow
)
2065 return AddTicks(interval
.Ticks
, out overflow
);
2068 public NpgsqlTime
Subtract(NpgsqlInterval interval
)
2070 return AddTicks(-interval
.Ticks
);
2073 public NpgsqlInterval
Subtract(NpgsqlTime earlier
)
2075 return new NpgsqlInterval(Ticks
- earlier
.Ticks
);
2078 public NpgsqlTimeTZ
AtTimeZone(NpgsqlTimeZone timeZone
)
2080 return new NpgsqlTimeTZ(this).AtTimeZone(timeZone
);
2083 public static NpgsqlTime
operator +(NpgsqlTime time
, NpgsqlInterval interval
)
2085 return time
.Add(interval
);
2088 public static NpgsqlTime
operator +(NpgsqlInterval interval
, NpgsqlTime time
)
2090 return time
+ interval
;
2093 public static NpgsqlTime
operator -(NpgsqlTime time
, NpgsqlInterval interval
)
2095 return time
.Subtract(interval
);
2098 public static NpgsqlInterval
operator -(NpgsqlTime later
, NpgsqlTime earlier
)
2100 return later
.Subtract(earlier
);
2105 public struct NpgsqlTimeTZ
: IEquatable
<NpgsqlTimeTZ
>, IComparable
<NpgsqlTimeTZ
>, IComparable
, IComparer
<NpgsqlTimeTZ
>,
2108 public static readonly NpgsqlTimeTZ AllBalls
= new NpgsqlTimeTZ(NpgsqlTime
.AllBalls
, NpgsqlTimeZone
.UTC
);
2110 public static NpgsqlTimeTZ Now
2112 get { return new NpgsqlTimeTZ(NpgsqlTime.Now); }
2115 public static NpgsqlTimeTZ
LocalMidnight(NpgsqlDate date
)
2117 return new NpgsqlTimeTZ(NpgsqlTime
.AllBalls
, NpgsqlTimeZone
.LocalTimeZone(date
));
2120 private readonly NpgsqlTime _localTime
;
2121 private readonly NpgsqlTimeZone _timeZone
;
2123 public NpgsqlTimeTZ(NpgsqlTime localTime
, NpgsqlTimeZone timeZone
)
2125 _localTime
= localTime
;
2126 _timeZone
= timeZone
;
2129 public NpgsqlTimeTZ(NpgsqlTime localTime
)
2130 : this(localTime
, NpgsqlTimeZone
.CurrentTimeZone
)
2134 public NpgsqlTimeTZ(long ticks
)
2135 : this(new NpgsqlTime(ticks
))
2139 public NpgsqlTimeTZ(TimeSpan time
)
2140 : this(new NpgsqlTime(time
))
2144 public NpgsqlTimeTZ(NpgsqlInterval time
)
2145 : this(new NpgsqlTime(time
))
2149 public NpgsqlTimeTZ(NpgsqlTimeTZ copyFrom
)
2150 : this(copyFrom
._localTime
, copyFrom
._timeZone
)
2154 public NpgsqlTimeTZ(int hours
, int minutes
, int seconds
)
2155 : this(new NpgsqlTime(hours
, minutes
, seconds
))
2159 public NpgsqlTimeTZ(int hours
, int minutes
, int seconds
, int microseconds
)
2160 : this(new NpgsqlTime(hours
, minutes
, seconds
, microseconds
))
2164 public NpgsqlTimeTZ(int hours
, int minutes
, decimal seconds
)
2165 : this(new NpgsqlTime(hours
, minutes
, seconds
))
2169 public NpgsqlTimeTZ(int hours
, int minutes
, double seconds
)
2170 : this(new NpgsqlTime(hours
, minutes
, seconds
))
2174 public NpgsqlTimeTZ(long ticks
, NpgsqlTimeZone timeZone
)
2175 : this(new NpgsqlTime(ticks
), timeZone
)
2179 public NpgsqlTimeTZ(TimeSpan time
, NpgsqlTimeZone timeZone
)
2180 : this(new NpgsqlTime(time
), timeZone
)
2184 public NpgsqlTimeTZ(NpgsqlInterval time
, NpgsqlTimeZone timeZone
)
2185 : this(new NpgsqlTime(time
), timeZone
)
2189 public NpgsqlTimeTZ(int hours
, int minutes
, int seconds
, NpgsqlTimeZone timeZone
)
2190 : this(new NpgsqlTime(hours
, minutes
, seconds
), timeZone
)
2194 public NpgsqlTimeTZ(int hours
, int minutes
, int seconds
, int microseconds
, NpgsqlTimeZone timeZone
)
2195 : this(new NpgsqlTime(hours
, minutes
, seconds
, microseconds
), timeZone
)
2199 public NpgsqlTimeTZ(int hours
, int minutes
, decimal seconds
, NpgsqlTimeZone timeZone
)
2200 : this(new NpgsqlTime(hours
, minutes
, seconds
), timeZone
)
2204 public NpgsqlTimeTZ(int hours
, int minutes
, double seconds
, NpgsqlTimeZone timeZone
)
2205 : this(new NpgsqlTime(hours
, minutes
, seconds
), timeZone
)
2209 public override string ToString()
2211 return string.Format("{0}{1}", _localTime
, _timeZone
);
2214 public static NpgsqlTimeTZ
Parse(string str
)
2218 throw new ArgumentNullException();
2222 int idx
= Math
.Max(str
.IndexOf('+'), str
.IndexOf('-'));
2225 throw new FormatException();
2227 return new NpgsqlTimeTZ(NpgsqlTime
.Parse(str
.Substring(0, idx
)), NpgsqlTimeZone
.Parse(str
.Substring(idx
)));
2229 catch (OverflowException
)
2235 throw new FormatException();
2239 public NpgsqlTime LocalTime
2241 get { return _localTime; }
2244 public NpgsqlTimeZone TimeZone
2246 get { return _timeZone; }
2249 public NpgsqlTime UTCTime
2251 get { return AtTimeZone(NpgsqlTimeZone.UTC).LocalTime; }
2254 public NpgsqlTimeTZ
AtTimeZone(NpgsqlTimeZone timeZone
)
2256 return new NpgsqlTimeTZ(LocalTime
- _timeZone
+ timeZone
, timeZone
);
2259 internal NpgsqlTimeTZ
AtTimeZone(NpgsqlTimeZone timeZone
, out int overflow
)
2262 new NpgsqlTimeTZ(LocalTime
.Add(timeZone
- (NpgsqlInterval
) (_timeZone
), out overflow
), timeZone
);
2267 get { return _localTime.Ticks; }
2271 /// Gets the number of whole microseconds held in the instance.
2272 /// <returns>An integer in the range [0, 999999].</returns>
2274 public int Microseconds
2276 get { return _localTime.Microseconds; }
2280 /// Gets the number of whole milliseconds held in the instance.
2281 /// <returns>An integer in the range [0, 999].</returns>
2283 public int Milliseconds
2285 get { return _localTime.Milliseconds; }
2289 /// Gets the number of whole seconds held in the instance.
2290 /// <returns>An interger in the range [0, 59].</returns>
2294 get { return _localTime.Seconds; }
2298 /// Gets the number of whole minutes held in the instance.
2299 /// <returns>An integer in the range [0, 59].</returns>
2303 get { return _localTime.Minutes; }
2307 /// Gets the number of whole hours held in the instance.
2308 /// <remarks>Note that the time 24:00:00 can be stored for roundtrip compatibility. Any calculations on such a
2309 /// value will normalised it to 00:00:00.</remarks>
2313 get { return _localTime.Hours; }
2317 /// Normalise this time; if it is 24:00:00, convert it to 00:00:00
2319 /// <returns>This time, normalised</returns>
2320 public NpgsqlTimeTZ
Normalize()
2322 return new NpgsqlTimeTZ(_localTime
.Normalize(), _timeZone
);
2325 public bool Equals(NpgsqlTimeTZ other
)
2327 return _localTime
.Equals(other
._localTime
) && _timeZone
.Equals(other
._timeZone
);
2330 public override bool Equals(object obj
)
2332 return obj
!= null && obj
is NpgsqlTimeTZ
&& Equals((NpgsqlTimeTZ
) obj
);
2335 public override int GetHashCode()
2337 return _localTime
.GetHashCode() ^ PGUtil
.RotateShift(_timeZone
.GetHashCode(), 24);
2341 /// Compares this with another <see cref="NpgsqlTimeTZ"/>. As per postgres' rules,
2342 /// first the times are compared as if they were both in the same timezone. If they are equal then
2343 /// then timezones are compared (+01:00 being "smaller" than -01:00).
2345 /// <param name="other">the <see cref="NpgsqlTimeTZ"/> to compare with.</param>
2346 /// <returns>An integer which is 0 if they are equal, < 0 if this is the smaller and > 0 if this is the larger.</returns>
2347 public int CompareTo(NpgsqlTimeTZ other
)
2349 int cmp
= AtTimeZone(NpgsqlTimeZone
.UTC
).LocalTime
.CompareTo(other
.AtTimeZone(NpgsqlTimeZone
.UTC
).LocalTime
);
2350 return cmp
== 0 ? _timeZone
.CompareTo(other
._timeZone
) : cmp
;
2353 public int CompareTo(object obj
)
2359 if (obj
is NpgsqlTimeTZ
)
2361 return CompareTo((NpgsqlTimeTZ
) obj
);
2363 throw new ArgumentException();
2366 public int Compare(NpgsqlTimeTZ x
, NpgsqlTimeTZ y
)
2368 return x
.CompareTo(y
);
2371 public int Compare(object x
, object y
)
2375 return y
== null ? 0 : -1;
2381 if (!(x
is IComparable
) || !(y
is IComparable
))
2383 throw new ArgumentException();
2385 return ((IComparable
) x
).CompareTo(y
);
2388 public static bool operator ==(NpgsqlTimeTZ x
, NpgsqlTimeTZ y
)
2393 public static bool operator !=(NpgsqlTimeTZ x
, NpgsqlTimeTZ y
)
2398 public static bool operator <(NpgsqlTimeTZ x
, NpgsqlTimeTZ y
)
2400 return x
.CompareTo(y
) < 0;
2403 public static bool operator >(NpgsqlTimeTZ x
, NpgsqlTimeTZ y
)
2405 return x
.CompareTo(y
) > 0;
2408 public static bool operator <=(NpgsqlTimeTZ x
, NpgsqlTimeTZ y
)
2410 return x
.CompareTo(y
) <= 0;
2413 public static bool operator >=(NpgsqlTimeTZ x
, NpgsqlTimeTZ y
)
2415 return x
.CompareTo(y
) >= 0;
2418 public NpgsqlTimeTZ
Add(NpgsqlInterval interval
)
2420 return new NpgsqlTimeTZ(_localTime
.Add(interval
), _timeZone
);
2423 internal NpgsqlTimeTZ
Add(NpgsqlInterval interval
, out int overflow
)
2425 return new NpgsqlTimeTZ(_localTime
.Add(interval
, out overflow
), _timeZone
);
2428 public NpgsqlTimeTZ
Subtract(NpgsqlInterval interval
)
2430 return new NpgsqlTimeTZ(_localTime
.Subtract(interval
), _timeZone
);
2433 public NpgsqlInterval
Subtract(NpgsqlTimeTZ earlier
)
2435 return _localTime
.Subtract(earlier
.AtTimeZone(_timeZone
)._localTime
);
2438 public static NpgsqlTimeTZ
operator +(NpgsqlTimeTZ time
, NpgsqlInterval interval
)
2440 return time
.Add(interval
);
2443 public static NpgsqlTimeTZ
operator +(NpgsqlInterval interval
, NpgsqlTimeTZ time
)
2445 return time
+ interval
;
2448 public static NpgsqlTimeTZ
operator -(NpgsqlTimeTZ time
, NpgsqlInterval interval
)
2450 return time
.Subtract(interval
);
2453 public static NpgsqlInterval
operator -(NpgsqlTimeTZ later
, NpgsqlTimeTZ earlier
)
2455 return later
.Subtract(earlier
);
2458 public static explicit operator NpgsqlTimeTZ(TimeSpan time
)
2460 return new NpgsqlTimeTZ(new NpgsqlTime(time
));
2463 public static explicit operator TimeSpan(NpgsqlTimeTZ time
)
2465 return (TimeSpan
) time
.LocalTime
;
2470 public struct NpgsqlTimeStamp
: IEquatable
<NpgsqlTimeStamp
>, IComparable
<NpgsqlTimeStamp
>, IComparable
,
2471 IComparer
<NpgsqlTimeStamp
>, IComparer
2473 private enum TimeType
2480 public static readonly NpgsqlTimeStamp Epoch
= new NpgsqlTimeStamp(NpgsqlDate
.Epoch
);
2481 public static readonly NpgsqlTimeStamp Era
= new NpgsqlTimeStamp(NpgsqlDate
.Era
);
2483 public static readonly NpgsqlTimeStamp Infinity
=
2484 new NpgsqlTimeStamp(TimeType
.Infinity
, NpgsqlDate
.Era
, NpgsqlTime
.AllBalls
);
2486 public static readonly NpgsqlTimeStamp MinusInfinity
=
2487 new NpgsqlTimeStamp(TimeType
.MinusInfinity
, NpgsqlDate
.Era
, NpgsqlTime
.AllBalls
);
2489 public static NpgsqlTimeStamp Now
2491 get { return new NpgsqlTimeStamp(NpgsqlDate.Now, NpgsqlTime.Now); }
2494 public static NpgsqlTimeStamp Today
2496 get { return new NpgsqlTimeStamp(NpgsqlDate.Now); }
2499 public static NpgsqlTimeStamp Yesterday
2501 get { return new NpgsqlTimeStamp(NpgsqlDate.Yesterday); }
2504 public static NpgsqlTimeStamp Tomorrow
2506 get { return new NpgsqlTimeStamp(NpgsqlDate.Tomorrow); }
2509 private readonly NpgsqlDate _date
;
2510 private readonly NpgsqlTime _time
;
2511 private readonly TimeType _type
;
2513 private NpgsqlTimeStamp(TimeType type
, NpgsqlDate date
, NpgsqlTime time
)
2520 public NpgsqlTimeStamp(NpgsqlDate date
, NpgsqlTime time
)
2521 : this(TimeType
.Finite
, date
, time
)
2525 public NpgsqlTimeStamp(NpgsqlDate date
)
2526 : this(date
, NpgsqlTime
.AllBalls
)
2530 public NpgsqlTimeStamp(int year
, int month
, int day
, int hours
, int minutes
, int seconds
)
2531 : this(new NpgsqlDate(year
, month
, day
), new NpgsqlTime(hours
, minutes
, seconds
))
2535 public NpgsqlDate Date
2537 get { return _date; }
2540 public NpgsqlTime Time
2542 get { return _time; }
2545 public int DayOfYear
2547 get { return _date.DayOfYear; }
2552 get { return _date.Year; }
2557 get { return _date.Month; }
2562 get { return _date.Day; }
2565 public DayOfWeek DayOfWeek
2567 get { return _date.DayOfWeek; }
2570 public bool IsLeapYear
2572 get { return _date.IsLeapYear; }
2575 public NpgsqlTimeStamp
AddDays(int days
)
2579 case TimeType
.Infinity
:
2580 case TimeType
.MinusInfinity
:
2583 return new NpgsqlTimeStamp(_date
.AddDays(days
), _time
);
2587 public NpgsqlTimeStamp
AddYears(int years
)
2591 case TimeType
.Infinity
:
2592 case TimeType
.MinusInfinity
:
2595 return new NpgsqlTimeStamp(_date
.AddYears(years
), _time
);
2599 public NpgsqlTimeStamp
AddMonths(int months
)
2603 case TimeType
.Infinity
:
2604 case TimeType
.MinusInfinity
:
2607 return new NpgsqlTimeStamp(_date
.AddMonths(months
), _time
);
2613 get { return _date.DaysSinceEra*NpgsqlInterval.TicksPerDay + _time.Ticks; }
2616 public int Microseconds
2618 get { return _time.Microseconds; }
2621 public int Milliseconds
2623 get { return _time.Milliseconds; }
2628 get { return _time.Seconds; }
2633 get { return _time.Minutes; }
2638 get { return _time.Hours; }
2641 public bool IsFinite
2643 get { return _type == TimeType.Finite; }
2646 public bool IsInfinity
2648 get { return _type == TimeType.Infinity; }
2651 public bool IsMinusInfinity
2653 get { return _type == TimeType.MinusInfinity; }
2656 public NpgsqlTimeStamp
Normalize()
2658 return Add(NpgsqlInterval
.Zero
);
2661 public override string ToString()
2665 case TimeType
.Infinity
:
2667 case TimeType
.MinusInfinity
:
2670 return string.Format("{0} {1}", _date
, _time
);
2674 public static NpgsqlTimeStamp
Parse(string str
)
2678 throw new NullReferenceException();
2680 switch (str
= str
.Trim().ToLowerInvariant())
2685 return MinusInfinity
;
2689 int idxSpace
= str
.IndexOf(' ');
2690 string datePart
= str
.Substring(0, idxSpace
);
2691 if (str
.Contains("bc"))
2695 int idxSecond
= str
.IndexOf(' ', idxSpace
+ 1);
2696 if (idxSecond
== -1)
2698 idxSecond
= str
.Length
;
2700 string timePart
= str
.Substring(idxSpace
+ 1, idxSecond
- idxSpace
- 1);
2701 return new NpgsqlTimeStamp(NpgsqlDate
.Parse(datePart
), NpgsqlTime
.Parse(timePart
));
2703 catch (OverflowException
)
2709 throw new FormatException();
2714 public bool Equals(NpgsqlTimeStamp other
)
2718 case TimeType
.Infinity
:
2719 return other
._type
== TimeType
.Infinity
;
2720 case TimeType
.MinusInfinity
:
2721 return other
._type
== TimeType
.MinusInfinity
;
2723 return other
._type
== TimeType
.Finite
&& _date
.Equals(other
._date
) && _time
.Equals(other
._time
);
2727 public override bool Equals(object obj
)
2729 return obj
!= null && obj
is NpgsqlTimeStamp
&& Equals((NpgsqlTimeStamp
) obj
);
2732 public override int GetHashCode()
2736 case TimeType
.Infinity
:
2737 return int.MaxValue
;
2738 case TimeType
.MinusInfinity
:
2739 return int.MinValue
;
2741 return _date
.GetHashCode() ^ PGUtil
.RotateShift(_time
.GetHashCode(), 16);
2745 public int CompareTo(NpgsqlTimeStamp other
)
2749 case TimeType
.Infinity
:
2750 return other
._type
== TimeType
.Infinity
? 0 : 1;
2751 case TimeType
.MinusInfinity
:
2752 return other
._type
== TimeType
.MinusInfinity
? 0 : -1;
2754 switch (other
._type
)
2756 case TimeType
.Infinity
:
2758 case TimeType
.MinusInfinity
:
2761 int cmp
= _date
.CompareTo(other
._date
);
2762 return cmp
== 0 ? _time
.CompareTo(_time
) : cmp
;
2767 public int CompareTo(object obj
)
2773 if (obj
is NpgsqlTimeStamp
)
2775 return CompareTo((NpgsqlTimeStamp
) obj
);
2777 throw new ArgumentException();
2780 public int Compare(NpgsqlTimeStamp x
, NpgsqlTimeStamp y
)
2782 return x
.CompareTo(y
);
2785 public int Compare(object x
, object y
)
2789 return y
== null ? 0 : -1;
2795 if (!(x
is IComparable
) || !(y
is IComparable
))
2797 throw new ArgumentException();
2799 return ((IComparable
) x
).CompareTo(y
);
2802 public NpgsqlTimeStampTZ
AtTimeZone(NpgsqlTimeZone timeZoneFrom
, NpgsqlTimeZone timeZoneTo
)
2805 NpgsqlTimeTZ adjusted
= new NpgsqlTimeTZ(_time
, timeZoneFrom
).AtTimeZone(timeZoneTo
, out overflow
);
2806 return new NpgsqlTimeStampTZ(_date
.AddDays(overflow
), adjusted
);
2809 public NpgsqlTimeStampTZ
AtTimeZone(NpgsqlTimeZone timeZone
)
2811 return AtTimeZone(timeZone
, NpgsqlTimeZone
.LocalTimeZone(_date
));
2814 public NpgsqlTimeStamp
Add(NpgsqlInterval interval
)
2818 case TimeType
.Infinity
:
2819 case TimeType
.MinusInfinity
:
2823 NpgsqlTime time
= _time
.Add(interval
, out overflow
);
2824 return new NpgsqlTimeStamp(_date
.Add(interval
, overflow
), time
);
2828 public NpgsqlTimeStamp
Subtract(NpgsqlInterval interval
)
2830 return Add(-interval
);
2833 public NpgsqlInterval
Subtract(NpgsqlTimeStamp timestamp
)
2837 case TimeType
.Infinity
:
2838 case TimeType
.MinusInfinity
:
2839 throw new ArgumentOutOfRangeException("You cannot subtract infinity timestamps");
2841 switch (timestamp
._type
)
2843 case TimeType
.Infinity
:
2844 case TimeType
.MinusInfinity
:
2845 throw new ArgumentOutOfRangeException("You cannot subtract infinity timestamps");
2847 return new NpgsqlInterval(0, _date
.DaysSinceEra
- timestamp
._date
.DaysSinceEra
, _time
.Ticks
- timestamp
._time
.Ticks
);
2850 public static implicit operator NpgsqlTimeStamp(DateTime datetime
)
2852 if (datetime
== DateTime
.MaxValue
)
2856 else if (datetime
== DateTime
.MinValue
)
2858 return MinusInfinity
;
2862 return new NpgsqlTimeStamp(new NpgsqlDate(datetime
), new NpgsqlTime(datetime
.TimeOfDay
));
2866 public static implicit operator DateTime(NpgsqlTimeStamp timestamp
)
2868 switch (timestamp
._type
)
2870 case TimeType
.Infinity
:
2871 return DateTime
.MaxValue
;
2872 case TimeType
.MinusInfinity
:
2873 return DateTime
.MinValue
;
2878 new DateTime(timestamp
.Date
.DaysSinceEra
*NpgsqlInterval
.TicksPerDay
+ timestamp
._time
.Ticks
,
2879 DateTimeKind
.Unspecified
);
2883 throw new InvalidCastException();
2888 public static NpgsqlTimeStamp
operator +(NpgsqlTimeStamp timestamp
, NpgsqlInterval interval
)
2890 return timestamp
.Add(interval
);
2893 public static NpgsqlTimeStamp
operator +(NpgsqlInterval interval
, NpgsqlTimeStamp timestamp
)
2895 return timestamp
.Add(interval
);
2898 public static NpgsqlTimeStamp
operator -(NpgsqlTimeStamp timestamp
, NpgsqlInterval interval
)
2900 return timestamp
.Subtract(interval
);
2903 public static NpgsqlInterval
operator -(NpgsqlTimeStamp x
, NpgsqlTimeStamp y
)
2905 return x
.Subtract(y
);
2908 public static bool operator ==(NpgsqlTimeStamp x
, NpgsqlTimeStamp y
)
2913 public static bool operator !=(NpgsqlTimeStamp x
, NpgsqlTimeStamp y
)
2918 public static bool operator <(NpgsqlTimeStamp x
, NpgsqlTimeStamp y
)
2920 return x
.CompareTo(y
) < 0;
2923 public static bool operator >(NpgsqlTimeStamp x
, NpgsqlTimeStamp y
)
2925 return x
.CompareTo(y
) > 0;
2928 public static bool operator <=(NpgsqlTimeStamp x
, NpgsqlTimeStamp y
)
2930 return x
.CompareTo(y
) <= 0;
2933 public static bool operator >=(NpgsqlTimeStamp x
, NpgsqlTimeStamp y
)
2935 return x
.CompareTo(y
) >= 0;
2940 public struct NpgsqlTimeStampTZ
: IEquatable
<NpgsqlTimeStampTZ
>, IComparable
<NpgsqlTimeStampTZ
>, IComparable
,
2941 IComparer
<NpgsqlTimeStampTZ
>, IComparer
2943 private enum TimeType
2950 public static readonly NpgsqlTimeStampTZ Epoch
= new NpgsqlTimeStampTZ(NpgsqlDate
.Epoch
, NpgsqlTimeTZ
.AllBalls
);
2951 public static readonly NpgsqlTimeStampTZ Era
= new NpgsqlTimeStampTZ(NpgsqlDate
.Era
, NpgsqlTimeTZ
.AllBalls
);
2953 public static readonly NpgsqlTimeStampTZ Infinity
=
2954 new NpgsqlTimeStampTZ(TimeType
.Infinity
, NpgsqlDate
.Era
, NpgsqlTimeTZ
.AllBalls
);
2956 public static readonly NpgsqlTimeStampTZ MinusInfinity
=
2957 new NpgsqlTimeStampTZ(TimeType
.MinusInfinity
, NpgsqlDate
.Era
, NpgsqlTimeTZ
.AllBalls
);
2959 public static NpgsqlTimeStampTZ Now
2961 get { return new NpgsqlTimeStampTZ(NpgsqlDate.Now, NpgsqlTimeTZ.Now); }
2964 public static NpgsqlTimeStampTZ Today
2966 get { return new NpgsqlTimeStampTZ(NpgsqlDate.Now); }
2969 public static NpgsqlTimeStampTZ Yesterday
2971 get { return new NpgsqlTimeStampTZ(NpgsqlDate.Yesterday); }
2974 public static NpgsqlTimeStampTZ Tomorrow
2976 get { return new NpgsqlTimeStampTZ(NpgsqlDate.Tomorrow); }
2979 private readonly NpgsqlDate _date
;
2980 private readonly NpgsqlTimeTZ _time
;
2981 private readonly TimeType _type
;
2983 private NpgsqlTimeStampTZ(TimeType type
, NpgsqlDate date
, NpgsqlTimeTZ time
)
2990 public NpgsqlTimeStampTZ(NpgsqlDate date
, NpgsqlTimeTZ time
)
2991 : this(TimeType
.Finite
, date
, time
)
2995 public NpgsqlTimeStampTZ(NpgsqlDate date
)
2996 : this(date
, NpgsqlTimeTZ
.LocalMidnight(date
))
3000 public NpgsqlTimeStampTZ(int year
, int month
, int day
, int hours
, int minutes
, int seconds
, NpgsqlTimeZone
? timezone
)
3002 new NpgsqlDate(year
, month
, day
),
3003 new NpgsqlTimeTZ(hours
, minutes
, seconds
,
3004 timezone
.HasValue
? timezone
.Value
: NpgsqlTimeZone
.LocalTimeZone(new NpgsqlDate(year
, month
, day
)))
3009 public NpgsqlDate Date
3011 get { return _date; }
3014 public NpgsqlTimeTZ Time
3016 get { return _time; }
3019 public int DayOfYear
3021 get { return _date.DayOfYear; }
3026 get { return _date.Year; }
3031 get { return _date.Month; }
3036 get { return _date.Day; }
3039 public DayOfWeek DayOfWeek
3041 get { return _date.DayOfWeek; }
3044 public bool IsLeapYear
3046 get { return _date.IsLeapYear; }
3049 public NpgsqlTimeStampTZ
AddDays(int days
)
3053 case TimeType
.Infinity
:
3054 case TimeType
.MinusInfinity
:
3057 return new NpgsqlTimeStampTZ(_date
.AddDays(days
), _time
);
3061 public NpgsqlTimeStampTZ
AddYears(int years
)
3065 case TimeType
.Infinity
:
3066 case TimeType
.MinusInfinity
:
3069 return new NpgsqlTimeStampTZ(_date
.AddYears(years
), _time
);
3073 public NpgsqlTimeStampTZ
AddMonths(int months
)
3077 case TimeType
.Infinity
:
3078 case TimeType
.MinusInfinity
:
3081 return new NpgsqlTimeStampTZ(_date
.AddMonths(months
), _time
);
3085 public NpgsqlTime LocalTime
3087 get { return _time.LocalTime; }
3090 public NpgsqlTimeZone TimeZone
3092 get { return _time.TimeZone; }
3095 public NpgsqlTime UTCTime
3097 get { return _time.UTCTime; }
3102 get { return _date.DaysSinceEra*NpgsqlInterval.TicksPerDay + _time.Ticks; }
3105 public int Microseconds
3107 get { return _time.Microseconds; }
3110 public int Milliseconds
3112 get { return _time.Milliseconds; }
3117 get { return _time.Seconds; }
3122 get { return _time.Minutes; }
3127 get { return _time.Hours; }
3130 public bool IsFinite
3132 get { return _type == TimeType.Finite; }
3135 public bool IsInfinity
3137 get { return _type == TimeType.Infinity; }
3140 public bool IsMinusInfinity
3142 get { return _type == TimeType.MinusInfinity; }
3145 public NpgsqlTimeStampTZ
Normalize()
3147 return Add(NpgsqlInterval
.Zero
);
3150 public override string ToString()
3154 case TimeType
.Infinity
:
3156 case TimeType
.MinusInfinity
:
3159 return string.Format("{0} {1}", _date
, _time
);
3163 public static NpgsqlTimeStampTZ
Parse(string str
)
3167 throw new NullReferenceException();
3169 switch (str
= str
.Trim().ToLowerInvariant())
3174 return MinusInfinity
;
3178 int idxSpace
= str
.IndexOf(' ');
3179 string datePart
= str
.Substring(0, idxSpace
);
3180 if (str
.Contains("bc"))
3184 int idxSecond
= str
.IndexOf(' ', idxSpace
+ 1);
3185 if (idxSecond
== -1)
3187 idxSecond
= str
.Length
;
3189 string timePart
= str
.Substring(idxSpace
+ 1, idxSecond
- idxSpace
- 1);
3190 return new NpgsqlTimeStampTZ(NpgsqlDate
.Parse(datePart
), NpgsqlTimeTZ
.Parse(timePart
));
3192 catch (OverflowException
)
3198 throw new FormatException();
3203 public bool Equals(NpgsqlTimeStampTZ other
)
3207 case TimeType
.Infinity
:
3208 return other
._type
== TimeType
.Infinity
;
3209 case TimeType
.MinusInfinity
:
3210 return other
._type
== TimeType
.MinusInfinity
;
3212 return other
._type
== TimeType
.Finite
&& _date
.Equals(other
._date
) && _time
.Equals(other
._time
);
3216 public override bool Equals(object obj
)
3218 return obj
!= null && obj
is NpgsqlTimeStamp
&& Equals((NpgsqlTimeStampTZ
) obj
);
3221 public override int GetHashCode()
3225 case TimeType
.Infinity
:
3226 return int.MaxValue
;
3227 case TimeType
.MinusInfinity
:
3228 return int.MinValue
;
3230 return _date
.GetHashCode() ^ PGUtil
.RotateShift(_time
.GetHashCode(), 16);
3234 public int CompareTo(NpgsqlTimeStampTZ other
)
3238 case TimeType
.Infinity
:
3239 return other
._type
== TimeType
.Infinity
? 0 : 1;
3240 case TimeType
.MinusInfinity
:
3241 return other
._type
== TimeType
.MinusInfinity
? 0 : -1;
3243 switch (other
._type
)
3245 case TimeType
.Infinity
:
3247 case TimeType
.MinusInfinity
:
3250 int cmp
= _date
.CompareTo(other
._date
);
3251 return cmp
== 0 ? _time
.CompareTo(_time
) : cmp
;
3256 public int CompareTo(object obj
)
3262 if (obj
is NpgsqlTimeStamp
)
3264 return CompareTo((NpgsqlTimeStamp
) obj
);
3266 throw new ArgumentException();
3269 public int Compare(NpgsqlTimeStampTZ x
, NpgsqlTimeStampTZ y
)
3271 return x
.CompareTo(y
);
3274 public int Compare(object x
, object y
)
3278 return y
== null ? 0 : -1;
3284 if (!(x
is IComparable
) || !(y
is IComparable
))
3286 throw new ArgumentException();
3288 return ((IComparable
) x
).CompareTo(y
);
3291 public NpgsqlTimeStamp
AtTimeZone(NpgsqlTimeZone timeZone
)
3294 NpgsqlTimeTZ adjusted
= _time
.AtTimeZone(timeZone
, out overflow
);
3295 return new NpgsqlTimeStamp(_date
.AddDays(overflow
), adjusted
.LocalTime
);
3298 public NpgsqlTimeStampTZ
Add(NpgsqlInterval interval
)
3302 case TimeType
.Infinity
:
3303 case TimeType
.MinusInfinity
:
3307 NpgsqlTimeTZ time
= _time
.Add(interval
, out overflow
);
3308 return new NpgsqlTimeStampTZ(_date
.Add(interval
, overflow
), time
);
3312 public NpgsqlTimeStampTZ
Subtract(NpgsqlInterval interval
)
3314 return Add(-interval
);
3317 public NpgsqlInterval
Subtract(NpgsqlTimeStampTZ timestamp
)
3321 case TimeType
.Infinity
:
3322 case TimeType
.MinusInfinity
:
3323 throw new ArgumentOutOfRangeException("You cannot subtract infinity timestamps");
3325 switch (timestamp
._type
)
3327 case TimeType
.Infinity
:
3328 case TimeType
.MinusInfinity
:
3329 throw new ArgumentOutOfRangeException("You cannot subtract infinity timestamps");
3331 return new NpgsqlInterval(0, _date
.DaysSinceEra
- timestamp
._date
.DaysSinceEra
, (_time
- timestamp
._time
).Ticks
);
3334 public static implicit operator NpgsqlTimeStampTZ(DateTime datetime
)
3336 if (datetime
== DateTime
.MaxValue
)
3340 else if (datetime
== DateTime
.MinValue
)
3342 return MinusInfinity
;
3346 NpgsqlDate newDate
= new NpgsqlDate(datetime
);
3348 new NpgsqlTimeStampTZ(newDate
,
3349 new NpgsqlTimeTZ(datetime
.TimeOfDay
,
3350 datetime
.Kind
== DateTimeKind
.Utc
3351 ? NpgsqlTimeZone
.UTC
3352 : NpgsqlTimeZone
.LocalTimeZone(newDate
)));
3356 public static explicit operator DateTime(NpgsqlTimeStampTZ timestamp
)
3358 switch (timestamp
._type
)
3360 case TimeType
.Infinity
:
3361 return DateTime
.MaxValue
;
3362 case TimeType
.MinusInfinity
:
3363 return DateTime
.MinValue
;
3367 NpgsqlTimeStamp utc
= timestamp
.AtTimeZone(NpgsqlTimeZone
.UTC
);
3368 return new DateTime(utc
.Date
.DaysSinceEra
*NpgsqlInterval
.TicksPerDay
+ utc
.Time
.Ticks
, DateTimeKind
.Utc
);
3372 throw new InvalidCastException();
3377 public static NpgsqlTimeStampTZ
operator +(NpgsqlTimeStampTZ timestamp
, NpgsqlInterval interval
)
3379 return timestamp
.Add(interval
);
3382 public static NpgsqlTimeStampTZ
operator +(NpgsqlInterval interval
, NpgsqlTimeStampTZ timestamp
)
3384 return timestamp
.Add(interval
);
3387 public static NpgsqlTimeStampTZ
operator -(NpgsqlTimeStampTZ timestamp
, NpgsqlInterval interval
)
3389 return timestamp
.Subtract(interval
);
3392 public static NpgsqlInterval
operator -(NpgsqlTimeStampTZ x
, NpgsqlTimeStampTZ y
)
3394 return x
.Subtract(y
);
3397 public static bool operator ==(NpgsqlTimeStampTZ x
, NpgsqlTimeStampTZ y
)
3402 public static bool operator !=(NpgsqlTimeStampTZ x
, NpgsqlTimeStampTZ y
)
3407 public static bool operator <(NpgsqlTimeStampTZ x
, NpgsqlTimeStampTZ y
)
3409 return x
.CompareTo(y
) < 0;
3412 public static bool operator >(NpgsqlTimeStampTZ x
, NpgsqlTimeStampTZ y
)
3414 return x
.CompareTo(y
) > 0;
3417 public static bool operator <=(NpgsqlTimeStampTZ x
, NpgsqlTimeStampTZ y
)
3419 return x
.CompareTo(y
) <= 0;
3422 public static bool operator >=(NpgsqlTimeStampTZ x
, NpgsqlTimeStampTZ y
)
3424 return x
.CompareTo(y
) >= 0;