bring back CodeContracts to mobile profiles.
[mono-project.git] / mcs / class / Npgsql / NpgsqlTypes / DateDatatypes.cs
blobd36a46b1f02a81cd6bc76c50b1c82e62a0245f23
1 // NpgsqlTypes\DateDatatypes.cs
2 //
3 // Author:
4 // Jon Hanna. (jon@hackcraft.net)
5 //
6 // Copyright (C) 2007-2008 The Npgsql Development Team
7 // npgsql-general@gborg.postgresql.org
8 // http://gborg.postgresql.org/project/npgsql/projdisplay.php
9 //
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.
14 //
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.
20 //
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.
27 using System;
28 using System.Collections;
29 using System.Collections.Generic;
30 using System.Text;
31 using Npgsql;
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.
37 namespace NpgsqlTypes
39 /// <summary>
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 &#x2014; 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 &#x2014;
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 &#x263a;</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>
57 /// </remarks>
58 /// <seealso cref="Ticks"/>
59 /// <seealso cref="JustifyDays"/>
60 /// <seealso cref="JustifyMonths"/>
61 /// <seealso cref="Canonicalize()"/>
62 /// </summary>
63 [Serializable]
64 public struct NpgsqlInterval : IComparable, IComparer, IEquatable<NpgsqlInterval>, IComparable<NpgsqlInterval>,
65 IComparer<NpgsqlInterval>
67 #region Constants
69 /// <summary>
70 /// Represents the number of ticks (100ns periods) in one microsecond. This field is constant.
71 /// </summary>
72 public const long TicksPerMicrosecond = TimeSpan.TicksPerMillisecond/1000;
74 /// <summary>
75 /// Represents the number of ticks (100ns periods) in one millisecond. This field is constant.
76 /// </summary>
77 public const long TicksPerMillsecond = TimeSpan.TicksPerMillisecond;
79 /// <summary>
80 /// Represents the number of ticks (100ns periods) in one second. This field is constant.
81 /// </summary>
82 public const long TicksPerSecond = TimeSpan.TicksPerSecond;
84 /// <summary>
85 /// Represents the number of ticks (100ns periods) in one minute. This field is constant.
86 /// </summary>
87 public const long TicksPerMinute = TimeSpan.TicksPerMinute;
89 /// <summary>
90 /// Represents the number of ticks (100ns periods) in one hour. This field is constant.
91 /// </summary>
92 public const long TicksPerHour = TimeSpan.TicksPerHour;
94 /// <summary>
95 /// Represents the number of ticks (100ns periods) in one day. This field is constant.
96 /// </summary>
97 public const long TicksPerDay = TimeSpan.TicksPerDay;
99 /// <summary>
100 /// Represents the number of hours in one day (assuming no daylight savings adjustments). This field is constant.
101 /// </summary>
102 public const int HoursPerDay = 24;
104 /// <summary>
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 &#xd7; 12 = 360 rather than 356/366 days.
108 /// </summary>
109 public const int DaysPerMonth = 30;
111 /// <summary>
112 /// Represents the number of ticks (100ns periods) in one day, assuming 30 days per month. <seealso cref="DaysPerMonth"/>
113 /// </summary>
114 public const long TicksPerMonth = TicksPerDay*DaysPerMonth;
116 /// <summary>
117 /// Represents the number of months in a year. This field is constant.
118 /// </summary>
119 public const int MonthsPerYear = 12;
121 /// <summary>
122 /// Represents the maximum <see cref="NpgsqlInterval"/>. This field is read-only.
123 /// </summary>
124 public static readonly NpgsqlInterval MaxValue = new NpgsqlInterval(long.MaxValue);
126 /// <summary>
127 /// Represents the minimum <see cref="NpgsqlInterval"/>. This field is read-only.
128 /// </summary>
129 public static readonly NpgsqlInterval MinValue = new NpgsqlInterval(long.MinValue);
131 /// <summary>
132 /// Represents the zero <see cref="NpgsqlInterval"/>. This field is read-only.
133 /// </summary>
134 public static readonly NpgsqlInterval Zero = new NpgsqlInterval(0);
136 #endregion
138 private readonly int _months;
139 private readonly int _days;
140 private readonly long _ticks;
142 #region Constructors
144 /// <summary>
145 /// Initializes a new <see cref="NpgsqlInterval"/> to the specified number of ticks.
146 /// </summary>
147 /// <param name="ticks">A time period expressed in 100ns units.</param>
148 public NpgsqlInterval(long ticks)
150 _months = 0;
151 _days = 0;
152 _ticks = ticks;
155 /// <summary>
156 /// Initializes a new <see cref="NpgsqlInterval"/> to hold the same time as a <see cref="TimeSpan"/>
157 /// </summary>
158 /// <param name="timespan">A time period expressed in a <see cref="TimeSpan"/></param>
159 public NpgsqlInterval(TimeSpan timespan)
160 : this(timespan.Ticks)
164 /// <summary>
165 /// Initializes a new <see cref="NpgsqlInterval"/> to the specified number of months, days
166 /// &amp; ticks.
167 /// </summary>
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)
173 _months = months;
174 _days = days;
175 _ticks = ticks;
178 /// <summary>
179 /// Initializes a new <see cref="NpgsqlInterval"/> to the specified number of
180 /// days, hours, minutes &amp; seconds.
181 /// </summary>
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)
191 /// <summary>
192 /// Initializes a new <see cref="NpgsqlInterval"/> to the specified number of
193 /// days, hours, minutes, seconds &amp; milliseconds.
194 /// </summary>
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)
205 /// <summary>
206 /// Initializes a new <see cref="NpgsqlInterval"/> to the specified number of
207 /// months, days, hours, minutes, seconds &amp; milliseconds.
208 /// </summary>
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)
220 /// <summary>
221 /// Initializes a new <see cref="NpgsqlInterval"/> to the specified number of
222 /// years, months, days, hours, minutes, seconds &amp; milliseconds.
223 /// <para>Years are calculated exactly equivalent to 12 months.</para>
224 /// </summary>
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)
237 #endregion
239 #region Whole Parts
241 /// <summary>
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&#xb5;s = 1,000 ns. It may be smaller as follows:
247 /// <list type="number">
248 /// <item>
249 /// <term>interval(0)</term>
250 /// <description>resolution of 1s (1 second)</description>
251 /// </item>
252 /// <item>
253 /// <term>interval(1)</term>
254 /// <description>resolution of 100ms = 0.1s (100 milliseconds)</description>
255 /// </item>
256 /// <item>
257 /// <term>interval(2)</term>
258 /// <description>resolution of 10ms = 0.01s (10 milliseconds)</description>
259 /// </item>
260 /// <item>
261 /// <term>interval(3)</term>
262 /// <description>resolution of 1ms = 0.001s (1 millisecond)</description>
263 /// </item>
264 /// <item>
265 /// <term>interval(4)</term>
266 /// <description>resolution of 100&#xb5;s = 0.0001s (100 microseconds)</description>
267 /// </item>
268 /// <item>
269 /// <term>interval(5)</term>
270 /// <description>resolution of 10&#xb5;s = 0.00001s (10 microseconds)</description>
271 /// </item>
272 /// <item>
273 /// <term>interval(6) or interval</term>
274 /// <description>resolution of 1&#xb5;s = 0.000001s (1 microsecond)</description>
275 /// </item>
276 /// </list>
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>
282 /// </remarks>
283 /// <returns>The number of ticks in the instance.</returns>
284 /// </summary>
285 public long Ticks
287 get { return _ticks; }
290 /// <summary>
291 /// Gets the number of whole microseconds held in the instance.
292 /// <returns>An in the range [-999999, 999999].</returns>
293 /// </summary>
294 public int Microseconds
296 get { return (int) (_ticks/10)%1000000; }
299 /// <summary>
300 /// Gets the number of whole milliseconds held in the instance.
301 /// <returns>An in the range [-999, 999].</returns>
302 /// </summary>
303 public int Milliseconds
305 get { return (int) ((_ticks/TicksPerMillsecond)%1000); }
308 /// <summary>
309 /// Gets the number of whole seconds held in the instance.
310 /// <returns>An in the range [-59, 59].</returns>
311 /// </summary>
312 public int Seconds
314 get { return (int) ((_ticks/TicksPerSecond)%60); }
317 /// <summary>
318 /// Gets the number of whole minutes held in the instance.
319 /// <returns>An in the range [-59, 59].</returns>
320 /// </summary>
321 public int Minutes
323 get { return (int) ((_ticks/TicksPerMinute)%60); }
326 /// <summary>
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>
330 /// </summary>
331 public int Hours
333 get { return (int) (_ticks/TicksPerHour); }
336 /// <summary>
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>
340 /// </summary>
341 public int Days
343 get { return _days; }
346 /// <summary>
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>
350 /// </summary>
351 public int Months
353 get { return _months; }
356 /// <summary>
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 &#xb1;23:59:59.9999999 unless
359 /// <see cref="JustifyDays()"/> has been called to produce this instance.</remarks>
360 /// </summary>
361 public TimeSpan Time
363 get { return new TimeSpan(_ticks); }
366 #endregion
368 #region Total Parts
370 /// <summary>
371 /// The total number of ticks (100ns units) in the instance, assuming 24 hours in each day and
372 /// 30 days in a month.
373 /// </summary>
374 public long TotalTicks
376 get { return Ticks + Days*TicksPerDay + Months*TicksPerMonth; }
379 /// <summary>
380 /// The total number of microseconds in the instance, assuming 24 hours in each day and
381 /// 30 days in a month.
382 /// </summary>
383 public double TotalMicroseconds
385 get { return TotalTicks/10d; }
388 /// <summary>
389 /// The total number of milliseconds in the instance, assuming 24 hours in each day and
390 /// 30 days in a month.
391 /// </summary>
392 public double TotalMilliseconds
394 get { return TotalTicks/(double) TicksPerMillsecond; }
397 /// <summary>
398 /// The total number of seconds in the instance, assuming 24 hours in each day and
399 /// 30 days in a month.
400 /// </summary>
401 public double TotalSeconds
403 get { return TotalTicks/(double) TicksPerSecond; }
406 /// <summary>
407 /// The total number of minutes in the instance, assuming 24 hours in each day and
408 /// 30 days in a month.
409 /// </summary>
410 public double TotalMinutes
412 get { return TotalTicks/(double) TicksPerMinute; }
415 /// <summary>
416 /// The total number of hours in the instance, assuming 24 hours in each day and
417 /// 30 days in a month.
418 /// </summary>
419 public double TotalHours
421 get { return TotalTicks/(double) TicksPerHour; }
424 /// <summary>
425 /// The total number of days in the instance, assuming 24 hours in each day and
426 /// 30 days in a month.
427 /// </summary>
428 public double TotalDays
430 get { return TotalTicks/(double) TicksPerDay; }
433 /// <summary>
434 /// The total number of months in the instance, assuming 24 hours in each day and
435 /// 30 days in a month.
436 /// </summary>
437 public double TotalMonths
439 get { return TotalTicks/(double) TicksPerMonth; }
442 #endregion
444 #region Create From Part
446 /// <summary>
447 /// Creates an <see cref="NpgsqlInterval"/> from a number of ticks.
448 /// </summary>
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();
456 /// <summary>
457 /// Creates an <see cref="NpgsqlInterval"/> from a number of microseconds.
458 /// </summary>
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));
466 /// <summary>
467 /// Creates an <see cref="NpgsqlInterval"/> from a number of milliseconds.
468 /// </summary>
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));
476 /// <summary>
477 /// Creates an <see cref="NpgsqlInterval"/> from a number of seconds.
478 /// </summary>
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));
486 /// <summary>
487 /// Creates an <see cref="NpgsqlInterval"/> from a number of minutes.
488 /// </summary>
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));
496 /// <summary>
497 /// Creates an <see cref="NpgsqlInterval"/> from a number of hours.
498 /// </summary>
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));
506 /// <summary>
507 /// Creates an <see cref="NpgsqlInterval"/> from a number of days.
508 /// </summary>
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));
516 /// <summary>
517 /// Creates an <see cref="NpgsqlInterval"/> from a number of months.
518 /// </summary>
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));
526 #endregion
528 #region Arithmetic
530 /// <summary>
531 /// Adds another interval to this instance and returns the result.
532 /// </summary>
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);
540 /// <summary>
541 /// Subtracts another interval from this instance and returns the result.
542 /// </summary>
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);
550 /// <summary>
551 /// Returns an <see cref="NpgsqlInterval"/> whose value is the negated value of this instance.
552 /// </summary>
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);
559 /// <summary>
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.
562 /// </summary>
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;
569 #endregion
571 #region Justification
573 /// <summary>
574 /// Equivalent to PostgreSQL's justify_days function.
575 /// </summary>
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);
583 /// <summary>
584 /// Opposite to PostgreSQL's justify_days function.
585 /// </summary>
586 /// <returns>An <see cref="NpgsqlInterval"/> based on this one, but with any days converted to multiples of &#xB1;24hours.</returns>
587 public NpgsqlInterval UnjustifyDays()
589 return new NpgsqlInterval(Months, 0, Ticks + Days*TicksPerDay);
592 /// <summary>
593 /// Equivalent to PostgreSQL's justify_months function.
594 /// </summary>
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);
602 /// <summary>
603 /// Opposite to PostgreSQL's justify_months function.
604 /// </summary>
605 /// <returns>An <see cref="NpgsqlInterval"/> based on this one, but with any months converted to multiples of &#xB1;30days.</returns>
606 public NpgsqlInterval UnjustifyMonths()
608 return new NpgsqlInterval(0, Days + Months*DaysPerMonth, Ticks);
611 /// <summary>
612 /// Equivalent to PostgreSQL's justify_interval function.
613 /// </summary>
614 /// <returns>An <see cref="NpgsqlInterval"/> based on this one,
615 /// but with any months converted to multiples of &#xB1;30days
616 /// and then with any days converted to multiples of &#xB1;24hours</returns>
617 public NpgsqlInterval JustifyInterval()
619 return JustifyMonths().JustifyDays();
622 /// <summary>
623 /// Opposite to PostgreSQL's justify_interval function.
624 /// </summary>
625 /// <returns>An <see cref="NpgsqlInterval"/> based on this one, but with any months converted to multiples of &#xB1;30days and then any days converted to multiples of &#xB1;24hours;</returns>
626 public NpgsqlInterval UnjustifyInterval()
628 return new NpgsqlInterval(Ticks + Days*TicksPerDay + Months*DaysPerMonth*TicksPerDay);
631 /// <summary>
632 /// Produces a canonical NpgslInterval with 0 months and hours in the range of [-23, 23].
633 /// <remarks>
634 /// <para>
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.
637 /// </para><para>
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
644 /// another.
645 /// </para>
646 /// <para>Note that the results of casting a <see cref="TimeSpan"/> to <see cref="NpgsqlInterval"/> is
647 /// canonicalised.</para>
648 /// </remarks>
649 /// <returns>An <see cref="NpgsqlInterval"/> based on this one, but with months converted to multiples of &#xB1;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);
656 #endregion
658 #region Casts
660 /// <summary>
661 /// Implicit cast of a <see cref="TimeSpan"/> to an <see cref="NpgsqlInterval"/>
662 /// </summary>
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();
670 /// <summary>
671 /// Implicit cast of an <see cref="NpgsqlInterval"/> to a <see cref="TimeSpan"/>.
672 /// </summary>
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);
680 #endregion
682 #region Comparison
684 /// <summary>
685 /// Returns true if another <see cref="NpgsqlInterval"/> is exactly the same as this instance.
686 /// </summary>
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;
695 /// <summary>
696 /// Returns true if another object is an <see cref="NpgsqlInterval"/>, that is exactly the same as
697 /// this instance
698 /// </summary>
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)
704 if (obj == null)
706 return false;
708 if (obj is NpgsqlInterval)
710 return Equals((NpgsqlInterval) obj);
712 return false;
715 /// <summary>
716 /// Compares two <see cref="NpgsqlInterval"/> instances.
717 /// </summary>
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)
734 if (x == null)
736 return y == null ? 0 : 1;
738 if (y == null)
740 return -1;
744 return ((IComparable) x).CompareTo(y);
746 catch (Exception)
748 throw new ArgumentException();
752 /// <summary>
753 /// A hash code suitable for uses with hashing algorithms.
754 /// </summary>
755 /// <returns>An signed integer.</returns>
756 public override int GetHashCode()
758 return UnjustifyInterval().Ticks.GetHashCode();
761 /// <summary>
762 /// Compares this instance with another/
763 /// </summary>
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);
773 /// <summary>
774 /// Compares this instance with another/
775 /// </summary>
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)
786 if (other == null)
788 return 1;
790 else if (other is NpgsqlInterval)
792 return CompareTo((NpgsqlInterval) other);
794 else
796 throw new ArgumentException();
800 #endregion
802 #region To And From Strings
804 /// <summary>
805 /// Parses a <see cref="String"/> and returns a <see cref="NpgsqlInterval"/> instance.
806 /// Designed to use the formats generally returned by PostgreSQL.
807 /// </summary>
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)
815 if (str == null)
817 throw new ArgumentNullException("str");
819 str = str.Replace('s', ' '); //Quick and easy way to catch plurals.
822 int years = 0;
823 int months = 0;
824 int days = 0;
825 int hours = 0;
826 int minutes = 0;
827 decimal seconds = 0m;
828 int idx = str.IndexOf("year");
829 if (idx > 0)
831 years = int.Parse(str.Substring(0, idx));
832 str = str.Substring(idx + 5);
834 idx = str.IndexOf("mon");
835 if (idx > 0)
837 months = int.Parse(str.Substring(0, idx));
838 str = str.Substring(idx + 4);
840 idx = str.IndexOf("day");
841 if (idx > 0)
843 days = int.Parse(str.Substring(0, idx));
844 str = str.Substring(idx + 4).Trim();
846 if (str.Length > 0)
848 string[] parts = str.Split(':');
849 switch (parts.Length) //One of those times that fall-through would actually be good.
851 case 1:
852 hours = int.Parse(parts[0]);
853 break;
854 case 2:
855 hours = int.Parse(parts[0]);
856 minutes = int.Parse(parts[1]);
857 break;
858 default:
859 hours = int.Parse(parts[0]);
860 minutes = int.Parse(parts[1]);
861 seconds = decimal.Parse(parts[2]);
862 break;
865 long ticks = hours*TicksPerHour + minutes*TicksPerMinute + (long) (seconds*TicksPerSecond);
866 return new NpgsqlInterval(years*MonthsPerYear + months, days, ticks);
868 catch (OverflowException)
870 throw;
872 catch (Exception)
874 throw new FormatException();
878 /// <summary>
879 /// Attempt to parse a <see cref="String"/> to produce an <see cref="NpgsqlInterval"/>.
880 /// </summary>
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)
888 result = Parse(str);
889 return true;
891 catch (Exception)
893 result = Zero;
894 return false;
898 /// <summary>
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
903 /// <remarks>
904 /// Ticks are 100ns, Postgress resolution is only to 1&#xb5;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.
908 /// </remarks>
909 /// </summary>
910 /// <returns>The <see cref="String"/> representation.</returns>
911 public override string ToString()
913 StringBuilder sb = new StringBuilder();
914 if (Months != 0)
916 sb.Append(Months).Append(Math.Abs(Months) == 1 ? " mon " : " mons ");
918 if (Days != 0)
920 if (Months < 0 && Days > 0)
922 sb.Append('+');
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))
930 sb.Append('+');
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();
952 #endregion
954 #region Common Operators
956 /// <summary>
957 /// Adds two <see cref="NpgsqlInterval"/> together.
958 /// </summary>
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)
964 return x.Add(y);
967 /// <summary>
968 /// Subtracts one <see cref="NpgsqlInterval"/> from another.
969 /// </summary>
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);
978 /// <summary>
979 /// Returns true if two <see cref="NpgsqlInterval"/> are exactly the same.
980 /// </summary>
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)
986 return x.Equals(y);
989 /// <summary>
990 /// Returns false if two <see cref="NpgsqlInterval"/> are exactly the same.
991 /// </summary>
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)
997 return !(x == y);
1000 /// <summary>
1001 /// Compares two <see cref="NpgsqlInterval"/> instances to see if the first is less than the second
1002 /// </summary>
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;
1011 /// <summary>
1012 /// Compares two <see cref="NpgsqlInterval"/> instances to see if the first is less than or equivalent to the second
1013 /// </summary>
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;
1022 /// <summary>
1023 /// Compares two <see cref="NpgsqlInterval"/> instances to see if the first is greater than the second
1024 /// </summary>
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)
1030 return !(x <= y);
1033 /// <summary>
1034 /// Compares two <see cref="NpgsqlInterval"/> instances to see if the first is greater than or equivalent the second
1035 /// </summary>
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)
1041 return !(x < y);
1044 /// <summary>
1045 /// Returns the instance.
1046 /// </summary>
1047 /// <param name="x">An <see cref="NpgsqlInterval"/>.</param>
1048 /// <returns>The argument.</returns>
1049 public static NpgsqlInterval operator +(NpgsqlInterval x)
1051 return x;
1054 /// <summary>
1055 /// Negates an <see cref="NpgsqlInterval"/> instance.
1056 /// </summary>
1057 /// <param name="x">An <see cref="NpgsqlInterval"/>.</param>
1058 /// <returns>The negation of the argument.</returns>
1059 public static NpgsqlInterval operator -(NpgsqlInterval x)
1061 return x.Negate();
1064 #endregion
1067 [Serializable]
1068 public struct NpgsqlDate : IEquatable<NpgsqlDate>, IComparable<NpgsqlDate>, IComparable, IComparer<NpgsqlDate>,
1069 IComparer
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
1089 get { return Now; }
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)
1104 if (str == null)
1106 throw new ArgumentNullException("str");
1108 str = str.Trim();
1111 int idx = str.IndexOf('-');
1112 if (idx == -1)
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));
1123 idxLast = idx + 1;
1124 if ((idx = str.IndexOf(' ', idxLast)) == -1)
1126 idx = str.Length;
1128 int day = int.Parse(str.Substring(idxLast, idx - idxLast));
1129 if (str.Contains("BC"))
1131 year = -year;
1133 return new NpgsqlDate(year, month, day);
1135 catch (OverflowException)
1137 throw;
1139 catch (Exception)
1141 throw new FormatException();
1145 public static bool TryParse(string str, out NpgsqlDate date)
1149 date = Parse(str);
1150 return true;
1152 catch
1154 date = Era;
1155 return false;
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; }
1210 public int Year
1214 int guess = (int) Math.Round(_daysSinceEra/365.2425);
1215 int test = guess - 1;
1216 while (DaysForYears(++test) <= _daysSinceEra)
1220 return test - 1;
1224 public int Month
1228 int i = 1;
1229 int target = DayOfYear;
1230 int[] array = IsLeapYear ? LeapYearDays : CommonYearDays;
1231 while (target > array[i])
1233 ++i;
1235 return i;
1239 public int Day
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.
1264 if (year < 1)
1266 year = year + 1;
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
1281 ++newYear;
1283 else if (newYear <= 0 && _daysSinceEra >= 0) //cross 1CE/1BCE divide going down
1285 --newYear;
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)
1316 if (x == null)
1318 return y == null ? 0 : -1;
1320 if (y == null)
1322 return 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)
1348 if (obj == null)
1350 return 1;
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.
1367 return
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)
1374 return x.Equals(y);
1377 public static bool operator !=(NpgsqlDate x, NpgsqlDate y)
1379 return !(x == 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);
1408 catch
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);
1440 [Serializable]
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)
1447 : this(ts.Ticks)
1451 private NpgsqlTimeZone(long ticks)
1453 _totalSeconds = (int) (ticks/NpgsqlInterval.TicksPerSecond);
1456 public NpgsqlTimeZone(NpgsqlInterval ni)
1457 : this(ni.Ticks)
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));
1501 public int Hours
1503 get { return _totalSeconds/60/60; }
1506 public int Minutes
1508 get { return (_totalSeconds/60)%60; }
1511 public int Seconds
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)
1523 DateTime dt;
1524 if (date.Year >= 1902 && date.Year <= 2038)
1526 dt = (DateTime) date;
1528 else
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"));
1551 if (Seconds != 0)
1553 sb.Append(":").Append(Math.Abs(Seconds).ToString("D2"));
1556 return sb.ToString();
1559 public static NpgsqlTimeZone Parse(string str)
1561 if (str == null)
1563 throw new ArgumentNullException();
1567 str = str.Trim();
1568 bool neg;
1569 switch (str[0])
1571 case '+':
1572 neg = false;
1573 break;
1574 case '-':
1575 neg = true;
1576 break;
1577 default:
1578 throw new FormatException();
1580 int hours;
1581 int minutes;
1582 int seconds;
1583 string[] parts = str.Substring(1).Split(':');
1584 switch (parts.Length) //One of those times that fall-through would actually be good.
1586 case 1:
1587 hours = int.Parse(parts[0]);
1588 minutes = seconds = 0;
1589 break;
1590 case 2:
1591 hours = int.Parse(parts[0]);
1592 minutes = int.Parse(parts[1]);
1593 seconds = 0;
1594 break;
1595 default:
1596 hours = int.Parse(parts[0]);
1597 minutes = int.Parse(parts[1]);
1598 seconds = int.Parse(parts[2]);
1599 break;
1601 int totalSeconds = hours*60*60 + minutes*60 + seconds*(neg ? -1 : 1);
1602 return new NpgsqlTimeZone(totalSeconds*NpgsqlInterval.TicksPerSecond);
1604 catch (OverflowException)
1606 throw;
1608 catch
1610 throw new FormatException();
1614 public static bool TryParse(string str, NpgsqlTimeZone tz)
1618 tz = Parse(str);
1619 return true;
1621 catch
1623 tz = UTC;
1624 return false;
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)
1641 if (obj == null)
1643 return 1;
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)
1659 return tz;
1662 public static bool operator ==(NpgsqlTimeZone x, NpgsqlTimeZone y)
1664 return x.Equals(y);
1667 public static bool operator !=(NpgsqlTimeZone x, NpgsqlTimeZone y)
1669 return !(x == 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;
1693 [Serializable]
1694 public struct NpgsqlTime : IEquatable<NpgsqlTime>, IComparable<NpgsqlTime>, IComparable, IComparer<NpgsqlTime>,
1695 IComparer
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)
1710 _ticks = ticks;
1712 else
1714 ticks %= NpgsqlInterval.TicksPerDay;
1715 _ticks = ticks < 0 ? ticks + NpgsqlInterval.TicksPerDay : ticks;
1719 public NpgsqlTime(TimeSpan time)
1720 : this(time.Ticks)
1724 public NpgsqlTime(NpgsqlInterval time)
1725 : this(time.Ticks)
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)
1740 : this(
1741 hours*NpgsqlInterval.TicksPerHour + minutes*NpgsqlInterval.TicksPerMinute + seconds*NpgsqlInterval.TicksPerSecond +
1742 microseconds*NpgsqlInterval.TicksPerMicrosecond)
1746 public NpgsqlTime(int hours, int minutes, decimal seconds)
1747 : this(
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)
1758 /// <summary>
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&#xb5;s = 1,000 ns. It may be smaller as follows:
1763 /// <list type="number">
1764 /// <item>
1765 /// <term>time(0)</term>
1766 /// <description>resolution of 1s (1 second)</description>
1767 /// </item>
1768 /// <item>
1769 /// <term>time(1)</term>
1770 /// <description>resolution of 100ms = 0.1s (100 milliseconds)</description>
1771 /// </item>
1772 /// <item>
1773 /// <term>time(2)</term>
1774 /// <description>resolution of 10ms = 0.01s (10 milliseconds)</description>
1775 /// </item>
1776 /// <item>
1777 /// <term>time(3)</term>
1778 /// <description>resolution of 1ms = 0.001s (1 millisecond)</description>
1779 /// </item>
1780 /// <item>
1781 /// <term>time(4)</term>
1782 /// <description>resolution of 100&#xb5;s = 0.0001s (100 microseconds)</description>
1783 /// </item>
1784 /// <item>
1785 /// <term>time(5)</term>
1786 /// <description>resolution of 10&#xb5;s = 0.00001s (10 microseconds)</description>
1787 /// </item>
1788 /// <item>
1789 /// <term>time(6) or interval</term>
1790 /// <description>resolution of 1&#xb5;s = 0.000001s (1 microsecond)</description>
1791 /// </item>
1792 /// </list>
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>
1798 /// </remarks>
1799 /// <returns>The number of ticks in the instance.</returns>
1800 /// </summary>
1801 public long Ticks
1803 get { return _ticks; }
1806 /// <summary>
1807 /// Gets the number of whole microseconds held in the instance.
1808 /// <returns>An integer in the range [0, 999999].</returns>
1809 /// </summary>
1810 public int Microseconds
1812 get { return (int) (_ticks/10)%1000000; }
1815 /// <summary>
1816 /// Gets the number of whole milliseconds held in the instance.
1817 /// <returns>An integer in the range [0, 999].</returns>
1818 /// </summary>
1819 public int Milliseconds
1821 get { return (int) ((_ticks/NpgsqlInterval.TicksPerMillsecond)%1000); }
1824 /// <summary>
1825 /// Gets the number of whole seconds held in the instance.
1826 /// <returns>An interger in the range [0, 59].</returns>
1827 /// </summary>
1828 public int Seconds
1830 get { return (int) ((_ticks/NpgsqlInterval.TicksPerSecond)%60); }
1833 /// <summary>
1834 /// Gets the number of whole minutes held in the instance.
1835 /// <returns>An integer in the range [0, 59].</returns>
1836 /// </summary>
1837 public int Minutes
1839 get { return (int) ((_ticks/NpgsqlInterval.TicksPerMinute)%60); }
1842 /// <summary>
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>
1846 /// </summary>
1847 public int Hours
1849 get { return (int) (_ticks/NpgsqlInterval.TicksPerHour); }
1852 /// <summary>
1853 /// Normalise this time; if it is 24:00:00, convert it to 00:00:00
1854 /// </summary>
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()
1878 StringBuilder sb =
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)
1895 if (str == null)
1897 throw new ArgumentNullException();
1901 int hours = 0;
1902 int minutes = 0;
1903 decimal seconds = 0m;
1904 string[] parts = str.Split(':');
1905 switch (parts.Length) //One of those times that fall-through would actually be good.
1907 case 1:
1908 hours = int.Parse(parts[0]);
1909 break;
1910 case 2:
1911 hours = int.Parse(parts[0]);
1912 minutes = int.Parse(parts[1]);
1913 break;
1914 default:
1915 hours = int.Parse(parts[0]);
1916 minutes = int.Parse(parts[1]);
1917 seconds = decimal.Parse(parts[2]);
1918 break;
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)
1929 throw;
1931 catch
1933 throw new FormatException();
1937 public static bool TryParse(string str, out NpgsqlTime time)
1941 time = Parse(str);
1942 return true;
1944 catch
1946 time = AllBalls;
1947 return false;
1951 public int CompareTo(NpgsqlTime other)
1953 return Ticks.CompareTo(other.Ticks);
1956 public int CompareTo(object obj)
1958 if (obj == null)
1960 return 1;
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)
1976 if (x == null)
1978 return y == null ? 0 : -1;
1980 if (y == null)
1982 return 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)
1993 return x.Equals(y);
1996 public static bool operator !=(NpgsqlTime x, NpgsqlTime y)
1998 return !(x == 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;
2051 if (result < 0)
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);
2104 [Serializable]
2105 public struct NpgsqlTimeTZ : IEquatable<NpgsqlTimeTZ>, IComparable<NpgsqlTimeTZ>, IComparable, IComparer<NpgsqlTimeTZ>,
2106 IComparer
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)
2216 if (str == null)
2218 throw new ArgumentNullException();
2222 int idx = Math.Max(str.IndexOf('+'), str.IndexOf('-'));
2223 if (idx == -1)
2225 throw new FormatException();
2227 return new NpgsqlTimeTZ(NpgsqlTime.Parse(str.Substring(0, idx)), NpgsqlTimeZone.Parse(str.Substring(idx)));
2229 catch (OverflowException)
2231 throw;
2233 catch
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)
2261 return
2262 new NpgsqlTimeTZ(LocalTime.Add(timeZone - (NpgsqlInterval) (_timeZone), out overflow), timeZone);
2265 public long Ticks
2267 get { return _localTime.Ticks; }
2270 /// <summary>
2271 /// Gets the number of whole microseconds held in the instance.
2272 /// <returns>An integer in the range [0, 999999].</returns>
2273 /// </summary>
2274 public int Microseconds
2276 get { return _localTime.Microseconds; }
2279 /// <summary>
2280 /// Gets the number of whole milliseconds held in the instance.
2281 /// <returns>An integer in the range [0, 999].</returns>
2282 /// </summary>
2283 public int Milliseconds
2285 get { return _localTime.Milliseconds; }
2288 /// <summary>
2289 /// Gets the number of whole seconds held in the instance.
2290 /// <returns>An interger in the range [0, 59].</returns>
2291 /// </summary>
2292 public int Seconds
2294 get { return _localTime.Seconds; }
2297 /// <summary>
2298 /// Gets the number of whole minutes held in the instance.
2299 /// <returns>An integer in the range [0, 59].</returns>
2300 /// </summary>
2301 public int Minutes
2303 get { return _localTime.Minutes; }
2306 /// <summary>
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>
2310 /// </summary>
2311 public int Hours
2313 get { return _localTime.Hours; }
2316 /// <summary>
2317 /// Normalise this time; if it is 24:00:00, convert it to 00:00:00
2318 /// </summary>
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);
2340 /// <summary>
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).
2344 /// </summary>
2345 /// <param name="other">the <see cref="NpgsqlTimeTZ"/> to compare with.</param>
2346 /// <returns>An integer which is 0 if they are equal, &lt; 0 if this is the smaller and &gt; 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)
2355 if (obj == null)
2357 return 1;
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)
2373 if (x == null)
2375 return y == null ? 0 : -1;
2377 if (y == null)
2379 return 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)
2390 return x.Equals(y);
2393 public static bool operator !=(NpgsqlTimeTZ x, NpgsqlTimeTZ y)
2395 return !(x == 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;
2469 [Serializable]
2470 public struct NpgsqlTimeStamp : IEquatable<NpgsqlTimeStamp>, IComparable<NpgsqlTimeStamp>, IComparable,
2471 IComparer<NpgsqlTimeStamp>, IComparer
2473 private enum TimeType
2475 Finite,
2476 Infinity,
2477 MinusInfinity
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)
2515 _type = type;
2516 _date = date;
2517 _time = 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; }
2550 public int Year
2552 get { return _date.Year; }
2555 public int Month
2557 get { return _date.Month; }
2560 public int Day
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)
2577 switch (_type)
2579 case TimeType.Infinity:
2580 case TimeType.MinusInfinity:
2581 return this;
2582 default:
2583 return new NpgsqlTimeStamp(_date.AddDays(days), _time);
2587 public NpgsqlTimeStamp AddYears(int years)
2589 switch (_type)
2591 case TimeType.Infinity:
2592 case TimeType.MinusInfinity:
2593 return this;
2594 default:
2595 return new NpgsqlTimeStamp(_date.AddYears(years), _time);
2599 public NpgsqlTimeStamp AddMonths(int months)
2601 switch (_type)
2603 case TimeType.Infinity:
2604 case TimeType.MinusInfinity:
2605 return this;
2606 default:
2607 return new NpgsqlTimeStamp(_date.AddMonths(months), _time);
2611 public long Ticks
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; }
2626 public int Seconds
2628 get { return _time.Seconds; }
2631 public int Minutes
2633 get { return _time.Minutes; }
2636 public int Hours
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()
2663 switch (_type)
2665 case TimeType.Infinity:
2666 return "infinity";
2667 case TimeType.MinusInfinity:
2668 return "-infinity";
2669 default:
2670 return string.Format("{0} {1}", _date, _time);
2674 public static NpgsqlTimeStamp Parse(string str)
2676 if (str == null)
2678 throw new NullReferenceException();
2680 switch (str = str.Trim().ToLowerInvariant())
2682 case "infinity":
2683 return Infinity;
2684 case "-infinity":
2685 return MinusInfinity;
2686 default:
2689 int idxSpace = str.IndexOf(' ');
2690 string datePart = str.Substring(0, idxSpace);
2691 if (str.Contains("bc"))
2693 datePart += " 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)
2705 throw;
2707 catch
2709 throw new FormatException();
2714 public bool Equals(NpgsqlTimeStamp other)
2716 switch (_type)
2718 case TimeType.Infinity:
2719 return other._type == TimeType.Infinity;
2720 case TimeType.MinusInfinity:
2721 return other._type == TimeType.MinusInfinity;
2722 default:
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()
2734 switch (_type)
2736 case TimeType.Infinity:
2737 return int.MaxValue;
2738 case TimeType.MinusInfinity:
2739 return int.MinValue;
2740 default:
2741 return _date.GetHashCode() ^ PGUtil.RotateShift(_time.GetHashCode(), 16);
2745 public int CompareTo(NpgsqlTimeStamp other)
2747 switch (_type)
2749 case TimeType.Infinity:
2750 return other._type == TimeType.Infinity ? 0 : 1;
2751 case TimeType.MinusInfinity:
2752 return other._type == TimeType.MinusInfinity ? 0 : -1;
2753 default:
2754 switch (other._type)
2756 case TimeType.Infinity:
2757 return -1;
2758 case TimeType.MinusInfinity:
2759 return 1;
2760 default:
2761 int cmp = _date.CompareTo(other._date);
2762 return cmp == 0 ? _time.CompareTo(_time) : cmp;
2767 public int CompareTo(object obj)
2769 if (obj == null)
2771 return 1;
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)
2787 if (x == null)
2789 return y == null ? 0 : -1;
2791 if (y == null)
2793 return 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)
2804 int overflow;
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)
2816 switch (_type)
2818 case TimeType.Infinity:
2819 case TimeType.MinusInfinity:
2820 return this;
2821 default:
2822 int overflow;
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)
2835 switch (_type)
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)
2854 return Infinity;
2856 else if (datetime == DateTime.MinValue)
2858 return MinusInfinity;
2860 else
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;
2874 default:
2877 return
2878 new DateTime(timestamp.Date.DaysSinceEra*NpgsqlInterval.TicksPerDay + timestamp._time.Ticks,
2879 DateTimeKind.Unspecified);
2881 catch
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)
2910 return x.Equals(y);
2913 public static bool operator !=(NpgsqlTimeStamp x, NpgsqlTimeStamp y)
2915 return !(x == 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;
2939 [Serializable]
2940 public struct NpgsqlTimeStampTZ : IEquatable<NpgsqlTimeStampTZ>, IComparable<NpgsqlTimeStampTZ>, IComparable,
2941 IComparer<NpgsqlTimeStampTZ>, IComparer
2943 private enum TimeType
2945 Finite,
2946 Infinity,
2947 MinusInfinity
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)
2985 _type = type;
2986 _date = date;
2987 _time = 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)
3001 : this(
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; }
3024 public int Year
3026 get { return _date.Year; }
3029 public int Month
3031 get { return _date.Month; }
3034 public int Day
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)
3051 switch (_type)
3053 case TimeType.Infinity:
3054 case TimeType.MinusInfinity:
3055 return this;
3056 default:
3057 return new NpgsqlTimeStampTZ(_date.AddDays(days), _time);
3061 public NpgsqlTimeStampTZ AddYears(int years)
3063 switch (_type)
3065 case TimeType.Infinity:
3066 case TimeType.MinusInfinity:
3067 return this;
3068 default:
3069 return new NpgsqlTimeStampTZ(_date.AddYears(years), _time);
3073 public NpgsqlTimeStampTZ AddMonths(int months)
3075 switch (_type)
3077 case TimeType.Infinity:
3078 case TimeType.MinusInfinity:
3079 return this;
3080 default:
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; }
3100 public long Ticks
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; }
3115 public int Seconds
3117 get { return _time.Seconds; }
3120 public int Minutes
3122 get { return _time.Minutes; }
3125 public int Hours
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()
3152 switch (_type)
3154 case TimeType.Infinity:
3155 return "infinity";
3156 case TimeType.MinusInfinity:
3157 return "-infinity";
3158 default:
3159 return string.Format("{0} {1}", _date, _time);
3163 public static NpgsqlTimeStampTZ Parse(string str)
3165 if (str == null)
3167 throw new NullReferenceException();
3169 switch (str = str.Trim().ToLowerInvariant())
3171 case "infinity":
3172 return Infinity;
3173 case "-infinity":
3174 return MinusInfinity;
3175 default:
3178 int idxSpace = str.IndexOf(' ');
3179 string datePart = str.Substring(0, idxSpace);
3180 if (str.Contains("bc"))
3182 datePart += " 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)
3194 throw;
3196 catch
3198 throw new FormatException();
3203 public bool Equals(NpgsqlTimeStampTZ other)
3205 switch (_type)
3207 case TimeType.Infinity:
3208 return other._type == TimeType.Infinity;
3209 case TimeType.MinusInfinity:
3210 return other._type == TimeType.MinusInfinity;
3211 default:
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()
3223 switch (_type)
3225 case TimeType.Infinity:
3226 return int.MaxValue;
3227 case TimeType.MinusInfinity:
3228 return int.MinValue;
3229 default:
3230 return _date.GetHashCode() ^ PGUtil.RotateShift(_time.GetHashCode(), 16);
3234 public int CompareTo(NpgsqlTimeStampTZ other)
3236 switch (_type)
3238 case TimeType.Infinity:
3239 return other._type == TimeType.Infinity ? 0 : 1;
3240 case TimeType.MinusInfinity:
3241 return other._type == TimeType.MinusInfinity ? 0 : -1;
3242 default:
3243 switch (other._type)
3245 case TimeType.Infinity:
3246 return -1;
3247 case TimeType.MinusInfinity:
3248 return 1;
3249 default:
3250 int cmp = _date.CompareTo(other._date);
3251 return cmp == 0 ? _time.CompareTo(_time) : cmp;
3256 public int CompareTo(object obj)
3258 if (obj == null)
3260 return 1;
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)
3276 if (x == null)
3278 return y == null ? 0 : -1;
3280 if (y == null)
3282 return 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)
3293 int overflow;
3294 NpgsqlTimeTZ adjusted = _time.AtTimeZone(timeZone, out overflow);
3295 return new NpgsqlTimeStamp(_date.AddDays(overflow), adjusted.LocalTime);
3298 public NpgsqlTimeStampTZ Add(NpgsqlInterval interval)
3300 switch (_type)
3302 case TimeType.Infinity:
3303 case TimeType.MinusInfinity:
3304 return this;
3305 default:
3306 int overflow;
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)
3319 switch (_type)
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)
3338 return Infinity;
3340 else if (datetime == DateTime.MinValue)
3342 return MinusInfinity;
3344 else
3346 NpgsqlDate newDate = new NpgsqlDate(datetime);
3347 return
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;
3364 default:
3367 NpgsqlTimeStamp utc = timestamp.AtTimeZone(NpgsqlTimeZone.UTC);
3368 return new DateTime(utc.Date.DaysSinceEra*NpgsqlInterval.TicksPerDay + utc.Time.Ticks, DateTimeKind.Utc);
3370 catch
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)
3399 return x.Equals(y);
3402 public static bool operator !=(NpgsqlTimeStampTZ x, NpgsqlTimeStampTZ y)
3404 return !(x == 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;