Microsoft.Data.Sqlite SqliteConnection does not support DateTime
See original GitHub issueMicrosoft.Data.Sqlite 6.0 .NET 6.0
If we save a datetime value to Sqlite database (integer column type), and then use Microsoft.Data.Sqlite.SqliteConnection to read it, Microsoft.Data.Sqlite will convert it to a string.
Tested:
- SqliteCommand.ExecuteScalar
- DbDataAdapter.Fill DataSet/DataTable
C# code:
using Microsoft.Data.Sqlite;
using System.Data;
using System.Data.Common;
namespace TestNamespace
{
public class DataAdapter : DbDataAdapter
{
}
public class TestClass
{
public static void Main()
{
var conn = new SqliteConnection("Data Source=:memory:");
conn.Open();
SqliteCommand cmd;
object? data;
cmd = conn.CreateCommand();
cmd.CommandText = @"CREATE TABLE UserTable (""CreationTime"" integer)";
cmd.ExecuteNonQuery();
cmd = conn.CreateCommand();
cmd.CommandText = @"INSERT INTO UserTable values (@P1)";
cmd.Parameters.Add("P1", SqliteType.Integer).Value = DateTime.Now;
cmd.ExecuteNonQuery();
cmd = conn.CreateCommand();
cmd.CommandText = "select CreationTime from UserTable";
data = cmd.ExecuteScalar();
Console.WriteLine("Use ExecuteScalar:");
Console.WriteLine("Type: " + data?.GetType());
Console.WriteLine("Value: " + data);
Console.WriteLine();
cmd = conn.CreateCommand();
cmd.CommandText = "select * from UserTable";
var da = new DataAdapter();
da.SelectCommand = cmd;
var dataTable = new DataTable();
da.Fill(dataTable);
Console.WriteLine("Use DataAdapter.Fill DataSet or DataTable:");
Console.WriteLine("Type: " + dataTable.Rows[0][0]?.GetType());
Console.WriteLine("Value: " + dataTable.Rows[0][0]);
}
}
}
The Console displays:
Type: System.String
It cannot directly restore the data to Datetime. For all tables, it is still necessary to convert the string to DateTime again.
Or can Microsoft.Data.Sqlite directly convert it to DateTime?
p.s.
The Sqlite offical library can provide this API to convert DateTime value. Not sure if it will affect the datetime data.
https://system.data.sqlite.org/
using System.Data.SQLite;
var stringBuilder = new SQLiteConnectionStringBuilder();
stringBuilder.DateTimeFormat = SQLiteDateFormats.Ticks;
stringBuilder.DateTimeKind = DateTimeKind.Utc;
//
// This implementation of SQLite for ADO.NET can process date/time fields in databases
// in one of six formats.
//
// ISO8601 format is more compatible, readable, fully-processable, but less accurate
// as it does not provide time down to fractions of a second. JulianDay is the numeric
// format the SQLite uses internally and is arguably the most compatible with 3rd
// party tools. It is not readable as text without post-processing. Ticks less compatible
// with 3rd party tools that query the database, and renders the DateTime field
// unreadable as text without post-processing. UnixEpoch is more compatible with
// Unix systems. InvariantCulture allows the configured format for the invariant
// culture format to be used and is human readable. CurrentCulture allows the configured
// format for the current culture to be used and is also human readable. The preferred
// order of choosing a DateTime format is JulianDay, ISO8601, and then Ticks. Ticks
// is mainly present for legacy code support.
public enum SQLiteDateFormats
{
//
// Use the value of DateTime.Ticks. This value is not recommended and is not well
// supported with LINQ.
Ticks = 0,
//
// Use the ISO-8601 format. Uses the "yyyy-MM-dd HH:mm:ss.FFFFFFFK" format for UTC
// DateTime values and "yyyy-MM-dd HH:mm:ss.FFFFFFF" format for local DateTime values).
ISO8601 = 1,
//
// The interval of time in days and fractions of a day since January 1, 4713 BC.
JulianDay = 2,
//
// The whole number of seconds since the Unix epoch (January 1, 1970).
UnixEpoch = 3,
//
// Any culture-independent string value that the .NET Framework can interpret as
// a valid DateTime.
InvariantCulture = 4,
//
// Any string value that the .NET Framework can interpret as a valid DateTime using
// the current culture.
CurrentCulture = 5,
//
// The default format for this provider.
Default = 1
}
And it supports UTC Time:
//
// Specifies whether a System.DateTime object represents a local time, a Coordinated
// Universal Time (UTC), or is not specified as either local time or UTC.
public enum DateTimeKind
{
//
// The time represented is not specified as either local time or Coordinated Universal
// Time (UTC).
Unspecified,
//
// The time represented is UTC.
Utc,
//
// The time represented is local time.
Local
}
Issue Analytics
- State:
- Created 2 years ago
- Comments:7 (5 by maintainers)
Top Results From Across the Web
sqlite throwing a "String not recognized as a valid datetime"
It seems that System.Data.SQLite does not handle DateTime s correctly. I tried DateTime.ParseExact and gave the format in my database (mm/dd ...
Read more >It should be documented that the connection string must ...
ArgumentException: Keyword not supported: 'datetimeformat'.\r\n at Microsoft.Data.Sqlite.SqliteConnectionStringBuilder.GetIndex(String keyword)\ ...
Read more >Transactions - Microsoft.Data.Sqlite
Transactions let you group multiple SQL statements into a single unit of work that is committed to the database as one atomic unit....
Read more >Auto populate from sqlite database - Microsoft Q&A
I'm using dictionary and item list to pull information from SQLite database. Populating number and time is no issue the rest of the...
Read more >The "String was not recognized as a valid DateTime" error ...
The "String was not recognized as a valid DateTime" error occurs in non invariant culture if schedulerCOntrol is connected to SQLite.
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
DbDataAdapter is generally considered legacy - I’d recommend considering either using DbDataReader directly (DbDataAdapter is a layer on top of that), or better yet, a data technology like Dapper or Entity Framework Core. I’m not sure, but there may be a way of configuring DbDataAdapter with the expected data type per column, which would help in this case.
Unfortunately, this really is a limitation of the Sqlite database itself, since it doesn’t actually have a timestamp type.
If you are selecting more than one field, then you need to use ExecuteReader in any case - ExecuteScalar cannot be used to select more than one value. At that point you can simply call
reader.GetFieldValue<DateTime>()
yourself. This really is@roland5572 since SQLite has no actual timestamp type in the database, Microsoft.Data.Sqlite has no way of knowing that it should return a DateTime here; this is why you need to tell it that via GetFieldValue.
You can easily wrap the above in a simple extension method, such as the following: