@@ -210,6 +210,23 @@ public partial class SQLiteConnection : IDisposable
210210 /// </summary>
211211 public bool StoreDateTimeAsTicks { get ; private set ; }
212212
213+ /// <summary>
214+ /// Whether to store TimeSpan properties as ticks (true) or strings (false).
215+ /// </summary>
216+ public bool StoreTimeSpanAsTicks { get ; private set ; }
217+
218+ /// <summary>
219+ /// The format to use when storing DateTime properties as strings. Ignored if StoreDateTimeAsTicks is true.
220+ /// </summary>
221+ /// <value>The date time string format.</value>
222+ public string DateTimeStringFormat { get ; private set ; }
223+
224+ /// <summary>
225+ /// The DateTimeStyles value to use when parsing a DateTime property string.
226+ /// </summary>
227+ /// <value>The date time style.</value>
228+ internal System . Globalization . DateTimeStyles DateTimeStyle { get ; private set ; }
229+
213230#if USE_SQLITEPCL_RAW && ! NO_SQLITEPCL_RAW_BATTERIES
214231 static SQLiteConnection ( )
215232 {
@@ -298,6 +315,8 @@ public SQLiteConnection (SQLiteConnectionString connectionString)
298315 _open = true ;
299316
300317 StoreDateTimeAsTicks = connectionString . StoreDateTimeAsTicks ;
318+ DateTimeStringFormat = connectionString . DateTimeStringFormat ;
319+ DateTimeStyle = connectionString . DateTimeStyle ;
301320
302321 BusyTimeout = TimeSpan . FromSeconds ( 0.1 ) ;
303322 Tracer = line => Debug . WriteLine ( line ) ;
@@ -546,7 +565,7 @@ public CreateTableResult CreateTable (Type ty, CreateFlags createFlags = CreateF
546565
547566 // Build query.
548567 var query = "create " + @virtual + "table if not exists \" " + map . TableName + "\" " + @using + "(\n " ;
549- var decls = map . Columns . Select ( p => Orm . SqlDecl ( p , StoreDateTimeAsTicks ) ) ;
568+ var decls = map . Columns . Select ( p => Orm . SqlDecl ( p , StoreDateTimeAsTicks , StoreTimeSpanAsTicks ) ) ;
550569 var decl = string . Join ( ",\n " , decls . ToArray ( ) ) ;
551570 query += decl ;
552571 query += ")" ;
@@ -812,7 +831,7 @@ void MigrateTable (TableMapping map, List<ColumnInfo> existingCols)
812831 }
813832
814833 foreach ( var p in toBeAdded ) {
815- var addCol = "alter table \" " + map . TableName + "\" add column " + Orm . SqlDecl ( p , StoreDateTimeAsTicks ) ;
834+ var addCol = "alter table \" " + map . TableName + "\" add column " + Orm . SqlDecl ( p , StoreDateTimeAsTicks , StoreTimeSpanAsTicks ) ;
816835 Execute ( addCol ) ;
817836 }
818837 }
@@ -2090,9 +2109,14 @@ public enum NotifyTableChangedAction
20902109 /// </summary>
20912110 public class SQLiteConnectionString
20922111 {
2112+ const string DateTimeSqliteDefaultFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff" ;
2113+
20932114 public string UniqueKey { get ; }
20942115 public string DatabasePath { get ; }
20952116 public bool StoreDateTimeAsTicks { get ; }
2117+ public bool StoreTimeSpanAsTicks { get ; }
2118+ public string DateTimeStringFormat { get ; }
2119+ public System . Globalization . DateTimeStyles DateTimeStyle { get ; }
20962120 public object Key { get ; }
20972121 public SQLiteOpenFlags OpenFlags { get ; }
20982122 public Action < SQLiteConnection > PreKeyAction { get ; }
@@ -2194,13 +2218,25 @@ public SQLiteConnectionString (string databasePath, bool storeDateTimeAsTicks, o
21942218 /// <param name="vfsName">
21952219 /// Specifies the Virtual File System to use on the database.
21962220 /// </param>
2197- public SQLiteConnectionString ( string databasePath , SQLiteOpenFlags openFlags , bool storeDateTimeAsTicks , object key = null , Action < SQLiteConnection > preKeyAction = null , Action < SQLiteConnection > postKeyAction = null , string vfsName = null )
2221+ /// <param name="dateTimeStringFormat">
2222+ /// Specifies the format to use when storing DateTime properties as strings.
2223+ /// </param>
2224+ /// <param name="storeTimeSpanAsTicks">
2225+ /// Specifies whether to store TimeSpan properties as ticks (true) or strings (false). You
2226+ /// absolutely do want to store them as Ticks in all new projects. The value of false is
2227+ /// only here for backwards compatibility. There is a *significant* speed advantage, with no
2228+ /// down sides, when setting storeTimeSpanAsTicks = true.
2229+ /// </param>
2230+ public SQLiteConnectionString ( string databasePath , SQLiteOpenFlags openFlags , bool storeDateTimeAsTicks , object key = null , Action < SQLiteConnection > preKeyAction = null , Action < SQLiteConnection > postKeyAction = null , string vfsName = null , string dateTimeStringFormat = DateTimeSqliteDefaultFormat , bool storeTimeSpanAsTicks = true )
21982231 {
21992232 if ( key != null && ! ( ( key is byte [ ] ) || ( key is string ) ) )
22002233 throw new ArgumentException ( "Encryption keys must be strings or byte arrays" , nameof ( key ) ) ;
22012234
22022235 UniqueKey = string . Format ( "{0}_{1:X8}" , databasePath , ( uint ) openFlags ) ;
22032236 StoreDateTimeAsTicks = storeDateTimeAsTicks ;
2237+ StoreTimeSpanAsTicks = storeTimeSpanAsTicks ;
2238+ DateTimeStringFormat = dateTimeStringFormat ;
2239+ DateTimeStyle = "o" . Equals ( DateTimeStringFormat , StringComparison . OrdinalIgnoreCase ) || "r" . Equals ( DateTimeStringFormat , StringComparison . OrdinalIgnoreCase ) ? System . Globalization . DateTimeStyles . RoundtripKind : System . Globalization . DateTimeStyles . None ;
22042240 Key = key ;
22052241 PreKeyAction = preKeyAction ;
22062242 PostKeyAction = postKeyAction ;
@@ -2596,9 +2632,9 @@ public static Type GetType (object obj)
25962632 return obj . GetType ( ) ;
25972633 }
25982634
2599- public static string SqlDecl ( TableMapping . Column p , bool storeDateTimeAsTicks )
2635+ public static string SqlDecl ( TableMapping . Column p , bool storeDateTimeAsTicks , bool storeTimeSpanAsTicks )
26002636 {
2601- string decl = "\" " + p . Name + "\" " + SqlType ( p , storeDateTimeAsTicks ) + " " ;
2637+ string decl = "\" " + p . Name + "\" " + SqlType ( p , storeDateTimeAsTicks , storeTimeSpanAsTicks ) + " " ;
26022638
26032639 if ( p . IsPK ) {
26042640 decl += "primary key " ;
@@ -2616,7 +2652,7 @@ public static string SqlDecl (TableMapping.Column p, bool storeDateTimeAsTicks)
26162652 return decl ;
26172653 }
26182654
2619- public static string SqlType ( TableMapping . Column p , bool storeDateTimeAsTicks )
2655+ public static string SqlType ( TableMapping . Column p , bool storeDateTimeAsTicks , bool storeTimeSpanAsTicks )
26202656 {
26212657 var clrType = p . ColumnType ;
26222658 if ( clrType == typeof ( Boolean ) || clrType == typeof ( Byte ) || clrType == typeof ( UInt16 ) || clrType == typeof ( SByte ) || clrType == typeof ( Int16 ) || clrType == typeof ( Int32 ) || clrType == typeof ( UInt32 ) || clrType == typeof ( Int64 ) ) {
@@ -2634,7 +2670,7 @@ public static string SqlType (TableMapping.Column p, bool storeDateTimeAsTicks)
26342670 return "varchar" ;
26352671 }
26362672 else if ( clrType == typeof ( TimeSpan ) ) {
2637- return "bigint" ;
2673+ return storeTimeSpanAsTicks ? "bigint" : "time ";
26382674 }
26392675 else if ( clrType == typeof ( DateTime ) ) {
26402676 return storeDateTimeAsTicks ? "bigint" : "datetime" ;
@@ -2920,15 +2956,13 @@ void BindAll (Sqlite3Statement stmt)
29202956 b . Index = nextIdx ++ ;
29212957 }
29222958
2923- BindParameter ( stmt , b . Index , b . Value , _conn . StoreDateTimeAsTicks ) ;
2959+ BindParameter ( stmt , b . Index , b . Value , _conn . StoreDateTimeAsTicks , _conn . DateTimeStringFormat , _conn . StoreTimeSpanAsTicks ) ;
29242960 }
29252961 }
29262962
29272963 static IntPtr NegativePointer = new IntPtr ( - 1 ) ;
29282964
2929- const string DateTimeExactStoreFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff" ;
2930-
2931- internal static void BindParameter ( Sqlite3Statement stmt , int index , object value , bool storeDateTimeAsTicks )
2965+ internal static void BindParameter ( Sqlite3Statement stmt , int index , object value , bool storeDateTimeAsTicks , string dateTimeStringFormat , bool storeTimeSpanAsTicks )
29322966 {
29332967 if ( value == null ) {
29342968 SQLite3 . BindNull ( stmt , index ) ;
@@ -2953,14 +2987,19 @@ internal static void BindParameter (Sqlite3Statement stmt, int index, object val
29532987 SQLite3 . BindDouble ( stmt , index , Convert . ToDouble ( value ) ) ;
29542988 }
29552989 else if ( value is TimeSpan ) {
2956- SQLite3 . BindInt64 ( stmt , index , ( ( TimeSpan ) value ) . Ticks ) ;
2990+ if ( storeTimeSpanAsTicks ) {
2991+ SQLite3 . BindInt64 ( stmt , index , ( ( TimeSpan ) value ) . Ticks ) ;
2992+ }
2993+ else {
2994+ SQLite3 . BindText ( stmt , index , ( ( TimeSpan ) value ) . ToString ( ) , - 1 , NegativePointer ) ;
2995+ }
29572996 }
29582997 else if ( value is DateTime ) {
29592998 if ( storeDateTimeAsTicks ) {
29602999 SQLite3 . BindInt64 ( stmt , index , ( ( DateTime ) value ) . Ticks ) ;
29613000 }
29623001 else {
2963- SQLite3 . BindText ( stmt , index , ( ( DateTime ) value ) . ToString ( DateTimeExactStoreFormat , System . Globalization . CultureInfo . InvariantCulture ) , - 1 , NegativePointer ) ;
3002+ SQLite3 . BindText ( stmt , index , ( ( DateTime ) value ) . ToString ( dateTimeStringFormat , System . Globalization . CultureInfo . InvariantCulture ) , - 1 , NegativePointer ) ;
29643003 }
29653004 }
29663005 else if ( value is DateTimeOffset ) {
@@ -3036,7 +3075,17 @@ object ReadCol (Sqlite3Statement stmt, int index, SQLite3.ColType type, Type clr
30363075 return ( float ) SQLite3 . ColumnDouble ( stmt , index ) ;
30373076 }
30383077 else if ( clrType == typeof ( TimeSpan ) ) {
3039- return new TimeSpan ( SQLite3 . ColumnInt64 ( stmt , index ) ) ;
3078+ if ( _conn . StoreTimeSpanAsTicks ) {
3079+ return new TimeSpan ( SQLite3 . ColumnInt64 ( stmt , index ) ) ;
3080+ }
3081+ else {
3082+ var text = SQLite3 . ColumnString ( stmt , index ) ;
3083+ TimeSpan resultTime ;
3084+ if ( ! TimeSpan . TryParseExact ( text , "c" , System . Globalization . CultureInfo . InvariantCulture , System . Globalization . TimeSpanStyles . None , out resultTime ) ) {
3085+ resultTime = TimeSpan . Parse ( text ) ;
3086+ }
3087+ return resultTime ;
3088+ }
30403089 }
30413090 else if ( clrType == typeof ( DateTime ) ) {
30423091 if ( _conn . StoreDateTimeAsTicks ) {
@@ -3045,7 +3094,7 @@ object ReadCol (Sqlite3Statement stmt, int index, SQLite3.ColType type, Type clr
30453094 else {
30463095 var text = SQLite3 . ColumnString ( stmt , index ) ;
30473096 DateTime resultDate ;
3048- if ( ! DateTime . TryParseExact ( text , DateTimeExactStoreFormat , System . Globalization . CultureInfo . InvariantCulture , System . Globalization . DateTimeStyles . None , out resultDate ) ) {
3097+ if ( ! DateTime . TryParseExact ( text , _conn . DateTimeStringFormat , System . Globalization . CultureInfo . InvariantCulture , _conn . DateTimeStyle , out resultDate ) ) {
30493098 resultDate = DateTime . Parse ( text ) ;
30503099 }
30513100 return resultDate ;
@@ -3149,7 +3198,7 @@ public int ExecuteNonQuery (object[] source)
31493198 //bind the values.
31503199 if ( source != null ) {
31513200 for ( int i = 0 ; i < source . Length ; i ++ ) {
3152- SQLiteCommand . BindParameter ( Statement , i + 1 , source [ i ] , Connection . StoreDateTimeAsTicks ) ;
3201+ SQLiteCommand . BindParameter ( Statement , i + 1 , source [ i ] , Connection . StoreDateTimeAsTicks , Connection . DateTimeStringFormat , Connection . StoreTimeSpanAsTicks ) ;
31533202 }
31543203 }
31553204 r = SQLite3 . Step ( Statement ) ;
0 commit comments