【问题标题】:Why is Tuesday sometimes Sunday?为什么周二有时是周日?
【发布时间】:2015-10-27 09:16:16
【问题描述】:

select to_char(sysdate, 'DAY') from dual; 将正确返回TUESDAY

但是为什么我当天运行select to_char(to_date(sysdate, 'DD-MON-YYYY'), 'DAY') from dual;,却返回SUNDAY

由于在尝试运行 select to_date('27-OCT-15', 'D') from dual; 时出现 ORA-01835: day of week conflicts with Julian date 错误,我必须在尝试获取日期之前将日期(我动态传递给函数)转换为 DD-MON-YYYY 格式一周。有谁知道我为什么会看到这种不一致?

这里有一个更好的例子(我在例子中替换了列名和表名)。

SELECT  DATE, 
    to_char(DATE, 'DAY'), 
    to_char(to_date(DATE, 'DD-MON-YYYY'), 'DAY') 
FROM    DATES
ORDER BY DATE;

结果是;

DATE      TO_CHAR(D TO_CHAR(T
--------- --------- ---------
19-OCT-15 MONDAY    SATURDAY
19-OCT-15 MONDAY    SATURDAY
19-OCT-15 MONDAY    SATURDAY
21-OCT-15 WEDNESDAY MONDAY
21-OCT-15 WEDNESDAY MONDAY
02-NOV-15 MONDAY    SATURDAY
02-NOV-15 MONDAY    SATURDAY

【问题讨论】:

  • 我得到的是ORA-01843: not a valid month,而不是SUNDAY。您的服务器的默认日期格式是什么?
  • 因为to_date返回一周的第一天-SUNDAY
  • @ÁlvaroG.Vicario 不能 100% 确定这是否是您要查找的内容,但我的 NLS_DATE_LANGUAGEAMERICAN
  • to_date(sysdate?真的吗? sysdate 是一个日期,您不需要将日期转换为日期。
  • @Dr R Dizzle 系统日期或日期,没关系。 TO_DATE 将 CHAR、VARCHAR2、NCHAR 或 NVARCHAR2 数据类型的字符转换为 DATE 数据类型的值。如果你输入日期数据类型,那么你应该准备好隐式类型转换和 nls 设置的任何问题。

标签: sql oracle date


【解决方案1】:

to_date(系统日期

切勿在 DATE 应用 TO_DATE。它迫使甲骨文:

  • 先转成字符串
  • 然后将其转换回日期

基于特定于区域设置的 NLS 设置。您需要 TO_DATE 将文字转换为日期。对于date-arithmetic,保留日期不变。

SQL> SELECT to_char(to_date('27-OCT-2015', 'DD-MON-YYYY'), 'DAY') FROM dual;

TO_CHAR(T
---------
TUESDAY

根本原因

SQL> alter session set nls_date_format='DD-MON-RR';

Session altered.

SQL> select to_char(to_date(sysdate,'DD-MON-YYYY'),'DD-MON-YYYY') from dual;

TO_CHAR(TO_
-----------
27-OCT-0015

所以年份改为0015。因为,您将 RR 格式转换为 YYYY 的值已经是 DATE

现在,0015 年 10 月第 27 天星期日

SQL> select to_char(to_date('27-OCT-0015','DD-MON-YYYY'),'DAY') FROM DUAL;

TO_CHAR(T
---------
SUNDAY

要了解内部行为,让我们看一个小演示:

SQL> SET AUTOT ON EXPLAIN
SQL> SELECT * FROM dual WHERE SYSDATE = TO_DATE(SYSDATE);

no rows selected


Execution Plan
----------------------------------------------------------
Plan hash value: 3752461848

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     1 |     2 |     2   (0)| 00:00:01 |
|*  1 |  FILTER            |      |       |       |            |          |
|   2 |   TABLE ACCESS FULL| DUAL |     1 |     2 |     2   (0)| 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(SYSDATE@!=TO_DATE(TO_CHAR(SYSDATE@!)))

你看到filter(SYSDATE@!=TO_DATE(TO_CHAR(SYSDATE@!)))。过滤器发生了什么?

SYSDATE

TO_DATE 在内部解释为TO_DATE(TO_CHAR(SYSDATE@!))

因此,首先应用 TO_CHAR,其格式取决于您的本地 NLS_DATE_FORMAT,然后转换回 DATE


更新基于以下 OP 的 cmets...

用途:

  • TO_DATE 将日期文字(字符串)转换为 DATE。由于 TO_DATE 依赖于 NLS,因此我更愿意在单个语句级别明确提及格式和 NLS_DATE_LANGUAGE
SQL> 更改会话集 nls_date_format='YYYY-MM-DD'; 会话已更改。 SQL> SELECT TO_DATE('27-OCT-2015', 'DD-MON-YYYY','NLS_DATE_LANGUAGE=ENGLISH') 2 来自双重; TO_DATE('2 ---------- 2015-10-27

如果您依赖客户的 NLS 设置,它可能不适用于在某些不同位置使用不同 NLS 的人。

SQL> alter session set NLS_DATE_LANGUAGE='FRENCH';

Session altered.

SQL> SELECT TO_DATE('27-OCT-2015', 'DD-MON-YYYY') from dual;
SELECT TO_DATE('27-OCT-2015', 'DD-MON-YYYY') from dual
               *
ERROR at line 1:
ORA-01843: not a valid month
  • TO_CHAR 将 DATE 转换为字符串,以便使用适当的 FORMAT MODEL所需格式显示。。李>

反之亦然。

【讨论】:

  • 在这种情况下,为什么当我运行select to_char('27-OCT-2015', 'DAY') FROM DUAL;select to_char('27-OCT-2015', 'DAY') FROM DUAL; 时我得到ORA-01722: invalid number?没有to_date,它将无法工作(对我而言)。
  • 为什么要使用 TO_CHAR 将字符串转换回字符串?您所做的一切从根本上来说都是错误的。您必须使用 TO_DATE 将其转换为日期。
  • 因为这是我让它在没有错误消息的情况下返回的唯一方法 - 使用 TO_DATE 给我day of week conflicts with Julian datenot a valid day of the week
  • 你有DATE还是STRING
  • @DrRDizzle 所以,你得到一个日期,只需使用SELECT TO_CHAR(passed_date, 'DAY') into some_variable FROM DUAL; 否则,如果它不是日期而是字符串,则使用上面给出的查询。
【解决方案2】:

因为sysdate 已经是日期,所以这个表达式:

to_date(sysdate, 'DD-MON-YYYY')

... 既多余又脆弱。您要求 Oracle 使用当前具有的任何值 NLS_DATE_FORMATNLS_TERRITORYNLS_LANGUAGE 将日期转换为字符串,然后使用固定(可能不同)格式将其解析为日期。垃圾进,垃圾出。

几个提示:

  1. 不要在没有充分理由的情况下对日期进行字符串化。
  2. 来回投射时,请始终指定格式。

我也不太喜欢使用月份名称作为交换格式;我认为数字不太容易出错。

【讨论】:

    【解决方案3】:

    当您的nls_date formatDD-MON-RR 时,转换:

    to_date(sysdate,'dd-mon-yyyy')
    

    将生成字符串 27-10-0015(其中 sysdate 为 2015-10-27)。

    在 15 年,10 月 27 日是一个星期日 - 在当时不存在的公历中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-30
      • 1970-01-01
      • 1970-01-01
      • 2011-10-21
      • 2011-09-14
      • 2020-08-12
      相关资源
      最近更新 更多