【问题标题】:Oracle TO_DATE format, symbol for "any character"Oracle TO_DATE 格式,“任意字符”的符号
【发布时间】:2017-04-12 08:13:21
【问题描述】:

this answer 中建议使用以下查询:

SELECT TO_DATE(
         'Thu Nov 24 15:20:52 CET 2016',
         'DY MON DD HH24:MI:SS "CET" YYYY'
       )
FROM DUAL

¿ 在格式中使用了一些字符,意思是“任何”?我喜欢将格式字符串中的“CET”替换为“...”或“###”之类的内容,即:

'DY MON DD HH24:MI:SS ... YYYY'

一个例子,¿ 哪种格式将接受以下所有日期字符串:

2017-12-31
2017_12_31
2017x12x31

【问题讨论】:

    标签: oracle date parsing format


    【解决方案1】:

    您可以通过正则表达式提取相关部分。

    select 
    TO_DATE(
          regexp_substr('Thu Nov 24 15:20:52 CET 2016', '^.+\d{2}:\d{2}:\d{2}')
        ||regexp_substr('Thu Nov 24 15:20:52 CET 2016', ' \d{4}$'), 
        'DY MON DD HH24:MI:SS YYYY')
    from dual;
    

    select 
    TO_DATE(
       REGEXP_REPLACE('Thu Nov 24 15:20:52 CET 2016', '\w+ (\d{4})$', '\1'),
       'DY MON DD HH24:MI:SS YYYY')
    from dual;
    

    【讨论】:

      【解决方案2】:

      这是使用to_timestamp_tz的另一种方式:

      WITH sample_data AS (SELECT 'Thu Nov 24 15:20:52 CET 2016' str FROM dual UNION ALL
                           SELECT 'Fri Dec 11 23:16:39 PST 2015' str FROM dual)
      SELECT str,
             to_timestamp_tz(str, 'Dy Mon dd hh24:mi:ss TZR yyyy', 'nls_date_language = english') timestamp_at_orig_tz,
             CAST(to_timestamp_tz(str, 'Dy Mon dd hh24:mi:ss TZR yyyy', 'nls_date_language = english') AS DATE) dt,
             CAST(to_timestamp_tz(str, 'Dy Mon dd hh24:mi:ss TZR yyyy', 'nls_date_language = english') AT TIME ZONE '-5:00' AS DATE) dt_at_utc_minus_5,
             cast(sys_extract_utc(to_timestamp_tz(str, 'Dy Mon dd hh24:mi:ss TZR yyyy', 'nls_date_language = english')) AS DATE) dt_at_utc
      FROM   sample_data;
      
      STR                          TIMESTAMP_AT_ORIG_TZ             DT                  DT_AT_UTC_MINUS_5   DT_AT_UTC
      ---------------------------- -------------------------------- ------------------- ------------------- -------------------
      Thu Nov 24 15:20:52 CET 2016 24-NOV-16 15.20.52.000000000 CET 24/11/2016 15:20:52 24/11/2016 09:20:52 24/11/2016 14:20:52
      Fri Dec 11 23:16:39 PST 2015 11-DEC-15 23.16.39.000000000 PST 11/12/2015 23:16:39 12/12/2015 02:16:39 12/12/2015 07:16:39
      

      我给出了将时间戳作为字符串转换为日期的三种不同方法:

      1. 将时间戳原样转换为日期。请注意,这将丢失您拥有的所有时间戳信息 - 如果您真的不关心时区信息,这将非常有用。
      2. 将时间戳转换为特定时区(在我的示例中为 UTC - 5),然后再将其转换为日期。
      3. 在将时间戳转换为日期之前将其转换为 UTC(您可以使用前面的方法来执行此操作,但 sys_extract_utc() 更不言自明,恕我直言,这只会有助于可读性和可维护性!)。

      对于您更新的问题(似乎更多地围绕日期部分分隔符,而不是时区),以下应该可以解决问题:

      WITH sample_data AS (SELECT '2017-12-31' dt_str FROM dual UNION ALL
                           SELECT '2017_12_31' dt_str FROM dual UNION ALL
                           SELECT '2017x12x31' dt_str FROM dual)
      SELECT dt_str,
             to_date(regexp_replace(dt_str,
                                    '([[:digit:]]{4}).([[:digit:]]{2}).([[:digit:]]{2})',
                                    '\1-\2-\3'), 'yyyy-mm-dd')
      FROM   sample_data;
      
      DT_STR     DT
      ---------- ----------
      2017-12-31 31/12/2017
      2017_12_31 31/12/2017
      2017x12x31 31/12/2017
      

      【讨论】:

      • 对一般情况更感兴趣,不限于 CET 单词。如今,通常不允许使用“任何”符号的模式格式。有人建议使用“#”,但我的测试拒绝了它。
      • 我是通用的,但是?我在子查询中有两行为要处理的查询提供示例数据,其中之一是 CET,另一个是 PST。无论如何查询都有效。
      • 对不起,我的意思是,例如,接受三个字符串,如“2017-12-01”或“2017_12_01”或“2017x12x01”。我将对问题进行澄清。
      • 注意,TZR 表示“时区地区”,只有有限的地区名称使用缩写,请参阅SELECT * FROM V$TIMEZONE_NAMES WHERE tzabbrev = tzname;
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-07-31
      • 1970-01-01
      • 1970-01-01
      • 2010-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多