SQLite数据库BigINT类型日期数据查询

定义了一个结构,包含一个DateTime类型的属性:

private DateTime _FromTime = DateTime.Now;

在创建SQLite数据库连接实例时,如果我们将storeDateTimeAsTicks参数设置为true:

        /// <summary>
        /// 创建SQLite连接
        /// .db文件不存在时创建,存在时读写,日期类型存为ticks
        /// </summary>
        /// <param name="sDbPath">.db文件路径</param>
        /// <returns>数据库的连接</returns>
        public static SDNConn CreateInstance(string sDbPath)
        {
            return new SDNConn() { Connection = new SQLite.SQLiteConnection(sDbPath, SQLite.SQLiteOpenFlags.ReadWrite | SQLite.SQLiteOpenFlags.Create | SQLite.SQLiteOpenFlags.SharedCache, true) };
        }

    /// <summary>
    /// Constructs a new SQLiteConnection and opens a SQLite database specified by databasePath.
    /// </summary>
    /// <param name="databasePath">
    /// Specifies the path to the database file.
    /// </param>
    /// <param name="openFlags">
    /// Flags controlling how the connection should be opened.
    /// </param>
    /// <param name="storeDateTimeAsTicks">
    /// Specifies whether to store DateTime properties as ticks (true) or strings (false). You
    /// absolutely do want to store them as Ticks in all new projects. The value of false is
    /// only here for backwards compatibility. There is a *significant* speed advantage, with no
    /// down sides, when setting storeDateTimeAsTicks = true.
    /// If you use DateTimeOffset properties, it will be always stored as ticks regardingless
    /// the storeDateTimeAsTicks parameter.
    /// </param>
    public SQLiteConnection(string databasePath, SQLiteOpenFlags openFlags, bool storeDateTimeAsTicks = true)
    {
      if (string.IsNullOrEmpty(databasePath))
        throw new ArgumentException("Must be specified", nameof (databasePath));
      this.DatabasePath = databasePath;
      sqlite3 db;
      SQLite3.Result r = SQLite3.Open(databasePath, out db, (int) openFlags, IntPtr.Zero);
      this.Handle = db;
      if (r != SQLite3.Result.OK)
        throw SQLiteException.New(r, string.Format("Could not open database file: {0} ({1})", new object[2]
        {
          (object) this.DatabasePath,
          (object) r
        }));
      this._open = true;
      this.StoreDateTimeAsTicks = storeDateTimeAsTicks;
      this.BusyTimeout = TimeSpan.FromSeconds(0.1);
      this.Tracer = (Action<string>) (line => {});
    }

则在创建SQLite数据表时,日期类型将自动保存为BIGINT类型:

CREATE TABLE [PictureMetadata](
  [OperatorType] integer, 
  [Person] varchar, 
  [FromTime] BIGINT, 
  [ToTime] bigint, 
  [Path] varchar, 
  [GlobalID] varchar PRIMARY KEY NOT NULL, 
  [TaskID] varchar, 
  [TaskID2] varchar, 
  [ResourceType] integer, 
  [ResourceGID] varchar, 
  [SourcePath] varchar);

在进行查询时,我们采用如下如下语句:

select datetime(FromTime/10000000 - 62135596800, 'unixepoch') mytime from PictureMetadata

结果中的BIGINT型数据 636652579650855945 将被格式化为 2018-06-22 09:52:45 。

那么问题来了,我们存入的时间数据 2018-06-22 09:52:45 是怎样被保存 636652579650855945 的呢?

首先我们需要明白,时间戳 unixepoch 表示返回的是国际协调时间UTC,该时间采用的是格列高利历Gregorian Calendar(标准阳历)基准,并将返回日期解释为UNIX时间,即自1970-01-01以来的秒数。

我们在查询秒数时,采用如下语句:

SELECT strftime('%s','2018-06-22 09:52:45')+62135596800 AS ticks;

与采用如下语句:

SELECT (((JulianDay('2018-06-22 09:52:45') - 2440587.5)*86400.0) + 62135596800) AS ticks

将会得到相同的结果,即 63665257965。

这两种查询方式,得到的都是标准阳历以来的秒数。

按标准阳历,自公元0001-01-01至1970-01-01之间的1969年中,有477年是闰年,则这期间的时间为:1969*365+477=719162天=62135596800秒。于是,我们要保存的时间 2018-06-22 09:52:45 相较 1970-01-01 是 1529661165 秒,加 62135596800 后为 63665257965 ,即JulianDay的时间。

这个时间的单位是秒。UTC采用的国际原子时的准确度为每日数纳秒(一秒的十亿分之一),我们将秒转化成100纳秒为单位,则须乘以一千万即10000000,得到 636652579650000000 。

这是一种精确到纳秒的算法。另外,我们还可以先计算当前时间距离标准阳历 0001-01-01 以来的天数(包含小数),然后转化成以100纳秒为单位的数,得 636652579650855945 。

猜你喜欢

转载自blog.csdn.net/a_dev/article/details/80838444