【问题标题】:Converting timestamp to date in Oracle 12c在 Oracle 12c 中将时间戳转换为日期
【发布时间】:2018-12-20 13:38:47
【问题描述】:

我想将这样格式的给定时间戳:2019-04-08 00:00:00.0 转换成这样格式的日期:2019-04-08

我已经尝试过使用:

SELECT TO_DATE('2019-04-20 00:00:00.0','YYYY-MM-DD') from dual; 

但我得到了提示:

ORA-01830: 日期格式图片在转换整个输入之前结束 字符串

【问题讨论】:

  • 这个时间戳是一个字符串(文本),还是一个实际的 Oracle 时间戳?
  • Oracle 中有关日期和时间戳的混淆通常来自于没有意识到这些是以内部二进制格式存储的本机数据类型,并且仅在需要用于显示目的时才提供方便的人类可读格式。当开发人员假设'2019-04-20 00:00:00.0' 之类的东西实际上只是一个字符串时,它的乐趣就开始了。要将实际的 timestamp 转换为实际的 date,您只需使用 cast,就像 Littlefoot 的回答一样,但我怀疑这不是您在这里面临的情况。
  • 在这里查看我的答案:stackoverflow.com/a/51492266/2141278

标签: sql oracle oracle12c


【解决方案1】:

我认为您可能对 TO_DATE 函数的工作原理以及 DBMS 如何处理日期存在一些概念性误解。

YYY-MM-DD 与您要导入的实际字符串的格式不匹配 (2019-04-20 00:00:00.0) 这就是错误告诉您的内容。您必须告诉 TO_DATE 函数在您 输入 的日期字符串中期望什么。您可以通过格式字符串来做到这一点。如果您没有指定与您实际要提供的格式匹配的格式字符串,则该函数将无法处理该字符串。

接下来,您说您想将其“转换为这种格式的日期”……但这并不完全有意义。 TO_DATE 将字符串转换为 DATETIME 类型的变量 - 即日期对象。日期对象不以任何特定格式存在,它作为对象存在。在内部,它将以独立于任何人类可读日期格式的方式存储日期信息。当被视为 string 时,该格式完全与日期的 presentation 相关。一旦你有了一个日期对象,你就可以输出特定格式的日期,如果你想让人们能够以他们熟悉的文化风格来阅读它。

因此,首先要将您的日期字符串正确导入为日期对象,您可以使用准确的格式字符串,也可以使用 TO_TIMESTAMP 而不是 TO_DATE 以便捕获亚秒值:

SELECT TO_TIMESTAMP('2019-04-20 00:00:00.0','YYYY-MM-DD HH24:MI:SS.FF5') from dual; 

如果您在控制台中运行此操作,则 SELECT 将自动将该日期对象(TO_DATE 函数的结果)重新格式化为您的服务器/会话中配置的默认日期格式。

但是,如果您真的想以特定格式在屏幕上看到它,您可以明确地说出来 - 一个明智的方法是使用 TO_CHAR 函数:

SELECT TO_CHAR(TO_TIMESTAMPT('2019-04-20 00:00:00.0','YYYY-MM-DD HH24:MI:SS.FF5'), 'YYYY-MM-DD') from dual;

格式说明符的完整列表可以在here 找到(也可以在其他在线地方找到)。

以上内容的现场演示:https://dbfiddle.uk/?rdbms=oracle_18&fiddle=619d918ea73953e11b3150c6b560112c

【讨论】:

  • 嘿;我重新考虑了我的原始评论(因此我删除了它),因为您的查询似乎适用于 18c。但是,您在亚秒内使用sssss,但它实际上应该是ff5。例如。 SELECT TO_DATE('2019-04-20 00:00:01.12345','YYYY-MM-DD HH24:MI:SS.SSSSS') from dual;ORA-01836: hour conflicts with seconds in day 失败;它似乎只起作用,因为 OP 的日期字符串的秒数为 0。
  • @Boneist 你确实又是正确的。请参阅编辑 - 非常感谢。
【解决方案2】:

假设输入是实际文本,而不是真正的时间戳,您可以尝试在调用 TO_DATE 之前截断文本:

WITH cte AS (
    SELECT '2019-04-20 00:00:00.0' AS ts FROM dual
)

SELECT TO_DATE(SUBSTR(ts, 1, 10), 'YYYY-MM-DD')
FROM cte;

如果您的输入是一个实际的 Oracle 时间戳,并且您想将其转换为日期,那么您可以使用CAST

SELECT CAST(ts AS DATE) dt
FROM cte;

【讨论】:

  • 我会选择trunc(ts)而不是演员,因为演员会留下时间元素(尽管没有亚秒),甚至to_char(ts, 'yyyy-mm-dd')
  • @Boneist 在对您的评论采取行动之前,我将等待 OP 的反馈,但感谢您的意见。
【解决方案3】:

CAST会有什么好处吗?

我正在设置日期格式,以便它显示 时间 组件,虽然它是 00:00:

SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';

Session altered.

SQL> select cast(timestamp '2019-04-20 00:00:00.0' as date) result from dual;

RESULT
-------------------
20.04.2019 00:00:00

另一种格式(没有时间成分):

SQL> alter session set nls_date_format = 'dd.mm.yyyy';

Session altered.

SQL> select cast(timestamp '2019-04-20 00:00:00.0' as date) result from dual;

RESULT
----------
20.04.2019

SQL>

或者,使用TO_CHAR 函数(这样会话的日期格式无关紧要):

SQL> select to_char(timestamp '2019-04-20 00:00:00.0', 'dd.mm.yyyy') result from dual;

RESULT
----------
20.04.2019

SQL>

【讨论】:

  • 如果你使用 to_char,为什么不只是在时间戳本身上使用 to_char,而不是先转换它?
  • 这是个好问题,@Boneist。没有特别的原因,也许是一两个借口 - 我不得不离线并复制/粘贴相同的代码并稍微修改它,而没有过多考虑我在做什么。我修好了它;谢谢你的评论。
猜你喜欢
  • 2016-09-30
  • 1970-01-01
  • 2016-06-07
  • 1970-01-01
  • 1970-01-01
  • 2016-11-26
  • 1970-01-01
  • 2018-03-27
  • 2020-10-19
相关资源
最近更新 更多