System.Data.SQLite
Check-in [c3dc93e495]
Not logged in

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 | SQL archive
Timelines: family | ancestors | descendants | both | newJulianDay
Files: files | file ages | folders
SHA1: c3dc93e495bef5d24a989988c3fbcef8ed4cb0e5
User & Date: mistachkin 2014-11-01 21:08:57
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
Hide Diffs Unified Diffs 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
...
323
324
325
326
327
328
329
330



331
332
333
334
335
336
337
...
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
...
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
...
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
    /// "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;
................................................................................

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



        }
    }

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

    /// <summary>
    /// Converts a Julian Day value to a <see cref="DateTime" />.
................................................................................
    /// "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.
................................................................................
        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

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

................................................................................
    /// <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);
    }








|
>







|



>
|
>
>
>
>
>
>
>







 







|
>
>
>







 







|
>



|
>



|



>
|
>
>
>
>
>
>
>





|

|

>
>
>













<











|
>
>
>







 







|
|







 







|
|







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
...
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
...
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
...
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
...
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
    /// "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;
................................................................................

        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" />.
................................................................................
    /// "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.
................................................................................
        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

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

................................................................................
    /// <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
..
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
..
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
###############################################################################

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]
................................................................................

    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 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







|







 







|












|



|





|







 







|









|
|
|
|
>
|
<
>





16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
..
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
..
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
###############################################################################

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]
................................................................................

    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 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