DeveelDB  20151217
complete SQL database system, primarly developed for .NET/Mono frameworks
SqlDateTime.cs
Go to the documentation of this file.
1 //
2 // Copyright 2010-2015 Deveel
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 using System;
18 using System.Globalization;
19 
20 namespace Deveel.Data.Sql.Objects {
21  public struct SqlDateTime : ISqlObject, IEquatable<SqlDateTime>, IConvertible, IComparable<SqlDateTime> {
22  private readonly DateTimeOffset? value;
23 
24  public static readonly SqlDateTime Null = new SqlDateTime(true);
25 
26  private const int DateSize = 7;
27  private const int TimeStampSize = 11;
28  private const int FullTimeStampSize = 13;
29 
30  public static readonly string[] SqlDateFormats = new[] {
31  "yyyy-MM-dd",
32  "yyyy MM dd"
33  };
34 
35  public static readonly string[] SqlTimeStampFormats = new[] {
36  "yyyy-MM-dd HH:mm:ss.fff",
37  "yyyy-MM-dd HH:mm:ss.fff z",
38  "yyyy-MM-dd HH:mm:ss.fff zz",
39  "yyyy-MM-dd HH:mm:ss.fff zzz",
40  "yyyy-MM-dd HH:mm:ss",
41  "yyyy-MM-dd HH:mm:ss z",
42  "yyyy-MM-dd HH:mm:ss zz",
43  "yyyy-MM-dd HH:mm:ss zzz",
44 
45  "yyyy-MM-ddTHH:mm:ss.fff",
46  "yyyy-MM-ddTHH:mm:ss.fff z",
47  "yyyy-MM-ddTHH:mm:ss.fff zz",
48  "yyyy-MM-ddTHH:mm:ss.fff zzz",
49  "yyyy-MM-ddTHH:mm:ss",
50  "yyyy-MM-ddTHH:mm:ss z",
51  "yyyy-MM-ddTHH:mm:ss zz",
52  "yyyy-MM-ddTHH:mm:ss zzz",
53  };
54 
55  public static readonly string[] SqlTimeFormats = new[] {
56  "HH:mm:ss.fff z",
57  "HH:mm:ss.fff zz",
58  "HH:mm:ss.fff zzz",
59  "HH:mm:ss.fff",
60  "HH:mm:ss z",
61  "HH:mm:ss zz",
62  "HH:mm:ss zzz",
63  "HH:mm:ss"
64  };
65 
66  public const string TimeStringFormat = "HH:mm:ss.fff zzz";
67  public const string TimeStampStringFormat = "yyyy-MM-ddTHH:mm:ss.fff zzz";
68  public const string DateStringFormat = "yyyy-MM-dd";
69 
70  public static readonly SqlDateTime MaxDate = new SqlDateTime(9999, 12, 31, 23, 59, 59, 999);
71  public static readonly SqlDateTime MinDate = new SqlDateTime(1, 1, 1, 0, 0, 0, 0);
72 
73  public SqlDateTime(int year, int month, int day)
74  : this(year, month, day, 0, 0, 0, 0, SqlDayToSecond.Zero) {
75  }
76 
77  public SqlDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond)
78  : this(year, month, day, hour, minute, second, millisecond, SqlDayToSecond.Zero) {
79  }
80 
81  public SqlDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, SqlDayToSecond offset)
82  : this() {
83  if (year <= 0 || year > 9999)
84  throw new ArgumentOutOfRangeException("year");
85  if (month <= 0 || month > 12)
86  throw new ArgumentOutOfRangeException("month");
87  if (day <= 0 || day > 31)
88  throw new ArgumentOutOfRangeException("day");
89 
90  if (hour < 0 || hour > 23)
91  throw new ArgumentOutOfRangeException("hour");
92  if (minute < 0 || minute > 59)
93  throw new ArgumentOutOfRangeException("minute");
94  if (second < 0 || second > 59)
95  throw new ArgumentOutOfRangeException("second");
96  if (millisecond < 0 || millisecond > 999)
97  throw new ArgumentOutOfRangeException("millisecond");
98 
99  var tsOffset = new TimeSpan(0, offset.Hours, offset.Minutes, 0, 0);
100  value = new DateTimeOffset(year, month, day, hour, minute, second, millisecond, tsOffset);
101  }
102 
103  public SqlDateTime(long ticks)
104  : this(ticks, SqlDayToSecond.Zero) {
105  }
106 
107  public SqlDateTime(long ticks, SqlDayToSecond offset)
108  : this() {
109  var tsOffset = new TimeSpan(0, offset.Hours, offset.Minutes, 0);
110  value = new DateTimeOffset(ticks, tsOffset);
111  }
112 
113  private SqlDateTime(bool isNull)
114  : this() {
115  if (isNull)
116  value = null;
117  }
118 
119  public SqlDateTime(byte[] bytes)
120  : this() {
121  var year = ((bytes[0] - 100)*100) + (bytes[1] - 100);
122  var month = (int) bytes[2];
123  var day = (int) bytes[3];
124  var hour = (int) bytes[4] - 1;
125  var minute = (int)bytes[5] - 1;
126  var second = (int)bytes[6] - 1;
127  int millis;
128  int tzh = 0, tzm = 0;
129 
130  if (bytes.Length == DateSize) {
131  millis = 0;
132  } else {
133  millis = bytes[7] << 24 | bytes[8] << 16 | bytes[9] << 8 | bytes[10];
134  if (bytes.Length == TimeStampSize) {
135  tzh = tzm = 0;
136  } else {
137  tzh = bytes[11] - 20;
138  tzm = bytes[12] - 60;
139  }
140  }
141 
142  value = new DateTimeOffset(year, month, day, hour, minute, second, millis, new TimeSpan(0, tzh, tzm, 0, 0));
143  }
144 
145  int IComparable.CompareTo(object obj) {
146  return CompareTo((SqlDateTime) obj);
147  }
148 
149  int IComparable<ISqlObject>.CompareTo(ISqlObject other) {
150  return CompareTo((SqlDateTime) other);
151  }
152 
153  public bool IsNull {
154  get { return value == null; }
155  }
156 
157  private void AssertNotNull() {
158  if (value == null)
159  throw new InvalidOperationException();
160  }
161 
162  public int Year {
163  get {
164  AssertNotNull();
165  return value.Value.Year;
166  }
167  }
168 
169  public int Month {
170  get {
171  AssertNotNull();
172  return value.Value.Month;
173  }
174  }
175 
176  public int Day {
177  get {
178  AssertNotNull();
179  return value.Value.Day;
180  }
181  }
182 
183  public int Hour {
184  get {
185  AssertNotNull();
186  return value.Value.Hour;
187  }
188  }
189 
190  public int Minute {
191  get {
192  AssertNotNull();
193  return value.Value.Minute;
194  }
195  }
196 
197  public int Second {
198  get {
199  AssertNotNull();
200  return value.Value.Second;
201  }
202  }
203 
204  public int Millisecond {
205  get {
206  AssertNotNull();
207  return value.Value.Millisecond;
208  }
209  }
210 
214  public SqlDayToSecond Offset {
215  get {
216  AssertNotNull();
217  return new SqlDayToSecond(0, value.Value.Offset.Hours, value.Value.Offset.Minutes, 0, 0);
218  }
219  }
220 
221  public static SqlDateTime Now {
222  get {
223  var date = DateTimeOffset.Now;
224  var offset = new SqlDayToSecond(date.Offset.Days, date.Offset.Hours, date.Offset.Minutes, date.Minute);
225  return new SqlDateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, date.Millisecond, offset);
226  }
227  }
228 
230  return other is SqlDateTime;
231  }
232 
233  TypeCode IConvertible.GetTypeCode() {
234  return TypeCode.DateTime;
235  }
236 
237  bool IConvertible.ToBoolean(IFormatProvider provider) {
238  throw new InvalidCastException();
239  }
240 
241  char IConvertible.ToChar(IFormatProvider provider) {
242  throw new InvalidCastException();
243  }
244 
245  sbyte IConvertible.ToSByte(IFormatProvider provider) {
246  throw new NotImplementedException();
247  }
248 
249  byte IConvertible.ToByte(IFormatProvider provider) {
250  throw new InvalidCastException();
251  }
252 
253  short IConvertible.ToInt16(IFormatProvider provider) {
254  throw new InvalidCastException();
255  }
256 
257  ushort IConvertible.ToUInt16(IFormatProvider provider) {
258  throw new InvalidCastException();
259  }
260 
261  int IConvertible.ToInt32(IFormatProvider provider) {
262  throw new InvalidCastException();
263  }
264 
265  uint IConvertible.ToUInt32(IFormatProvider provider) {
266  throw new InvalidCastException();
267  }
268 
269  long IConvertible.ToInt64(IFormatProvider provider) {
270  return ToInt64();
271  }
272 
273  ulong IConvertible.ToUInt64(IFormatProvider provider) {
274  return (ulong) ToInt64();
275  }
276 
277  float IConvertible.ToSingle(IFormatProvider provider) {
278  return ToInt64();
279  }
280 
281  double IConvertible.ToDouble(IFormatProvider provider) {
282  return ToInt64();
283  }
284 
285  decimal IConvertible.ToDecimal(IFormatProvider provider) {
286  throw new NotImplementedException();
287  }
288 
289  DateTime IConvertible.ToDateTime(IFormatProvider provider) {
290  if (value == null)
291  throw new NullReferenceException();
292 
293  return value.Value.DateTime;
294  }
295 
296  string IConvertible.ToString(IFormatProvider provider) {
297  return ToString();
298  }
299 
300  object IConvertible.ToType(Type conversionType, IFormatProvider provider) {
301  if (conversionType == typeof (long))
302  return ToInt64();
303  if (conversionType == typeof (float))
304  return (float) ToInt64();
305  if (conversionType == typeof (double))
306  return (double) ToInt64();
307 
308  if (conversionType == typeof (string))
309  return ToString();
310 
311  if (conversionType == typeof (byte[]))
312  return ToByteArray();
313 
314  throw new InvalidCastException();
315  }
316 
317  public bool Equals(SqlDateTime other) {
318  if (IsNull && other.IsNull)
319  return true;
320 
321  return value.Equals(other.value);
322  }
323 
324  public override bool Equals(object obj) {
325  return Equals((SqlDateTime) obj);
326  }
327 
328  public override int GetHashCode() {
329  return value == null ? 0 : value.GetHashCode();
330  }
331 
332  public int CompareTo(SqlDateTime other) {
333  if (!value.HasValue && !other.value.HasValue)
334  return 0;
335  if (!value.HasValue)
336  return 1;
337  if (!other.value.HasValue)
338  return -1;
339 
340  return value.Value.CompareTo(other.value.Value);
341  }
342 
343  public long ToInt64() {
344  AssertNotNull();
345  return value.Value.Ticks;
346  }
347 
348  public byte[] ToByteArray() {
349  return ToByteArray(false);
350  }
351 
352  public byte[] ToByteArray(bool timeZone) {
353  var size = timeZone ? 13 : 11;
354  if (IsNull)
355  return new byte[size];
356 
357  var bytes = new byte[size];
358  bytes[0] = (byte)((Year / 100) + 100);
359  bytes[1] = (byte)((Year % 100) + 100);
360  bytes[2] = (byte)(Month);
361  bytes[3] = (byte)(Day);
362  bytes[4] = (byte)(Hour + 1);
363  bytes[5] = (byte)(Minute + 1);
364  bytes[6] = (byte)(Second + 1);
365  bytes[7] = (byte)((Millisecond >> 24));
366  bytes[8] = (byte)((Millisecond >> 16) & 0xff);
367  bytes[9] = (byte)((Millisecond >> 8) & 0xff);
368  bytes[10]= (byte)(Millisecond & 0xff);
369  if (timeZone) {
370  var tsOffset = Offset;
371  bytes[11] = (byte)(tsOffset.Hours + 20);
372  bytes[12] = (byte)(tsOffset.Minutes + 60);
373  }
374  return bytes;
375  }
376 
390  public SqlDateTime Add(SqlDayToSecond interval) {
391  if (IsNull)
392  return Null;
393  if (interval.IsNull)
394  return this;
395 
396  var result = value.Value.AddMilliseconds(interval.TotalMilliseconds);
397  return new SqlDateTime(result.Ticks);
398  }
399 
410  if (IsNull)
411  return Null;
412  if (interval.IsNull)
413  return this;
414 
415  var result = value.Value.AddMilliseconds(-(interval.TotalMilliseconds));
416  return new SqlDateTime(result.Ticks);
417  }
418 
425  public SqlDateTime Add(SqlYearToMonth interval) {
426  if (IsNull)
427  return Null;
428  if (interval.IsNull)
429  return this;
430 
431  var result = value.Value.AddMonths(interval.TotalMonths);
432  return new SqlDateTime(result.Ticks);
433  }
434 
436  if (IsNull)
437  return Null;
438  if (interval.IsNull)
439  return this;
440 
441  var result = value.Value.AddMonths(-interval.TotalMonths);
442  return new SqlDateTime(result.Ticks);
443  }
444 
445  public static bool operator ==(SqlDateTime a, SqlDateTime b) {
446  return a.Equals(b);
447  }
448 
449  public static bool operator !=(SqlDateTime a, SqlDateTime b) {
450  return !(a == b);
451  }
452 
453  public static bool operator >(SqlDateTime a, SqlDateTime b) {
454  return a.CompareTo(b) > 0;
455  }
456 
457  public static bool operator <(SqlDateTime a, SqlDateTime b) {
458  return a.CompareTo(b) < 0;
459  }
460 
461  public static bool operator >=(SqlDateTime a, SqlDateTime b) {
462  var i = a.CompareTo(b);
463  return i == 0 || i > 0;
464  }
465 
466  public static bool operator <=(SqlDateTime a, SqlDateTime b) {
467  var i = a.CompareTo(b);
468  return i == 0 || i < 0;
469  }
470 
471  public static SqlDateTime operator +(SqlDateTime a, SqlDayToSecond b) {
472  return a.Add(b);
473  }
474 
475  public static SqlDateTime operator -(SqlDateTime a, SqlDayToSecond b) {
476  return a.Subtract(b);
477  }
478 
479  public static SqlDateTime operator +(SqlDateTime a, SqlYearToMonth b) {
480  return a.Add(b);
481  }
482 
483  public static SqlDateTime operator -(SqlDateTime a, SqlYearToMonth b) {
484  return a.Subtract(b);
485  }
486 
487  public static SqlDateTime Parse(string s) {
488  SqlDateTime date;
489  if (!TryParse(s, out date))
490  throw new FormatException(String.Format("Cannot convert string {0} to a valid SQL DATE", s));
491 
492  return date;
493  }
494 
495  public static bool TryParse(string s, out SqlDateTime value) {
496  // We delegate parsing DATE and TIME strings to the .NET DateTime object...
497  if (TryParseDate(s, out value))
498  return true;
499 
500  if (TryParseTime(s, out value))
501  return true;
502 
503  if (TryParseTimeStamp(s, out value))
504  return true;
505 
506  value = new SqlDateTime();
507  return false;
508  }
509 
510  public static bool TryParseDate(string s, out SqlDateTime value) {
511  value = new SqlDateTime();
512 
513  // We delegate parsing DATE and TIME strings to the .NET DateTime object...
514  DateTimeOffset date;
515  if (DateTimeOffset.TryParseExact(s, SqlDateFormats, CultureInfo.InvariantCulture, DateTimeStyles.None, out date)) {
516  value = new SqlDateTime(date.Year, date.Month, date.Day, 0, 0, 0, 0, SqlDayToSecond.Zero);
517  return true;
518  }
519 
520  return false;
521  }
522 
523  public static bool TryParseTime(string s, out SqlDateTime value) {
524  value = new SqlDateTime();
525 
526  // We delegate parsing DATE and TIME strings to the .NET DateTime object...
527  DateTimeOffset date;
528  if (DateTimeOffset.TryParseExact(s, SqlTimeFormats, CultureInfo.InvariantCulture, DateTimeStyles.None, out date)) {
529  var offset = new SqlDayToSecond(date.Offset.Hours, date.Offset.Minutes,0);
530  value = new SqlDateTime(1, 1, 1, date.Hour, date.Minute, date.Second, date.Millisecond, offset);
531  return true;
532  }
533 
534  return false;
535  }
536 
537  public static bool TryParseTimeStamp(string s, out SqlDateTime value) {
538  value = new SqlDateTime();
539 
540  // We delegate parsing DATE and TIME strings to the .NET DateTime object...
541  DateTimeOffset date;
542  if (DateTimeOffset.TryParseExact(s, SqlTimeStampFormats, CultureInfo.InvariantCulture, DateTimeStyles.None, out date)) {
543  var offset = new SqlDayToSecond(date.Offset.Hours, date.Offset.Minutes, 0);
544  value = new SqlDateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, date.Millisecond, offset);
545  return true;
546  }
547 
548  return false;
549  }
550 
551  public static implicit operator SqlDateTime(DateTimeOffset? a) {
552  if (a == null)
553  return Null;
554 
555  return a.Value;
556  }
557 
558  public static implicit operator SqlDateTime(DateTimeOffset a) {
559  var date = a;
560  var offset = new SqlDayToSecond(date.Offset.Days, date.Offset.Hours, date.Offset.Minutes, date.Offset.Seconds);
561  return new SqlDateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, date.Millisecond, offset);
562  }
563 
564  public static implicit operator DateTimeOffset?(SqlDateTime a) {
565  if (a == null || a.IsNull)
566  return null;
567 
568  var offset = new TimeSpan(a.Offset.Hours, a.Offset.Minutes, a.Offset.Seconds);
569  return new DateTimeOffset(a.Year, a.Month, a.Day, a.Hour, a.Minute, a.Second, a.Millisecond, offset);
570  }
571 
572  public static implicit operator DateTimeOffset(SqlDateTime a) {
573  if (a == null || a.IsNull)
574  throw new NullReferenceException();
575 
576  var offset = new TimeSpan(a.Offset.Hours, a.Offset.Minutes, a.Offset.Seconds);
577  return new DateTimeOffset(a.Year, a.Month, a.Day, a.Hour, a.Minute, a.Second, a.Millisecond, offset);
578  }
579 
580  public SqlDateTime ToUtc() {
581  if (value == null)
582  return Null;
583 
584  var utc = value.Value.ToUniversalTime();
585  var offset = new SqlDayToSecond(utc.Offset.Days, utc.Offset.Hours, utc.Offset.Minutes);
586  return new SqlDateTime(utc.Year, utc.Month, utc.Day, utc.Hour, utc.Minute, utc.Second, utc.Millisecond, offset);
587  }
588 
590  if (value == null)
591  return SqlString.Null;
592 
593  var s = value.Value.ToString(DateStringFormat, CultureInfo.InvariantCulture);
594  return new SqlString(s);
595  }
596 
598  if (value == null)
599  return SqlString.Null;
600 
601  var s = value.Value.ToString(TimeStringFormat, CultureInfo.InvariantCulture);
602  return new SqlString(s);
603  }
604 
606  if (value == null)
607  return SqlString.Null;
608 
609  var s = value.Value.ToString(TimeStampStringFormat, CultureInfo.InvariantCulture);
610  return new SqlString(s);
611  }
612 
613  public override string ToString() {
614  if (value == null)
615  return "NULL";
616 
617  return ToTimeStampString().ToString();
618  }
619 
620  public DateTime ToDateTime() {
621  if (value == null)
622  throw new InvalidCastException();
623 
624  return value.Value.DateTime;
625  }
626  }
627 }
SqlDateTime Add(SqlYearToMonth interval)
Adds the given months to this date.
Definition: SqlDateTime.cs:425
SqlDayToSecond Offset
Gets the offset between the date-time instance and the UTC time.
Definition: SqlDateTime.cs:214
int CompareTo(SqlDateTime other)
Definition: SqlDateTime.cs:332
static bool TryParseTimeStamp(string s, out SqlDateTime value)
Definition: SqlDateTime.cs:537
SqlDateTime Add(SqlDayToSecond interval)
Adds the given interval of time to this date-time.
Definition: SqlDateTime.cs:390
byte[] ToByteArray(bool timeZone)
Definition: SqlDateTime.cs:352
readonly DateTimeOffset value
Definition: SqlDateTime.cs:22
static bool TryParseTime(string s, out SqlDateTime value)
Definition: SqlDateTime.cs:523
SqlDateTime(long ticks, SqlDayToSecond offset)
Definition: SqlDateTime.cs:107
override bool Equals(object obj)
Definition: SqlDateTime.cs:324
SqlDateTime(int year, int month, int day)
Definition: SqlDateTime.cs:73
static readonly SqlDayToSecond Zero
Defines the contract for a valid SQL Object
Definition: ISqlObject.cs:23
int IComparable. CompareTo(object obj)
Definition: SqlDateTime.cs:145
static SqlDateTime Parse(string s)
Definition: SqlDateTime.cs:487
TypeCode IConvertible. GetTypeCode()
Definition: SqlDateTime.cs:233
static bool TryParseDate(string s, out SqlDateTime value)
Definition: SqlDateTime.cs:510
bool IsComparableTo(ISqlObject other)
Checks if the current object is comparable with the given one.
bool Equals(SqlDateTime other)
Definition: SqlDateTime.cs:317
int TotalMonths
Gets the total number of months that represents the time span.
SqlDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond)
Definition: SqlDateTime.cs:77
A month span representation of time.
SqlDateTime Subtract(SqlDayToSecond interval)
Subtracts a given interval of time from this date.
Definition: SqlDateTime.cs:409
SqlDateTime Subtract(SqlYearToMonth interval)
Definition: SqlDateTime.cs:435
static bool TryParse(string s, out SqlDateTime value)
Definition: SqlDateTime.cs:495
Deveel.Data.Sql.Objects.SqlString SqlString
Definition: DataObject.cs:27
SqlDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, SqlDayToSecond offset)
Definition: SqlDateTime.cs:81