【问题标题】:How to convert Mon Dec 21 00:00:00 EST 2020 into dd/mm/yyyy in oracle sql如何在 oracle sql 中将 Mon Dec 21 00:00:00 EST 2020 转换为 dd/mm/yyyy
【发布时间】:2021-06-23 10:23:17
【问题描述】:

我们如何在 oracle SQL 中将“Mon Dec 21 00:00:00 EST 2020”转换为 dd/mm/yyyy?日期存储在数据类型 NVARCHAR2 中。

【问题讨论】:

  • Edit 问题并展示您已经尝试过的内容。解释失败的原因/位置。具体(错误消息、意外结果等)。
  • 好的,日期存储为NVARCHAR2(这并不理想-与您在此线程中的问题分开,您可能想调查为什么它不存储为TIMESTAMP WITH TIME ZONE)。请澄清你必须得到什么作为输出 - string?日期或带有时区的时间戳等没有“格式”,例如dd/mm/yyyy - 这种格式仅适用于日期或时间戳(有或没有时区)等的字符串表示 - 无论是在屏幕上或报告中显示它们,或者(可怕的做法!)将它们作为字符串存储在数据库中。所以,请澄清输出。
  • 我只需要这种 NVARCHAR2 格式的日期
  • 好的,但这是date 数据类型吗?还是某种字符串?而且,当您说“日期”时 - 您是否要删除时区规范以及时间(以便时间将是午夜,00:00:00)?您确实明白,Oracle 中的date总是 也有时间,对吧? (与其他一些数据库产品不同。)
  • 问题出在输入数据本身。 EST 并不含糊。但是 EDT 是模棱两可的——至少在 Oracle 中使用它作为时区区域的缩写。 EDT 适用于美国东部和加拿大,也适用于墨西哥坎昆和牙买加。后者在 2021 年不遵守夏令时;因此,如果不包括时区 region,则时区 DST 缩写无效,例如 'America/New_York''America/Cancun'。这是不将日期(以及带有时区的时间戳)存储为字符串的众多原因之一 - 您无法立即看到无效值。

标签: sql oracle oracle11g oracle10g


【解决方案1】:

以下是您如何接受输入为nvarchar2 并提供输出为varchar2(如果出于某种原因需要,您可以将其转换为nvarchar2 - 看看我是如何为输入做的)。

在大多数情况下,您只需要带有时区的时间戳来进行进一步计算 - 转换回字符串应该只是为人类可读报告准备结果时的最后一步。如果您在进一步计算中需要“结果”,只需去掉对to_char 的外部调用。

第三行代码显示了输入。我没有您的数据,所以我从头开始创建它 - 它是一个 nvarchar2 字符串,表示带有时区的时间戳,采用您向我们展示的格式。请注意对to_timestamp_tz 的调用中的语言 规范;如果没有它,如果您的默认值不是英语,“Mon”和“Dec”将导致抛出错误。

select to_char(
          to_timestamp_tz(
              to_nchar('Mon Dec 21 00:00:00 EST 2020'),
                       'Dy Mon dd hh24:mi:ss TZR yyyy',
                       'nls_date_language = english'),
          'dd/mm/yyyy') as result
from   dual
;

RESULT    
----------
21/12/2020

编辑

在进一步的 cmets 中,OP 询问了不同的输入字符串,其中 'EDT' 作为时区组件。

这是个问题。 EST 并不模棱两可,但 EDT 是模棱两可的,因为不同的时区区域使用 EDT 夏令时标记,并且它们不会在每年的同一时间全部更改为夏令时。与 EST 不同,EDT 必须在输入中显示实际时区区域名称; EDT 真的不是时区区域,它只是不同区域的 DST 标记,不能单独使用它来识别正确的区域。

OP 声明所有输入都应该在'America/New_York' 区域中。如果是这样,则可以将其添加(连接)到输入中,并且可以更改格式模型以添加 TZR 元素,如下所示。我只展示了我们从字符串转换为带有时区的时间戳的部分;其余的不需要改变。

注意——查询结果中的ts是数据类型timestamp with time zone;它在输出中看起来像字符串(以特定格式),因为输出总是显示字符串,但实际上如果需要,结果是用于进一步处理的正确数据类型 - 例如,如果必须只选择时间戳是 2021 年等。特别是,可以将 to_char 应用于结果,使用 `dd/mm/yyyy' 格式模型,以匹配 OP 的原始请求。

with
  inputs (ts) as (
    select 'Mon Dec 21 00:00:00 EST 2020' from dual union all
    select 'Thu Mar 18 00:00:00 EDT 2021' from dual
  )
select to_timestamp_tz(ts || ' America/New_York',
                       'Dy Mon dd hh24:mi:ss TZD yyyy TZR',
                       'nls_date_language = english') as ts
from   inputs
;

TS                                          
--------------------------------------------
2020-12-21 00:00:00.000 America/New_York EST
2021-03-18 00:00:00.000 America/New_York EDT

【讨论】:

  • @Ankit - 第一步是从 nvarchar2 转换为带时区的时间戳 - 无论您在第二步中如何使用它。如果需要转换为日期(不是字符串),可以使用cast( ... as date) 而不是to_char( ... , 'dd/mm/yyyy')。如果您想转换为截断时间的日期(最接近 Oracle 中的“纯日期”),请使用 trunc( ... ) - 这将转换为日期,它会丢弃时区并截断日期同时到午夜 (00:00:00)。在所有这些示例中,... 是带有时区的时间戳。
  • 感谢您的帮助...您也可以帮助我完成上述示例吗?其中时区是 EDT...在这种情况下我遇到了错误。
  • 我在数据库生产中存储了这个日期“Mon Mar 22 00:00:00 EDT 2021”,并且在转换时出现错误。你能帮忙吗?
猜你喜欢
  • 2020-11-11
  • 2016-09-24
  • 1970-01-01
  • 1970-01-01
  • 2022-11-03
  • 2019-07-19
  • 1970-01-01
  • 2014-06-08
  • 1970-01-01
相关资源
最近更新 更多