Lazarus SQLite日期条目显示不正确

时间:2017-02-27 15:46:21

标签: sqlite date delphi lazarus

更新:问题由@whosrdaddy解决。请参阅此问题下面的评论。

我正在尝试解决以下特殊情况:在朋友的Lazarus项目中,他尝试查询SQLite中的条目。 asString() - 方法(在显示约会的过程中)在Windows 64 Bit上返回正确的日期。但是,在32位操作系统上,只显示前两位数字('16'而不是'28 .02.2016')。可能是什么原因?

这是初始化表单的源代码:

<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.6.4/css/bootstrap-datepicker3.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.6.4/locales/bootstrap-datepicker.fr.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.6.4/js/bootstrap-datepicker.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<div id="datepicker" class="input-group date" data-date-format="dd-mm-yyyy"></div>
            <input type="hidden" id="my_hidden_input" class="form-control">

还有两个程序:

// Initialise Form
procedure TForm1.FormCreate(Sender: TObject);
begin
  SQLite3Connection1.DatabaseName:='Kalender.sqlite';
  SQLTransaction1.Database:=SQLite3Connection1;
  SQLQuery1.Transaction:=SQLTransaction1;

  // Create Table "tblTermine"
  SQLQuery1.SQL.text := 'CREATE TABLE IF NOT EXISTS tblKalender (Datum DATETIME, Termin VARCHAR(10))';
  SQLQuery1.ExecSQL;
  SQLTransaction1.commit;
end;

The intended output into the TListBox would be something like this.

2 个答案:

答案 0 :(得分:0)

您应首先将DateTime转换为Julian日期

function DateTimeToJulianDate(const Datum: TDateTime): Double;

SqlQuery1.SQL.text:= 'Insert into tblKalender Values (:Datum, :Termin)';
SqlQuery1.ParamByName('Datum').AsFloat := DateTimeToJulianDate(Datum);
...
SqlQuery1.ExecSQL;

测试并获得使用价值:
function TryJulianDateToDateTime(const AValue: Double; ADateTime: TDateTime):Boolean;

if TryJulianDateToDateTime(SQLQuery1.Fields[0].AsFloat,myDate)
   then
   ListBox1.Items.add(DateTimeToStr(myDate)+ ': ' + .....
   else
   ShowMessage('Not a valid Julian date');

<强>更新

  

SQLite能够将日期和时间存储为TEXT,REAL或INTEGER值:

     
      
  • TEXT as ISO8601 strings(&#34; YYYY-MM-DD HH:MM:SS.SSS&#34;)。
  •   
  • 真实如朱利安日数,即格林威治中午11月24日中午的天数,公元前4714年根据预示   阳历。
  •   
  • INTEGER as Unix Time,自1970-01-01 00:00:00 UTC以来的秒数。
  •   

双重测试

procedure TForm1.Button3Click(Sender: TObject);
var
 Datum  : TDate;
 myDate : TDateTime;
 JulianDouble : Double;
begin
//  uses ....,DateUtils

Datum := StrToDate('01.01.2013');  //German Culture settings
     Memo1.Lines.Add('01/01/2013 = '+DateTimeToStr(Datum)+ '    TDate as Text');
     Memo1.Lines.Add('01/01/2013 = '+FloatToStr(Datum)   + '           TDate Double');
JulianDouble := DateTimeToJulianDate(Datum);
     Memo1.Lines.Add('01/01/2013 = '+FloatToStr(JulianDouble)  + '    Julian Double');
if TryJulianDateToDateTime(JulianDouble,myDate)
   then
     Memo1.Lines.Add('01/01/2013 = '+DateTimeToStr(myDate)+ '   TDate as Text')
   else
     ShowMessage('Not a valid Julian date');
end;

输出

  

01/01/2013 = 01.01.2013 TDate as Text
  01/01/2013 = 41275 TDate Double
  01/01/2013 = 2456293,5 Julian Double
  01/01/2013 = 01.01.2013 TDate as Text

更新-2: 将Delphi TDate Double写入SQLite Date字段是错误的

您的评论告诉我您不知道问题。

当然,您可以直接将Delphi Double值写入数据库字段。并将其读回TDateTime 这很快就会导致问题。

示例:

SQLite的:

  

这些功能仅适用于0000-01-01 00:00:00和之间的日期   9999-12-31 23:59:59(julidan day numbers 1721059.5到5373484.5)。
  对于该范围之外的日期,这些函数的结果是   未定义。

  • 41275 2013/01/01 Delphi TDate Double超出上述范围!!

  • 无法再使用SQLite自己的日期函数。

  

计算当前日期。
      选择日期(&#39;现在&#39;);
  计算当月的最后一天。
      选择日期(&#39;现在&#39;,&#39;月初&#39;,&#39; +1个月&#39;,&#39; -1天&#39;);
  计算给定unix时间戳1092941466的日期和时间。
      选择日期时间(1092941466,&#39; unixepoch&#39;);
  计算给定unix时间戳1092941466的日期和时间,并补偿您当地的时区
      选择日期时间(1092941466,&#39; unixepoch&#39;,&#39; localtime&#39;);
  计算自签署美国独立宣言以来的天数。
      SELECT julianday(&#39; now&#39;) - julianday(&#39; 1776-07-04&#39;);
  等等。

  • 使用上述功能更改日期值会为日期 2013/01/01 提供双倍 2456293,5 如果您现在使用未经证实并将其传递给Delphi TDateTime,它将 3387/11/26 )。
    这与TDateTimePicker的最大值相差不远 2958465.5 ,意味着 9999/12/31

    DateTimePicker1.DateTime := 2958465.5;

    DateTimePicker1 9999/12/31

如果一个人已经知道这是错误的,那就不应该用它来崩溃。

答案 1 :(得分:0)

SQLite使用名为manifest typing的东西,这意味着如果存储(Delphi)类型的TDateTime值,SQLite将存储基础浮点值而不发出警告或消息,并为您提供值,这样您就不会请注意,SQLite不会将此视为日期时间值,除非您尝试从SQL中操作该值。

为了抵消这种情况,我使用这段SQL代码将Delphi TDateTime值转换为实际的SQL日期时间:

datetime('1900-01-01','+'||(myDateField-2)||' day')

(另见here