System.Data.SQLite

Check-in [c3dc93e495]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Improve backward compatibility by throwing exceptions for Julian Day values that are out of the range supported by the DateTime class in the .NET Framework. Fix issue with millisecond accuracy.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | newJulianDay
Files: files | file ages | folders
SHA1: c3dc93e495bef5d24a989988c3fbcef8ed4cb0e5
User & Date: mistachkin 2014-11-01 21:08:57.304
Context
2014-11-01
21:10
Improve coding style. check-in: 4a5306964c user: mistachkin tags: newJulianDay
21:08
Improve backward compatibility by throwing exceptions for Julian Day values that are out of the range supported by the DateTime class in the .NET Framework. Fix issue with millisecond accuracy. check-in: c3dc93e495 user: mistachkin tags: newJulianDay
18:59
Improve the precision of the new tests. check-in: 0d4a166b9a user: mistachkin tags: newJulianDay
Changes
Unified Diff Ignore Whitespace Patch
Changes to System.Data.SQLite/SQLiteConvert.cs.
286
287
288
289
290
291
292
293

294
295
296
297
298
299
300
301
302
303
304

305







306
307
308
309
310
311
312
    /// "date.c" file belonging to the SQLite core library.
    /// </summary>
    /// <param name="jd">
    /// The Julian Day value to convert.
    /// </param>
    /// <param name="badValue">
    /// The <see cref="DateTime" /> value to return in the event that the
    /// Julian Day is out of the supported range.

    /// </param>
    /// <returns>
    /// A <see cref="DateTime" /> value that contains the year, month, and
    /// day values that are closest to the specified Julian Day value.
    /// </returns>
    private static DateTime computeYMD(
        long jd,
        DateTime badValue
        )
    {
        if (!isValidJd(jd))

            return badValue;








        int Z, A, B, C, D, E, X1;

        Z = (int)((jd + 43200000) / 86400000);
        A = (int)((Z - 1867216.25) / 36524.25);
        A = Z + 1 + A - (A / 4);
        B = A + 1524;







|
>







|



>
|
>
>
>
>
>
>
>







286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
    /// "date.c" file belonging to the SQLite core library.
    /// </summary>
    /// <param name="jd">
    /// The Julian Day value to convert.
    /// </param>
    /// <param name="badValue">
    /// The <see cref="DateTime" /> value to return in the event that the
    /// Julian Day is out of the supported range.  If this value is null,
    /// an exception will be thrown instead.
    /// </param>
    /// <returns>
    /// A <see cref="DateTime" /> value that contains the year, month, and
    /// day values that are closest to the specified Julian Day value.
    /// </returns>
    private static DateTime computeYMD(
        long jd,
        DateTime? badValue
        )
    {
        if (!isValidJd(jd))
        {
            if (badValue == null)
            {
                throw new ArgumentException(
                    "Not a supported Julian Day value.");
            }

            return (DateTime)badValue;
        }

        int Z, A, B, C, D, E, X1;

        Z = (int)((jd + 43200000) / 86400000);
        A = (int)((Z - 1867216.25) / 36524.25);
        A = Z + 1 + A - (A / 4);
        B = A + 1524;
323
324
325
326
327
328
329
330



331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346

347
348
349
350

351
352
353
354
355
356
357

358







359
360
361
362
363
364
365
366
367



368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393



394
395
396
397
398
399
400

        try
        {
            return new DateTime(year, month, day);
        }
        catch
        {
            return badValue;



        }
    }

    ///////////////////////////////////////////////////////////////////////////

    /// <summary>
    /// Converts a Julian Day value to a <see cref="DateTime" />.
    /// This method was translated from the "computeHMS" function in the
    /// "date.c" file belonging to the SQLite core library.
    /// </summary>
    /// <param name="jd">
    /// The Julian Day value to convert.
    /// </param>
    /// <param name="badValue">
    /// The <see cref="DateTime" /> value to return in the event that the
    /// Julian Day value is out of the supported range.

    /// </param>
    /// <returns>
    /// A <see cref="DateTime" /> value that contains the hour, minute, and
    /// second values that are closest to the specified Julian Day value.

    /// </returns>
    private static DateTime computeHMS(
        long jd,
        DateTime badValue
        )
    {
        if (!isValidJd(jd))

            return badValue;








        int s;

        s = (int)((jd + 43200000) % 86400000);

        double seconds;

        seconds = s / 1000.0;
        s = (int)seconds;



        seconds -= s;

        int hour;

        hour = s / 3600;
        s -= hour * 3600;

        int minute;

        minute = s / 60;
        seconds += s - minute * 60;

        int second = (int)seconds;
        int millisecond = (int)((seconds - second) * 1000.0);

        try
        {
            DateTime minValue = DateTime.MinValue;

            return new DateTime(
                minValue.Year, minValue.Month, minValue.Day,
                hour, minute, second, millisecond);
        }
        catch
        {
            return badValue;



        }
    }

    ///////////////////////////////////////////////////////////////////////////

    /// <summary>
    /// Converts a <see cref="DateTime" /> to a Julian Day value.







|
>
>
>















|
>



|
>



|



>
|
>
>
>
>
>
>
>





|

|

>
>
>













<











|
>
>
>







332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405

406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427

        try
        {
            return new DateTime(year, month, day);
        }
        catch
        {
            if (badValue == null)
                throw;

            return (DateTime)badValue;
        }
    }

    ///////////////////////////////////////////////////////////////////////////

    /// <summary>
    /// Converts a Julian Day value to a <see cref="DateTime" />.
    /// This method was translated from the "computeHMS" function in the
    /// "date.c" file belonging to the SQLite core library.
    /// </summary>
    /// <param name="jd">
    /// The Julian Day value to convert.
    /// </param>
    /// <param name="badValue">
    /// The <see cref="DateTime" /> value to return in the event that the
    /// Julian Day value is out of the supported range.  If this value is
    /// null, an exception will be thrown instead.
    /// </param>
    /// <returns>
    /// A <see cref="DateTime" /> value that contains the hour, minute, and
    /// second, and millisecond values that are closest to the specified
    /// Julian Day value.
    /// </returns>
    private static DateTime computeHMS(
        long jd,
        DateTime? badValue
        )
    {
        if (!isValidJd(jd))
        {
            if (badValue == null)
            {
                throw new ArgumentException(
                    "Not a supported Julian Day value.");
            }

            return (DateTime)badValue;
        }

        int s;

        s = (int)((jd + 43200000) % 86400000);

        decimal seconds;

        seconds = s / 1000.0M;
        s = (int)seconds;

        int millisecond = (int)((seconds - s) * 1000.0M);

        seconds -= s;

        int hour;

        hour = s / 3600;
        s -= hour * 3600;

        int minute;

        minute = s / 60;
        seconds += s - minute * 60;

        int second = (int)seconds;


        try
        {
            DateTime minValue = DateTime.MinValue;

            return new DateTime(
                minValue.Year, minValue.Month, minValue.Day,
                hour, minute, second, millisecond);
        }
        catch
        {
            if (badValue == null)
                throw;

            return (DateTime)badValue;
        }
    }

    ///////////////////////////////////////////////////////////////////////////

    /// <summary>
    /// Converts a <see cref="DateTime" /> to a Julian Day value.
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
        X1 = 36525 * (Y + 4716) / 100;
        X2 = 306001 * (M + 1) / 10000;

        long jd;

        jd = (long)((X1 + X2 + D + B - 1524.5) * 86400000);

        jd += dateTime.Hour * 3600000 + dateTime.Minute *
            60000 + (long)(dateTime.Second * 1000);

        return jd;
    }
    #endregion

    ///////////////////////////////////////////////////////////////////////////








|
|







466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
        X1 = 36525 * (Y + 4716) / 100;
        X2 = 306001 * (M + 1) / 10000;

        long jd;

        jd = (long)((X1 + X2 + D + B - 1524.5) * 86400000);

        jd += (dateTime.Hour * 3600000) + (dateTime.Minute * 60000) +
            (dateTime.Second * 1000) + dateTime.Millisecond;

        return jd;
    }
    #endregion

    ///////////////////////////////////////////////////////////////////////////

656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
    /// <returns>A .NET DateTime</returns>
    public static DateTime ToDateTime(
        double julianDay,
        DateTimeKind kind
        )
    {
        long jd = DoubleToJd(julianDay);
        DateTime dateTimeYMD = computeYMD(jd, DateTime.MinValue);
        DateTime dateTimeHMS = computeHMS(jd, DateTime.MinValue);

        return new DateTime(
            dateTimeYMD.Year, dateTimeYMD.Month, dateTimeYMD.Day,
            dateTimeHMS.Hour, dateTimeHMS.Minute, dateTimeHMS.Second,
            dateTimeHMS.Millisecond, kind);
    }








|
|







683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
    /// <returns>A .NET DateTime</returns>
    public static DateTime ToDateTime(
        double julianDay,
        DateTimeKind kind
        )
    {
        long jd = DoubleToJd(julianDay);
        DateTime dateTimeYMD = computeYMD(jd, null);
        DateTime dateTimeHMS = computeHMS(jd, null);

        return new DateTime(
            dateTimeYMD.Year, dateTimeYMD.Month, dateTimeYMD.Day,
            dateTimeHMS.Hour, dateTimeHMS.Minute, dateTimeHMS.Second,
            dateTimeHMS.Millisecond, kind);
    }

Changes to Tests/tkt-3e783eecbe.eagle.
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
###############################################################################

package require System.Data.SQLite.Test
runSQLiteTestPrologue

###############################################################################

runTest {test tkt-3e783eecbe-1.1 {Julian Day w/o OLE Automation} -setup {
  set minDateTime [object invoke -create -alias DateTime MinValue]
  set maxDateTime [object invoke -create -alias DateTime MaxValue]

  set dateTimeValues [list $minDateTime "0099-12-31 00:00:00" \
      "0100-01-01 00:00:00" $maxDateTime]
} -body {
  set results [list]







|







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
###############################################################################

package require System.Data.SQLite.Test
runSQLiteTestPrologue

###############################################################################

runTest {test tkt-3e783eecbe-1.1 {To Julian Day w/o OLE Automation} -setup {
  set minDateTime [object invoke -create -alias DateTime MinValue]
  set maxDateTime [object invoke -create -alias DateTime MaxValue]

  set dateTimeValues [list $minDateTime "0099-12-31 00:00:00" \
      "0100-01-01 00:00:00" $maxDateTime]
} -body {
  set results [list]
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

103
104
105
106
107
108
109

    set code [catch {
      object invoke System.Data.SQLite.SQLiteConvert ToJulianDay \
          $dateTimeValue
    } result]

    if {$code != 0} then {
      regexp -- {---> (.*?)(?:\r|\n)} $result result result
    }

    lappend results [list [$dateTimeValue ToString [getDateTimeFormat]] \
        $code $result]
  }

  set results
} -cleanup {
  unset -nocomplain code result results dateTimeValue dateTimeValues \
      maxDateTime minDateTime
} -constraints {eagle System.Data.SQLite} -result {{{0001-01-01 00:00:00} 0\
1721425.5} {{0099-12-31 00:00:00Z} 0 1757583.5} {{0100-01-01 00:00:00Z} 0\
1757584.5} {{9999-12-31 23:59:59.9999999} 0 5373484.49998843}}}

###############################################################################

runTest {test tkt-3e783eecbe-1.2 {Julian Day w/o OLE Automation} -setup {
  set minDoubleValue [object invoke -create -alias Double MinValue]
  set maxDoubleValue [object invoke -create -alias Double MaxValue]

  set doubleValues [list \
      $minDoubleValue -1.0 0.0 1.0 1721425.5 2451910.5 2456962.0 \
      5373484.49998843 $maxDoubleValue]
} -body {
  set results [list]

  foreach doubleValue $doubleValues {
    if {$doubleValue ni [info objects]} then {
      set doubleValue [object invoke \
          -create -alias Double Parse $doubleValue]
    }

    set code [catch {
      set dateTimeValue [object invoke -create -alias \
          System.Data.SQLite.SQLiteConvert ToDateTime $doubleValue Utc]

      $dateTimeValue ToString [getDateTimeFormat]
    } result]

    if {$code != 0} then {
      regexp -- {---> (.*?)(?:\r|\n)} $result result result
    }

    lappend results [list [$doubleValue ToString] $code $result]
  }

  set results
} -cleanup {
  unset -nocomplain code result results dateTimeValue doubleValue \
      doubleValues maxDoubleValue minDoubleValue
} -constraints {eagle System.Data.SQLite} -result {{-1.79769313486232E+308 0\
{0001-01-01 00:00:00Z}} {-1 0 {0001-01-01 00:00:00Z}} {0 0 {0001-01-01\
00:00:00Z}} {1 0 {0001-01-01 00:00:00Z}} {1721425.5 0 {0001-01-01 00:00:00Z}}\
{2451910.5 0 {2001-01-01 00:00:00Z}} {2456962 0 {2014-10-31 12:00:00Z}}\

{5373484.49998843 0 {9999-12-31 23:59:59Z}} {1.79769313486232E+308 0\
{0001-01-01 00:00:00Z}}}}

###############################################################################

runSQLiteTestEpilogue
runTestEpilogue







|












|



|





|

















|









|
|
|
|
>
|
|





41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110

    set code [catch {
      object invoke System.Data.SQLite.SQLiteConvert ToJulianDay \
          $dateTimeValue
    } result]

    if {$code != 0} then {
      regexp -- {---> (.*?):} $result result result
    }

    lappend results [list [$dateTimeValue ToString [getDateTimeFormat]] \
        $code $result]
  }

  set results
} -cleanup {
  unset -nocomplain code result results dateTimeValue dateTimeValues \
      maxDateTime minDateTime
} -constraints {eagle System.Data.SQLite} -result {{{0001-01-01 00:00:00} 0\
1721425.5} {{0099-12-31 00:00:00Z} 0 1757583.5} {{0100-01-01 00:00:00Z} 0\
1757584.5} {{9999-12-31 23:59:59.9999999} 0 5373484.49999999}}}

###############################################################################

runTest {test tkt-3e783eecbe-1.2 {From Julian Day w/o OLE Automation} -setup {
  set minDoubleValue [object invoke -create -alias Double MinValue]
  set maxDoubleValue [object invoke -create -alias Double MaxValue]

  set doubleValues [list \
      $minDoubleValue -1.0 0.0 1.0 1721425.5 2451910.5 2456962.0 \
      5373484.49999998 5373484.49999999 $maxDoubleValue]
} -body {
  set results [list]

  foreach doubleValue $doubleValues {
    if {$doubleValue ni [info objects]} then {
      set doubleValue [object invoke \
          -create -alias Double Parse $doubleValue]
    }

    set code [catch {
      set dateTimeValue [object invoke -create -alias \
          System.Data.SQLite.SQLiteConvert ToDateTime $doubleValue Utc]

      $dateTimeValue ToString [getDateTimeFormat]
    } result]

    if {$code != 0} then {
      regexp -- {---> (.*?):} $result result result
    }

    lappend results [list [$doubleValue ToString] $code $result]
  }

  set results
} -cleanup {
  unset -nocomplain code result results dateTimeValue doubleValue \
      doubleValues maxDoubleValue minDoubleValue
} -constraints {eagle System.Data.SQLite} -result {{-1.79769313486232E+308 1\
System.ArgumentException} {-1 1 System.ArgumentException} {0 1\
System.ArgumentException} {1 1 System.ArgumentException} {1721425.5 0\
{0001-01-01 00:00:00Z}} {2451910.5 0 {2001-01-01 00:00:00Z}} {2456962 0\
{2014-10-31 12:00:00Z}} {5373484.49999998 0 {9999-12-31 23:59:59.998Z}}\
{5373484.49999999 0 {9999-12-31 23:59:59.999Z}} {1.79769313486232E+308 1\
System.ArgumentException}}}

###############################################################################

runSQLiteTestEpilogue
runTestEpilogue