More tests.
[mono.git] / mcs / class / System.Data / System.Data.SqlTypes / SqlDateTime.cs
1 //
2 // System.Data.SqlTypes.SqlDateTime
3 //
4 // Author:
5 //   Tim Coleman <tim@timcoleman.com>
6 //   Ville Palo <vi64pa@koti.soon.fi>
7 //
8 // (C) Copyright 2002 Tim Coleman
9 //
10
11 //
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33
34 using System;
35 using System.Xml;
36 using System.Xml.Schema;
37 using System.Globalization;
38 using System.Xml.Serialization;
39
40 namespace System.Data.SqlTypes
41 {
42 #if NET_2_0
43         [SerializableAttribute]
44         [XmlSchemaProvider ("GetXsdType")]
45 #endif
46         public struct SqlDateTime : INullable, IComparable
47 #if NET_2_0
48                                 , IXmlSerializable
49 #endif
50         {
51                 #region Fields
52
53                 private DateTime value;
54                 private bool notNull;
55
56                 public static readonly SqlDateTime MaxValue;
57                 public static readonly SqlDateTime MinValue;
58                 public static readonly SqlDateTime Null;
59                 public static readonly int SQLTicksPerHour = 1080000;
60                 public static readonly int SQLTicksPerMinute = 18000;
61                 public static readonly int SQLTicksPerSecond = 300;
62
63                 static readonly DateTime zero_day = new DateTime (1900, 1, 1);
64
65                 #endregion
66
67                 #region Constructors
68
69                 static SqlDateTime ()
70                 {
71                         DateTime t = new DateTime (9999, 12, 31, 23, 59, 59);
72                         long ticks = (long) (t.Ticks + (997 * 10000));
73                         MaxValue.value = new DateTime (ticks);
74                         MaxValue.notNull = true;
75
76                         MinValue.value = new DateTime (1753, 1, 1);
77                         MinValue.notNull = true;
78                 }
79
80                 public SqlDateTime (DateTime value)
81                 {
82                         this.value = value;
83                         notNull = true;
84                         CheckRange (this);
85                 }
86
87                 public SqlDateTime (int dayTicks, int timeTicks)
88                 {
89                         try {
90                                 long ms = SQLTicksToMilliseconds (timeTicks);
91                                 this.value = zero_day.AddDays (dayTicks).AddMilliseconds (ms);
92                         } catch (ArgumentOutOfRangeException ex) {
93                                 throw new SqlTypeException (ex.Message);
94                         }
95                         notNull = true;
96                         CheckRange (this);
97                 }
98
99                 public SqlDateTime (int year, int month, int day)
100                 {
101                         try {
102                                 this.value = new DateTime (year, month, day);
103                         } catch (ArgumentOutOfRangeException ex) {
104                                 throw new SqlTypeException (ex.Message);
105                         }
106                         notNull = true;
107                         CheckRange (this);
108                 }
109
110                 public SqlDateTime (int year, int month, int day, int hour, int minute, int second)
111                 {
112                         try {
113                                 this.value = new DateTime (year, month, day, hour, minute, second);
114                         } catch (ArgumentOutOfRangeException ex) {
115                                 throw new SqlTypeException (ex.Message);
116                         }
117                         notNull = true;
118                         CheckRange (this);
119                 }
120
121                 static int TimeSpanTicksToSQLTicks (long ticks)
122                 {
123                         return (int) ((ticks * SQLTicksPerSecond) / TimeSpan.TicksPerSecond);
124                 }
125
126                 static long SQLTicksToMilliseconds (int timeTicks)
127                 {
128                         return (long) (((timeTicks * 1000.0) / SQLTicksPerSecond) + 0.5);
129                 }
130
131                 public SqlDateTime (int year, int month, int day, int hour, int minute, int second, double millisecond)
132                 {
133                         try {
134                                 long ticks = (long) (millisecond * TimeSpan.TicksPerMillisecond);
135                                 long ms = SQLTicksToMilliseconds (TimeSpanTicksToSQLTicks (ticks));
136                                 this.value = new DateTime (year, month, day, hour, minute, second).AddMilliseconds (ms);
137                         } catch (ArgumentOutOfRangeException ex) {
138                                 throw new SqlTypeException (ex.Message);
139                         }
140                         notNull = true;
141                         CheckRange (this);
142                 }
143
144                 // Some genius in MS came up with 'bilisecond', and gave it the ambiguous definition of one-"billionth"
145                 // of a second.  I'm almost tempted to use a nanosecond or a picosecond depending on the current culture :-)
146                 // But, wait!! it turns out it's a microsecond, in reality.  AAAAAAAAAAAARGH.  Did this misguided
147                 // individual think that a millisecond is a millionth of a second and thus come up with the dastardly name
148                 // and the very wrong definition?
149                 public SqlDateTime (int year, int month, int day, int hour, int minute, int second, int bilisecond)
150                 {
151                         try {
152                                 long ticks = bilisecond * 10;
153                                 long ms = SQLTicksToMilliseconds (TimeSpanTicksToSQLTicks (ticks));
154                                 this.value = new DateTime (year, month, day, hour, minute, second).AddMilliseconds (ms);
155                         } catch (ArgumentOutOfRangeException ex) {
156                                 throw new SqlTypeException (ex.Message);
157                         }
158                         notNull = true;
159                         CheckRange (this);
160                 }
161
162                 #endregion
163
164                 #region Properties
165
166                 public int DayTicks {
167                         get { return (Value - zero_day).Days; }
168                 }
169
170                 public bool IsNull {
171                         get { return !notNull; }
172                 }
173
174                 public int TimeTicks {
175                         get { return TimeSpanTicksToSQLTicks (Value.TimeOfDay.Ticks); }
176                 }
177
178                 public DateTime Value {
179                         get {
180                                 if (this.IsNull) 
181                                         throw new SqlNullValueException ("The property contains Null.");
182                                 return value; 
183                         }
184                 }
185
186                 #endregion
187
188                 #region Methods
189
190                 private static void CheckRange (SqlDateTime target)
191                 {
192                         if (target.IsNull)
193                                 return;
194                         if (target.value > MaxValue.value || target.value < MinValue.value)
195                                 throw new SqlTypeException (String.Format ("SqlDateTime overflow. Must be between {0} and {1}. Value was {2}", MinValue.Value, MaxValue.Value, target.value));
196                 }
197
198                 public int CompareTo (object value)
199                 {
200                         if (value == null)
201                                 return 1;
202                         if (!(value is SqlDateTime))
203                                 throw new ArgumentException (Locale.GetText ("Value is not a System.Data.SqlTypes.SqlDateTime"));
204
205                         return CompareTo ((SqlDateTime) value);
206                 }
207
208 #if NET_2_0
209                 public
210 #endif
211                 int CompareTo (SqlDateTime value)
212                 {
213                         if (value.IsNull)
214                                 return 1;
215                         else
216                                 return this.value.CompareTo (value.Value);
217                 }
218
219                 public override bool Equals (object value)
220                 {
221                         if (!(value is SqlDateTime))
222                                 return false;
223                         else if (this.IsNull)
224                                 return ((SqlDateTime)value).IsNull;
225                         else if (((SqlDateTime)value).IsNull)
226                                 return false;
227                         else
228                                 return (bool) (this == (SqlDateTime)value);
229                 }
230
231                 public static SqlBoolean Equals (SqlDateTime x, SqlDateTime y)
232                 {
233                         return (x == y);
234                 }
235
236                 public override int GetHashCode ()
237                 {
238                         return value.GetHashCode ();
239                 }
240
241 #if NET_2_0
242                 public static SqlDateTime Add (SqlDateTime x, TimeSpan t)
243                 {
244                         return (x + t);
245                 }
246
247                 public static SqlDateTime Subtract (SqlDateTime x, TimeSpan t)
248                 {
249                         return (x - t);
250                 }
251 #endif
252
253                 public static SqlBoolean GreaterThan (SqlDateTime x, SqlDateTime y)
254                 {
255                         return (x > y);
256                 }
257
258                 public static SqlBoolean GreaterThanOrEqual (SqlDateTime x, SqlDateTime y)
259                 {
260                         return (x >= y);
261                 }
262
263                 public static SqlBoolean LessThan (SqlDateTime x, SqlDateTime y)
264                 {
265                         return (x < y);
266                 }
267
268                 public static SqlBoolean LessThanOrEqual (SqlDateTime x, SqlDateTime y)
269                 {
270                         return (x <= y);
271                 }
272
273                 public static SqlBoolean NotEquals (SqlDateTime x, SqlDateTime y)
274                 {
275                         return (x != y);
276                 }
277
278                 public static SqlDateTime Parse (string s)
279                 {
280                         if (s == null)
281                                 throw new ArgumentNullException ("Argument cannot be null");
282
283                         // try parsing in local culture
284                         DateTimeFormatInfo fmtInfo = DateTimeFormatInfo.CurrentInfo;
285                         try {
286                                 return new SqlDateTime (DateTime.Parse (s, fmtInfo));
287                         } catch (Exception) {
288                         }
289
290                         // try parsing in invariant culture
291                         try {
292                                 return new SqlDateTime (DateTime.Parse (s, CultureInfo.InvariantCulture));
293                         } catch (Exception) {
294                         }
295
296                         throw new FormatException (String.Format ("String {0}" +
297                                 " is not recognized as valid DateTime.", s));
298                 }
299
300                 public SqlString ToSqlString ()
301                 {
302                         return ((SqlString) this);
303                 }
304
305                 public override string ToString ()
306                 {
307                         if (this.IsNull)
308                                 return "Null";
309                         else
310                                 return value.ToString (CultureInfo.InvariantCulture);
311                 }
312         
313                 public static SqlDateTime operator + (SqlDateTime x, TimeSpan t)
314                 {
315                         if (x.IsNull)
316                                 return SqlDateTime.Null;
317                         return new SqlDateTime (x.Value + t);
318                 }
319
320                 public static SqlBoolean operator == (SqlDateTime x, SqlDateTime y)
321                 {
322                         if (x.IsNull || y.IsNull)
323                                 return SqlBoolean.Null;
324                         return new SqlBoolean (x.Value == y.Value);
325                 }
326
327                 public static SqlBoolean operator > (SqlDateTime x, SqlDateTime y)
328                 {
329                         if (x.IsNull || y.IsNull)
330                                 return SqlBoolean.Null;
331                         return new SqlBoolean (x.Value > y.Value);
332                 }
333
334                 public static SqlBoolean operator >= (SqlDateTime x, SqlDateTime y)
335                 {
336                         if (x.IsNull || y.IsNull)
337                                 return SqlBoolean.Null;
338                         return new SqlBoolean (x.Value >= y.Value);
339                 }
340
341                 public static SqlBoolean operator != (SqlDateTime x, SqlDateTime y)
342                 {
343                         if (x.IsNull || y.IsNull)
344                                 return SqlBoolean.Null;
345                         return new SqlBoolean (!(x.Value == y.Value));
346                 }
347
348                 public static SqlBoolean operator < (SqlDateTime x, SqlDateTime y)
349                 {
350                         if (x.IsNull || y.IsNull)
351                                 return SqlBoolean.Null;
352                         return new SqlBoolean (x.Value < y.Value);
353                 }
354
355                 public static SqlBoolean operator <= (SqlDateTime x, SqlDateTime y)
356                 {
357                         if (x.IsNull || y.IsNull)
358                                 return SqlBoolean.Null;
359                         return new SqlBoolean (x.Value <= y.Value);
360                 }
361
362                 public static SqlDateTime operator - (SqlDateTime x, TimeSpan t)
363                 {
364                         if (x.IsNull)
365                                 return x;
366                         return new SqlDateTime (x.Value - t);
367                 }
368
369                 public static explicit operator DateTime (SqlDateTime x)
370                 {
371                         return x.Value;
372                 }
373
374                 public static explicit operator SqlDateTime (SqlString x)
375                 {
376                         return SqlDateTime.Parse (x.Value);
377                 }
378
379                 public static implicit operator SqlDateTime (DateTime value)
380                 {
381                         return new SqlDateTime (value);
382                 }
383
384 #if NET_2_0
385                 public static XmlQualifiedName GetXsdType (XmlSchemaSet schemaSet)
386                 {
387                         XmlQualifiedName qualifiedName = new XmlQualifiedName ("dateTime", "http://www.w3.org/2001/XMLSchema");
388                         return qualifiedName;
389                 }
390                 
391                 [MonoTODO]
392                 XmlSchema IXmlSerializable.GetSchema ()
393                 {
394                         throw new NotImplementedException ();
395                 }
396                 
397                 [MonoTODO]
398                 void IXmlSerializable.ReadXml (XmlReader reader)
399                 {
400                         throw new NotImplementedException ();
401                 }
402                 
403                 [MonoTODO]
404                 void IXmlSerializable.WriteXml (XmlWriter writer) 
405                 {
406                         throw new NotImplementedException ();
407                 }
408 #endif
409
410                 #endregion
411         }
412 }