【问题标题】:Converting a NVARCHAR into a UK date将 NVARCHAR 转换为英国日期
【发布时间】:2019-11-15 14:25:31
【问题描述】:

我希望将用户输入的 NVARCHAR 转换为英国日期

用户的输入将始终最多为 6 位数字。

例如:

151119 (DDMMYY) --> 15NOV19

120119 (DDMMYY) --> 12JAN19

【问题讨论】:

  • 不难,但乏味。 T-SQL 中没有任何内容可以为您提供月份名称,因此您需要SUBSTRING 和一大堆CASE ... WHEN '01' THEN 'JAN' WHEN '02' THEN 'FEB' ... END。当然,一般来说,您最好使用像yyyy-MM-dd 这样的明确格式,将日期存储为DATE 列并将格式留给客户端。
  • @JeroenMostert - DATENAMEFORMAT 都可以提供月份名称
  • @MartinSmith:我说完就想到了FORMAT,但我从来没有用过DATENAME。 (鉴于其特定于文化的输出,现在我知道了,我永远不会知道。但是,嘿,它是一些东西。)
  • 是的,这就是为什么你真的想在DATE 列中存储日期。虽然您可以将字符串转换为 DATE ((通过适当的应用 STUFFCONVERT)然后 FORMAT 它,这比仅仅做一个子字符串和 CASE 舞蹈更加笨拙和迂回。有还有两位数年份不明确的问题。SELECT UPPER(FORMAT(CONVERT(DATE, STUFF(STUFF('151119', 3, 0, '-'), 6, 0, '-'), 5), 'ddMMMyy', 'en-GB')) 看起来对你有吸引力吗?对我来说看起来很可怕。
  • 不要允许这样的输入开始。到底19是哪一年?所有 UI 平台都有日期选择器,所有语言都支持日期类型。即使你说cutoff year,未来也会发生变化。如果您在谷歌上搜索15 november 1919,您会发现许多网站都存储了此类日期,并且可以告诉您,例如红军于 1919 年 11 月 14 日攻占鄂木斯克

标签: sql-server tsql date ssms


【解决方案1】:

您首先需要一个有效的 DATEDATETIME / DATETIME2 值。您可以使用此 SELECT 查询和 CONVERT 获取此值:

SELECT CONVERT(DATE, 
  SUBSTRING('151119', 3, 2) + '-'
  + SUBSTRING('151119', 1, 2) + '-'
  + SUBSTRING('151119', 5, 2)
, 10);

现在您有两种可能以预期格式 (DDMMMYY) 获取日期。

1 - 使用DATENAME的解决方案:

-- set the date value (from custom date value).
DECLARE @dDateValue AS DATE = CONVERT(DATE, 
  SUBSTRING('150419', 3, 2) + '-'
  + SUBSTRING('150419', 1, 2) + '-'
  + SUBSTRING('150419', 5, 2)
, 10);

-- format the date value to the expected format.
SELECT DATENAME(DD, @dDateValue) + 
  UPPER(LEFT(DATENAME(MM, @dDateValue), 3)) + 
  RIGHT(DATENAME(YY, @dDateValue), 2);

2 - 使用CONVERT的解决方案:

-- set the date value (from custom date value).
DECLARE @dDateValue AS DATE = CONVERT(DATE, 
  SUBSTRING('150419', 3, 2) + '-'
  + SUBSTRING('150419', 1, 2) + '-'
  + SUBSTRING('150419', 5, 2)
, 10);

-- format the date value to the expected format.
SELECT UPPER(REPLACE(CONVERT(VARCHAR, @dDateValue, 6), ' ', ''));

demo on dbfiddle.uk


注意:我建议将日期值存储在具有DATEDATETIME 数据类型的列上。您可以在应用程序上格式化日期值,也可以直接在 SQL-Server 上使用格式化函数。

【讨论】:

  • 由于DATENAME 取决于语言,您可以在SET LANGUAGE French 下使用150419 等日期获得惊喜。当然,获取特定语言的日期可能正是您想要的,具体取决于用例。 (可能有些语言的月份的三个字母名称不是月份名称的前三个字母,所以这首先不起作用,尽管我不知道是否有。)
【解决方案2】:

你需要把字符串改成看起来有点像普通日期格式的东西,然后你可以使用转换:

declare @textDate nvarchar(6) = '120119';

select @textDate
    , stuff(stuff(@textDate, 3,0,'/'), 6,0,'/')
    , convert(date, stuff(stuff(@textDate, 3,0,'/'), 6,0,'/'), 3);

给:120119,12/01/19,2019-01-12 由于最后一个是有效的日期数据类型,您现在可以使用Format()

虽然首先显然 2 位数的年份是个坏主意。

忘了说,3代表英国2位格式(dd/mm/yy),其他选项可以看here

【讨论】:

    【解决方案3】:

    我强烈建议在 AS DATE 或 DATETIME 类型的列上使用日期值。这是一个满足您需要的简单实现:

    SQL Fiddle

    MS SQL Server 2017 架构设置

    create table test (mydate nvarchar(6))
    insert into test (mydate)values('151119')
    insert into test (mydate)values('120119')
    

    查询 1

    select FORMAT(CONVERT(DATE, dates), 'dd/MM/yyyy ')   from (select left(mydate,2)
    + 
    CASE  SUBSTRING(mydate, 3, 2)
           WHEN '01' THEN 'JAN'
           WHEN '02' THEN 'FEB'
           WHEN '03' THEN 'MAR'
           WHEN  '04' THEN 'APR'
           WHEN '05' THEN 'MAY'
           WHEN '06' THEN 'JUN'
           WHEN '07' THEN 'JUL'
           WHEN '08' THEN 'AUG'
           WHEN '09' THEN 'SEP'
           WHEN '10' THEN 'OCT'
           WHEN '11' THEN 'NOV'
           WHEN '12' THEN 'DEC'
           ELSE 'error'
    END
    + right(mydate,2) AS 'dates'
    from test ) AS T
    

    Results

    |             |
    |-------------|
    | 15/11/2019  |
    | 12/01/2019  |
    

    【讨论】:

    • A simple CASE 将适用,因为只检查一个值并且不需要likecase Substring( MyDate, 3, 2 ) when '01' then 'JAN' when '02' then 'FEB' ... else 'Thanks for playing!' end
    • 我会完全省略ELSE——结果表达式将变成NULL,它非常明显并且很容易诊断(而不是字符串可能变得太长,或者更糟的是,被“错误”默默地接受)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多