【问题标题】:Sqlite convert string to dateSqlite 将字符串转换为日期
【发布时间】:2011-05-24 15:34:22
【问题描述】:

我将日期作为字符串存储在 sqlite 数据库中,例如“28/11/2010”。 我想将字符串转换为日期。

具体来说,我必须在两个日期之间转换大量字符串日期。

在 postgresql 中,我使用 to_date('30/11/2010','dd/MM/yyyy'),如何使用 sqlite 做同样的事情?

类似这样的:

SELECT * FROM table
    WHERE   to_date(column,'dd/MM/yyyy')
    BETWEEN to_date('01/11/2010','dd/MM/yyyy')
    AND     to_date('30/11/2010','dd/MM/yyyy')

【问题讨论】:

标签: string sqlite date date-format


【解决方案1】:

作为 Sqlite doesn't have a date type,您需要进行字符串比较来实现这一点。为此,您需要颠倒顺序 - 例如从 dd/MM/yyyy 到 yyyyMMdd,使用类似

where substr(column,7)||substr(column,4,2)||substr(column,1,2) 
      between '20101101' and '20101130'

【讨论】:

  • +1:如果日期已被格式化为 SQLite 的日期处理函数可以理解的格式,则可以做一些更智能的事情。 (或者如果日期在存储到数据库之前已转换为儒略日。)但事实并非如此,并且“日期”需要修改。当然,他也可以尝试添加自己的to_date 函数,但具体怎么做取决于SQLite 嵌入了什么(我们不知道)。
  • @Donal 重新创建了自己的to_date 函数,有什么赌注不是该字段中的所有字符串都是无效日期:-)
【解决方案2】:

保存日期为 TEXT(20/10/2013 03:26) 查询和选择日期之间的记录?

更好的版本是:

SELECT TIMSTARTTIMEDATE 
FROM TIMER 
WHERE DATE(substr(TIMSTARTTIMEDATE,7,4)
||substr(TIMSTARTTIMEDATE,4,2)
||substr(TIMSTARTTIMEDATE,1,2)) 
BETWEEN DATE(20131020) AND DATE(20131021);

2013 年 10 月 20 日的 substr 给出 20131020 日期格式 DATE(20131021) - 这使得 SQL 可以处理日期并使用日期和时间函数。

SELECT TIMSTARTTIMEDATE 
FROM TIMER 
WHERE DATE(substr(TIMSTARTTIMEDATE,7,4)
||'-'
||substr(TIMSTARTTIMEDATE,4,2)
||'-'
||substr(TIMSTARTTIMEDATE,1,2)) 
BETWEEN DATE('2013-10-20') AND DATE('2013-10-21');

这是一行

SELECT TIMSTARTTIMEDATE FROM TIMER WHERE DATE(substr(TIMSTARTTIMEDATE,7,4)||'-'||substr(TIMSTARTTIMEDATE,4,2)||'-'||substr(TIMSTARTTIMEDATE,1,2)) BETWEEN DATE('2013-10-20') AND DATE('2013-10-21');

【讨论】:

    【解决方案3】:

    您应该研究的一件事是SQLite date and time functions,尤其是在您必须处理大量日期的情况下。这是使用日期的明智方式,但代价是更改了内部格式(必须是 ISO,即 yyyy-MM-dd)。

    【讨论】:

    • 该文档被反复引用...但是,IMO 需要对其进行重新修改才能快速找到信息。所有有意义的细节都被埋没了。例如,是否有可能在不到 10 秒的时间内一目了然地确定 strftime 函数的返回类型......?不 !在任何体面的 javadoc 中都是可行的。
    • 它被过度引用了,因为它更经常被忽略,但它可以通过返工来完成。
    【解决方案4】:

    与脆弱的 substr 值相比,我更喜欢 UDF 方法。

    #!/usr/bin/env python3
    import sqlite3
    from dateutil import parser
    from pprint import pprint
    
    
    def date_parse(s):
        ''' Converts a string to a date '''
        try:
            t = parser.parse(s, parser.parserinfo(dayfirst=True))
            return t.strftime('%Y-%m-%d')
        except:
            return None
    
    
    def dict_factory(cursor, row):
        ''' Helper for dict row results '''
        d = {}
        for idx, col in enumerate(cursor.description):
            d[col[0]] = row[idx]
        return d
    
    
    def main():
        ''' Demonstrate UDF '''
        with sqlite3.connect(":memory:") as conn:
            conn.row_factory = dict_factory
            setup(conn)
    
            ##################################################
            # This is the code that matters. The rest is setup noise.
            conn.create_function("date_parse", 1, date_parse)
            cur = conn.cursor()
            cur.execute(''' select "date", date_parse("date") as parsed from _test order by 2; ''')
            pprint(cur.fetchall())
            ##################################################
    
    def setup(conn):
        ''' Setup some values to parse '''
        cur = conn.cursor()
    
        # Make a table
        sql = '''
        create table _test (
            "id" integer primary key,
            "date" text
        );
        '''
        cur.execute(sql)
    
        # Fill the table
        dates = [
            '2/1/03', '03/2/04', '4/03/05', '05/04/06',
            '6/5/2007', '07/6/2008', '8/07/2009', '09/08/2010',
            '2-1-03', '03-2-04', '4-03-05', '05-04-06',
            '6-5-2007', '07-6-2008', '8-07-2009', '09-08-2010',
            '31/12/20', '31-12-2020',
            'BOMB!',
        ]
        params = [(x,) for x in dates]
        cur.executemany(''' insert into _test ("date") values(?); ''', params)
    
    
    if __name__ == "__main__":
        main()
    

    这将为您提供以下结果:

    [{'date': 'BOMB!', 'parsed': None},
     {'date': '2/1/03', 'parsed': '2003-01-02'},
     {'date': '2-1-03', 'parsed': '2003-01-02'},
     {'date': '03/2/04', 'parsed': '2004-02-03'},
     {'date': '03-2-04', 'parsed': '2004-02-03'},
     {'date': '4/03/05', 'parsed': '2005-03-04'},
     {'date': '4-03-05', 'parsed': '2005-03-04'},
     {'date': '05/04/06', 'parsed': '2006-04-05'},
     {'date': '05-04-06', 'parsed': '2006-04-05'},
     {'date': '6/5/2007', 'parsed': '2007-05-06'},
     {'date': '6-5-2007', 'parsed': '2007-05-06'},
     {'date': '07/6/2008', 'parsed': '2008-06-07'},
     {'date': '07-6-2008', 'parsed': '2008-06-07'},
     {'date': '8/07/2009', 'parsed': '2009-07-08'},
     {'date': '8-07-2009', 'parsed': '2009-07-08'},
     {'date': '09/08/2010', 'parsed': '2010-08-09'},
     {'date': '09-08-2010', 'parsed': '2010-08-09'},
     {'date': '31/12/20', 'parsed': '2020-12-31'},
     {'date': '31-12-2020', 'parsed': '2020-12-31'}]
    

    SQLite 等价于任何这种强大的东西是你应该避免的 substrinstr 调用的纠结编织。

    【讨论】:

      【解决方案5】:

      如果源日期格式不一致,则存在一些问题 带有substr函数,例如:

      1/1/2017 1/11/2017 11/11/ 2017 1/1/17 等等。

      所以我使用临时表遵循了不同的方法。如果存在,此 sn-p 输出 'YYYY-MM-DD' + 时间。

      请注意,此版本接受日/月/年格式。如果你想要月/日/年 交换前两个变量DayPartMonthPart。此外,两年日期 '44-'99 假定为 1944-1999,而 '00-'43 假定为 2000-2043。

       BEGIN;
      
          CREATE TEMP TABLE [DateconvertionTable] (Id TEXT PRIMARY KEY, OriginalDate  TEXT  , SepA  INTEGER,  DayPart TEXT,Rest1 TEXT, SepB  INTEGER,  MonthPart TEXT, Rest2 TEXT, SepC  INTEGER,  YearPart TEXT, Rest3 TEXT, NewDate TEXT);
          INSERT INTO [DateconvertionTable] (Id,OriginalDate)  SELECT SourceIdColumn, SourceDateColumn From  [SourceTable];
      
          --day Part (If day is first)
      
          UPDATE [DateconvertionTable] SET SepA=instr(OriginalDate ,'/');
          UPDATE [DateconvertionTable] SET DayPart=substr(OriginalDate,1,SepA-1) ;
          UPDATE [DateconvertionTable] SET Rest1=substr(OriginalDate,SepA+1);
      
          --Month Part (If Month is second)
      
          UPDATE [DateconvertionTable] SET SepB=instr(Rest1,'/');
          UPDATE [DateconvertionTable]  SET MonthPart=substr(Rest1, 1,SepB-1);
          UPDATE [DateconvertionTable] SET Rest2=substr(Rest1,SepB+1);
      
          --Year Part (3d)
      
          UPDATE [DateconvertionTable] SET SepC=instr(Rest2,' ');
      
                 --Use Cases In case of time string included
          UPDATE [DateconvertionTable]  SET YearPart= CASE WHEN SepC=0 THEN Rest2 ELSE substr(Rest2,1,SepC-1)  END;
      
                 --The Rest considered time
          UPDATE [DateconvertionTable]  SET Rest3= CASE WHEN SepC=0 THEN  '' ELSE substr(Rest2,SepC+1) END;
      
                 -- Convert 1 digit day and month to 2 digit
          UPDATE [DateconvertionTable] SET DayPart=0||DayPart WHERE CAST(DayPart AS INTEGER)<10;
          UPDATE [DateconvertionTable] SET MonthPart=0||MonthPart WHERE CAST(MonthPart AS INTEGER)<10;
      
                 --If there is a need to convert 2 digit year to 4 digit year, make some assumptions...
          UPDATE [DateconvertionTable] SET YearPart=19||YearPart WHERE CAST(YearPart AS INTEGER)>=44 AND CAST(YearPart AS INTEGER)<100;
          UPDATE [DateconvertionTable] SET YearPart=20||YearPart WHERE CAST(YearPart AS INTEGER)<44 AND CAST(YearPart AS INTEGER)<100;
      
          UPDATE [DateconvertionTable] SET NewDate = YearPart  || '-' || MonthPart || '-' || DayPart || ' ' || Rest3;  
      
          UPDATE [SourceTable] SET SourceDateColumn=(Select NewDate FROM DateconvertionTable WHERE [DateconvertionTable].id=SourceIdColumn);
          END;
      

      【讨论】:

      • 我搜索了几个小时,令人难以置信的是,人们建议这个糟糕的书面文档sqlite.org/lang_datefunc.html 没有关于如何解析具有不寻常的非正统日期格式的字符串的示例,例如 D /M/YYYY(由 fakenamegenerator 使用)或使用 substr,当日期不能有前导零时,它是无用的。这个脚本似乎是解决任何编程语言都可以通过指定任何非常规日期格式轻松解决的问题的唯一解决方案......真的哇。
      • 非常感谢。其实我想知道是否有人可以欣赏它!
      【解决方案6】:

      这是用于 fecha(TEXT) 格式日期 YYYY-MM-dd HH:mm:ss 例如我想要 Ene-05-2014 (2014-01-05) 的所有记录:

      SELECT 
       fecha 
      FROM 
       Mytable 
      WHERE 
       DATE(substr(fecha ,1,4) ||substr(fecha ,6,2)||substr(fecha ,9,2))
      BETWEEN 
       DATE(20140105) 
      AND 
       DATE(20140105);
      

      【讨论】:

      • 没有日期,即 (substr(fecha ,1,4) ||substr(fecha ,6,2)||substr(fecha ,9,2)) 在 (20140105) 和 (20140105) 之间为我工作
      【解决方案7】:

      我将日期存储为 'DD-MON-YYYY 格式(2016 年 6 月 10 日),下面的查询可让我搜索 2 个日期之间的记录。

      select date, substr(date,8,11) || '-' || substr(date,4,4) || substr(date, 1,2),  case 
      substr(date, 4,3) 
      when 'Jan' then strftime('%s', replace(substr(date,8,11) || '-' || substr(date,4,4) || substr(date, 1,2), 'Jan' , '01')) 
      when 'Feb' then strftime('%s', replace(substr(date,8,11) || '-' || substr(date,4,4) || substr(date, 1,2), 'Feb' , '02')) 
      when 'Mar' then strftime('%s', replace(substr(date,8,11) || '-' || substr(date,4,4) || substr(date, 1,2), 'Mar' , '03')) 
      when 'Apr' then strftime('%s', replace(substr(date,8,11) || '-' || substr(date,4,4) || substr(date, 1,2), 'Apr' , '04')) 
      when 'May' then strftime('%s', replace(substr(date,8,11) || '-' || substr(date,4,4) || substr(date, 1,2), 'May' , '05')) 
      when 'Jun' then strftime('%s', replace(substr(date,8,11) || '-' || substr(date,4,4) || substr(date, 1,2), 'Jun' , '06')) 
      when 'Jul' then strftime('%s', replace(substr(date,8,11) || '-' || substr(date,4,4) || substr(date, 1,2), 'Jul' , '07')) 
      when 'Aug' then strftime('%s', replace(substr(date,8,11) || '-' || substr(date,4,4) || substr(date, 1,2), 'Aug' , '08')) 
      when 'Sep' then strftime('%s', replace(substr(date,8,11) || '-' || substr(date,4,4) || substr(date, 1,2), 'Sep' , '09')) 
      when 'Oct' then strftime('%s', replace(substr(date,8,11) || '-' || substr(date,4,4) || substr(date, 1,2), 'Oct' , '10')) 
      when 'Nov' then strftime('%s', replace(substr(date,8,11) || '-' || substr(date,4,4) || substr(date, 1,2), 'Nov' , '11')) 
      when 'Dec' then strftime('%s', replace(substr(date,8,11) || '-' || substr(date,4,4) || substr(date, 1,2), 'Dec' , '12')) 
      else '0' end as srcDate from payment where srcDate >= strftime('%s', '2016-07-06') and srcDate <= strftime('%s', '2016-09-06');
      

      【讨论】:

        【解决方案8】:

        我有一个数据库,其中日期以 d F Y 格式(2017 年 11 月 20 日)存储并将其转换为机器可读的日期(Ymd),我使用此方法将整个表更新为正确的格式。

        如果您只想要日期格式,请查看内部选择我如何格式化日期。

        update TABLENAME as realTABLE set created_at = (
        select 
            -- Get Year
            substr(tmpTABLE.created_at ,-4, 4)
             || '-' ||
             -- Get Month
              substr(
                   replace (replace (replace (replace (replace (replace (replace (replace (replace (replace (replace (replace (tmpReis.szAanmaakDatum
                   , ' Dec ', '-12-') , ' Nov ', '-11-') , ' Oct ', '-10-') , ' Sep ', '-09-') , ' Aug ', '-08-') , ' Jul ', '-07-') , ' Jun ', '-06-') , ' May ', '-05-') , ' Apr ', '-04-') , ' Mar ', '-03-') , ' Feb ', '-02-') , ' Jan ', '-01-')
                   -- Get it from the original space location + 1, then get the two numbers.
                   ,instr(tmpTABLE.created_at, ' ')+1, 2)
             || '-' ||
             -- Get day, prepend with a zero if there's a zero lacking.
             substr('00' || tmpTABLE.created_at, -2, 2) as foo
        from TABLENAME as tmpTABLE 
        where tmpTABLE.id = realTABLE.id    
        -- Check for valid matching formats. don't do those that already were converted.
        ) where created_at like '_ ___ ____' 
        or created_at like '__ ___ ____';
        

        【讨论】:

          【解决方案9】:

          string 转换为 date 小问题认为索引 mmm 3,3 但在日期字符串上添加一个月的工作

          SELECT substr('12Jan20',1,2) as dday,
          date(substr('12Jan20',6,7) ||'00-' || case substr('12Jan20',3,3) when 'Jan' then '01'
          when 'Feb' then '02'
          when 'Mar' then '03'
          when 'Apr' then '04'
          when 'May' then '05' 
          when 'Jun' then '06'
          when 'Jul' then '07'
          when 'Aug' then '08'
          when 'Sep' then '09'
          when 'Oct' then '10'
          when 'Nov' then '11'
          when 'Dec' then '12' end  || '-'||substr('12Jan20',1,2), '+1 month') as tt
          

          【讨论】:

          • 感谢我的风格,确保我也理解这一点