定义了一个结构,包含一个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 。