• Sqlite.net 读取DateTime异常的解决方案


    以前在处理DateTime的时候,为了屏蔽不同数据库的差异,经常将DateTime保存成字符串,只要服务器不切换本地化表示方法,这种方案肯定是没有问题的。只是在读取和保存的时候需要各做一次转换,(实际上System.Data.Sqlite也会做类似的事情,因此性能上几乎没有差异)。

    这种方法延续到Sqlite一样没有问题,最近看一个开源项目,里面直接用的DateTime,里面用了Utc格式,后来在日志中发现总是有格式异常的报警,仔细调阅了一下日志发现问题都是一样的,根源指到了System.Data.Sqlite。

    System.FormatException: String was not recognized as a valid DateTime.

    at System.DateTimeParse.ParseExactMultiple(String s, String[] formats, DateTimeFormatInfo dtfi, DateTimeStyles style)

    at System.DateTime.ParseExact(String s, String[] formats, IFormatProvider provider, DateTimeStyles style)
    at System.Data.SQLite.SQLiteConvert.ToDateTime(String dateText)
    at System.Data.SQLite.SQLite3.GetDateTime(SQLiteStatement stmt, Int32 index)
    at System.Data.SQLite.SQLite3.GetValue(SQLiteStatement stmt, Int32 index, SQLiteType typ)
    at System.Data.SQLite.SQLiteDataReader.GetValue(Int32 i)

    对应源代码为:

    Sqlite3.cs

       

    internal override DateTime GetDateTime(SQLiteStatement stmt, int index)
        {
    #if !SQLITE_STANDARD
          
    int len;
          
    return ToDateTime(UnsafeNativeMethods.sqlite3_column_text_interop(stmt._sqlite_stmt, index, out len), len);
    #else
          
    return ToDateTime(UnsafeNativeMethods.sqlite3_column_text(stmt._sqlite_stmt, index), -1);
    #endif
        }

    SQLiteConvert.cs

    /// <summary>
        
    /// Converts a string into a DateTime, using the current DateTimeFormat specified for the connection when it was opened.
        
    /// </summary>
        
    /// <remarks>
        
    /// Acceptable ISO8601 DateTime formats are:
        
    ///   yyyy-MM-dd HH:mm:ss
        
    ///   yyyyMMddHHmmss
        
    ///   yyyyMMddTHHmmssfffffff
        
    ///   yyyy-MM-dd
        
    ///   yy-MM-dd
        
    ///   yyyyMMdd
        
    ///   HH:mm:ss
        
    ///   THHmmss
        
    /// </remarks>
        
    /// <param name="dateText">The string containing either a Tick value, a JulianDay double, or an ISO8601-format string</param>
        
    /// <returns>A DateTime value</returns>
        public DateTime ToDateTime(string dateText)
        {
          
    switch (_datetimeFormat)
          {
            
    case SQLiteDateFormats.Ticks:
              
    return new DateTime(Convert.ToInt64(dateText, CultureInfo.InvariantCulture));
            
    case SQLiteDateFormats.JulianDay:
              
    return ToDateTime(Convert.ToDouble(dateText, CultureInfo.InvariantCulture));
            
    default:
              
    return DateTime.ParseExact(dateText, _datetimeFormats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.None);
          }
        }

    问题就出现在这里面,ISO8601规范,无非就有两种办法,

    一种是在存储的时候datetime格式要遵守ISO8601格式规范,即转码.ToString("S");

    另外一种方法就是扩展_datetimeFormats,让其支持其他格式。

    原始定义为:

    /// <summary>
        
    /// An array of ISO8601 datetime formats we support conversion from
        
    /// </summary>
        private static string[] _datetimeFormats = new string[] {
          
    "THHmmss",
          
    "THHmm",
          
    "HH:mm:ss",
          
    "HH:mm",
          
    "HH:mm:ss.FFFFFFF",
          
    "yy-MM-dd",
          
    "yyyy-MM-dd",
          
    "yyyy-MM-dd HH:mm:ss.FFFFFFF",
          
    "yyyy-MM-dd HH:mm:ss",
          
    "yyyy-MM-dd HH:mm",                               
          
    "yyyy-MM-ddTHH:mm:ss.FFFFFFF",
          
    "yyyy-MM-ddTHH:mm",
          
    "yyyy-MM-ddTHH:mm:ss",
          
    "yyyyMMddHHmmss",
          
    "yyyyMMddHHmm",
          
    "yyyyMMddTHHmmssFFFFFFF",
          
    "yyyyMMdd"
        };

    修改后的定义为:

    /// <summary>
        
    /// An array of ISO8601 datetime formats we support conversion from
        
    /// </summary>
        private static string[] _datetimeFormats = new string[] {
          
    "THHmmss",
          
    "THHmm",
          
    "HH:mm:ss",
          
    "HH:mm",
          
    "HH:mm:ss.FFFFFFF",
          
    "yy-M-d",
          
    "yy-M-dd",
          
    "yy-MM-dd",
          
    "yyyy-M-d",
          
    "yyyy-M-dd",
          
    "yyyy-MM-dd",
          
    "yyyy-M-d H:mm:ss.FFFFFFF",
          
    "yyyy-M-d H:mm:ss",
          
    "yyyy-M-d H:mm",                         
          
    "yyyy-M-d HH:mm:ss.FFFFFFF",
          
    "yyyy-M-d HH:mm:ss",
          
    "yyyy-M-d HH:mm",                               
          
    "yyyy-M-dTHH:mm:ss.FFFFFFF",
          
    "yyyy-M-dTHH:mm",
          
    "yyyy-M-dTHH:mm:ss",
          
    "yyyy-M-dd H:mm:ss.FFFFFFF",
          
    "yyyy-M-dd H:mm:ss",
          
    "yyyy-M-dd H:mm",                         
          
    "yyyy-M-dd HH:mm:ss.FFFFFFF",
          
    "yyyy-M-dd HH:mm:ss",
          
    "yyyy-M-dd HH:mm",                               
          
    "yyyy-M-ddTHH:mm:ss.FFFFFFF",
          
    "yyyy-M-ddTHH:mm",
          
    "yyyy-M-ddTHH:mm:ss",
          
    "yyyy-MM-dd H:mm:ss.FFFFFFF",
          
    "yyyy-MM-dd H:mm:ss",
          
    "yyyy-MM-dd H:mm",                         
          
    "yyyy-MM-dd HH:mm:ss.FFFFFFF",
          
    "yyyy-MM-dd HH:mm:ss",
          
    "yyyy-MM-dd HH:mm",                               
          
    "yyyy-MM-ddTHH:mm:ss.FFFFFFF",
          
    "yyyy-MM-ddTHH:mm",
          
    "yyyy-MM-ddTHH:mm:ss",
          
    "yyyyMMddHHmmss",
          
    "yyyyMMddHHmm",
          
    "yyyyMMddTHHmmssFFFFFFF",
          
    "yyyyMMdd",
          
    "yy/M/d",
          
    "yy/M/dd",
          
    "yy/MM/dd",
          
    "yyyy/M/d",
          
    "yyyy/M/dd",
          
    "yyyy/MM/dd",
          
    "yyyy/M/d H:mm:ss.FFFFFFF",
          
    "yyyy/M/d H:mm:ss",
          
    "yyyy/M/d H:mm",                         
          
    "yyyy/M/d HH:mm:ss.FFFFFFF",
          
    "yyyy/M/d HH:mm:ss",
          
    "yyyy/M/d HH:mm",                               
          
    "yyyy/M/dTHH:mm:ss.FFFFFFF",
          
    "yyyy/M/dTHH:mm",
          
    "yyyy/M/dTHH:mm:ss",
          
    "yyyy/M/dd H:mm:ss.FFFFFFF",
          
    "yyyy/M/dd H:mm:ss",
          
    "yyyy/M/dd H:mm",                         
          
    "yyyy/M/dd HH:mm:ss.FFFFFFF",
          
    "yyyy/M/dd HH:mm:ss",
          
    "yyyy/M/dd HH:mm",                               
          
    "yyyy/M/ddTHH:mm:ss.FFFFFFF",
          
    "yyyy/M/ddTHH:mm",
          
    "yyyy/M/ddTHH:mm:ss",
          
    "yyyy/MM/dd H:mm:ss.FFFFFFF",
          
    "yyyy/MM/dd H:mm:ss",
          
    "yyyy/MM/dd H:mm",                         
          
    "yyyy/MM/dd HH:mm:ss.FFFFFFF",
          
    "yyyy/MM/dd HH:mm:ss",
          
    "yyyy/MM/dd HH:mm",                               
          
    "yyyy/MM/ddTHH:mm:ss.FFFFFFF",
          
    "yyyy/MM/ddTHH:mm",
          
    "yyyy/MM/ddTHH:mm:ss"
        };

    然后重新编译一下,就OK了,您也可以根据具体的使用情况进行扩展。

    最后还有一种办法,就是Ticks,这种方案需要在连接字符串上设置,DateTimeFormat=Ticks(默认是ISO8601),这种方案和最开始的方案类似,第一种方案是转换为字符串,这种是转换为int64,然后由系统的转换方法实现转换。

     

    修改后的Sqlite,/Files/chinull/sqlite.rar

  • 相关阅读:
    使用Python进行文件操作
    Python学习笔记(六)Python组合数据类型
    python基本算法题(一)
    Python要如何实现(列表)排序?
    Python中输入和输出(打印)数据
    Python学习笔记(五)函数和代码复用
    关于Python缩进,我们该了解哪些?
    Python学习笔记(四)Python程序的控制结构
    Python学习笔记(三)字符串类型及其操作(2)
    Java视频按帧保存为图片
  • 原文地址:https://www.cnblogs.com/chinull/p/2168838.html
Copyright © 2020-2023  润新知