SQL Serverの文字列から日付への変換


186

このような文字列を変換したい:

'10/15/2008 10:06:32 PM'

SQL Serverの同等のDATETIME値に。

オラクルでは、私はこれを言うでしょう:

TO_DATE('10/15/2008 10:06:32 PM','MM/DD/YYYY HH:MI:SS AM')

この質問は、文字列を標準形式の 1つに解析し、それらのコードの1つを使用して変換する必要があることを意味しています。それは、そのような平凡な操作にとってばかげているようです。もっと簡単な方法はありますか?


回答:


28

SQL Server(2005、2000、7.0)には、任意に構造化された日付時刻を文字列形式で取得し、それを日付時刻データ型に変換する柔軟性のある、または柔軟性のない方法さえありません。

「恣意的に」とは、「それを書いた人が、おそらくあなたや私ではなく、地球の反対側にいる誰かが、直感的で完全に明白であると考える形態」を意味します。正直なところ、そのようなアルゴリズムがあるかどうかはわかりません。


32
そのようなアルゴリズムがあり、Oracleはすでにそれを実装しており、SQL Serverに同等のアルゴリズムがないことは常に問題です。
マタオ2012年

19
@mataoだから教えてください、入力9/6/12したユーザーが2012年9月6日、2012年6月9日、2009年12月6日などを意味するかどうか、Oracleはどのように魔法のように判断しますか?
アーロンバートランド

13
ここでは心配ない、:techonthenet.com/oracle/functions/to_date.phpは明らかにそれは、あなたが開発者に指定することを一貫性のある形式である必要がありますが、痛みを伴うカスタム解析における結果MSがあなたに与え書式マスクの一握りよりもはるかに多くの柔軟。
マタオ2013年

3
@JosphStyonsは、彼のサンプルに示すように、OracleのTO_DATE関数を認識していました。彼は、文字列の形式/構造を知らなくても、日付としての文字列を文字列に変換する方法があるかどうかを知りたがっていました。SQLはそれを行わず、OracleのTO_DATEもそれを行わないようです。
フィリップケリー2013年

23
@PhilipKelley OPがフォーマットを知らなくてもそれを行う方法を知りたい場所がわかりません。彼は明示的にフォーマットを知っていると述べ、SQL ServerにTO_DATEと同等のもの、つまり開発者が任意のフォーマット文字列を入力できるものがあるかどうかを尋ねています。
neverfox

306

これを試して

Cast('7/7/2011' as datetime)

そして

Convert(varchar(30),'7/7/2011',102)

詳細については、CASTおよびCONVERT(Transact-SQL)を参照してください。


14
これは正しい方法であり、正解としてマークする必要があります。Cast('2011-07-07' as datetime)も機能し、月と日の順序のあいまいさを排除することに注意してください。
Joe DeRose、2015

これは、月が12を超える場合は機能しません。書式設定ではmm / dd / yyyy形式が想定されます
Chakri

dd / mm / yyyyから変換する場合はConvert(varchar(30)、 '7/7/2011'、103)を使用します
Matias Masso

2
@Chakri日付がdd / mm / yyyyの場合はSET DATEFORMAT dmy、クエリの前に使用してください
Nathan Griffiths

49

これをクエリプロセッサで実行します。日付や時刻をそのようにフォーマットし、これらの1つがあなたが探しているものを与えるはずです。適応するのは難しくありません:

Declare @d datetime
select @d = getdate()

select @d as OriginalDate,
convert(varchar,@d,100) as ConvertedDate,
100 as FormatValue,
'mon dd yyyy hh:miAM (or PM)' as OutputFormat
union all
select @d,convert(varchar,@d,101),101,'mm/dd/yy'
union all
select @d,convert(varchar,@d,102),102,'yy.mm.dd'
union all
select @d,convert(varchar,@d,103),103,'dd/mm/yy'
union all
select @d,convert(varchar,@d,104),104,'dd.mm.yy'
union all
select @d,convert(varchar,@d,105),105,'dd-mm-yy'
union all
select @d,convert(varchar,@d,106),106,'dd mon yy'
union all
select @d,convert(varchar,@d,107),107,'Mon dd, yy'
union all
select @d,convert(varchar,@d,108),108,'hh:mm:ss'
union all
select @d,convert(varchar,@d,109),109,'mon dd yyyy hh:mi:ss:mmmAM (or PM)'
union all
select @d,convert(varchar,@d,110),110,'mm-dd-yy'
union all
select @d,convert(varchar,@d,111),111,'yy/mm/dd'
union all
select @d,convert(varchar,@d,12),12,'yymmdd'
union all
select @d,convert(varchar,@d,112),112,'yyyymmdd'
union all
select @d,convert(varchar,@d,113),113,'dd mon yyyy hh:mm:ss:mmm(24h)'
union all
select @d,convert(varchar,@d,114),114,'hh:mi:ss:mmm(24h)'
union all
select @d,convert(varchar,@d,120),120,'yyyy-mm-dd hh:mi:ss(24h)'
union all
select @d,convert(varchar,@d,121),121,'yyyy-mm-dd hh:mi:ss.mmm(24h)'
union all
select @d,convert(varchar,@d,126),126,'yyyy-mm-dd Thh:mm:ss:mmm(no spaces)'

47

SQL Server Denaliでは、探しているものに近づくことができます。しかし、任意に定義された奇抜な日付文字列を渡して、SQL Serverが対応できると期待することはできません。自分の回答で投稿したものを使用した例を1つ示します。FORMAT()関数は、オプションの引数としてロケールを受け入れることもできます。これは.Netの形式に基づいているため、表示されると予想されるほとんどすべてのトークン形式が存在します。

DECLARE @d DATETIME = '2008-10-13 18:45:19';

-- returns Oct-13/2008 18:45:19:
SELECT FORMAT(@d, N'MMM-dd/yyyy HH:mm:ss');

-- returns NULL if the conversion fails:
SELECT TRY_PARSE(FORMAT(@d, N'MMM-dd/yyyy HH:mm:ss') AS DATETIME);

-- returns an error if the conversion fails:
SELECT PARSE(FORMAT(@d, N'MMM-dd/yyyy HH:mm:ss') AS DATETIME);

日付の入力をより細かく制御してサニタイズすることを強くお勧めします。人々がフリーテキストフォームフィールドに好きな形式を使用して日付を入力できるようになった時代は、今ではかなり遅れているはずです。誰かが2011年8月9日と入力した場合、それは8月9日か9月8日ですか?カレンダーコントロールで日付を選択させると、アプリで形式を制御できます。ユーザーの行動をどれほど予測しようとしても、ユーザーは計画していない日付を入力するための気の利いた方法を常に理解します。

しかし、デナリまでは、@ Ovidiuがこれまでのところ最高のアドバイスを持っていると思います...これは、独自のCLR関数を実装することでかなり簡単にすることができます。その後、必要な数の奇抜な非標準形式のケース/スイッチを作成できます。


@dhergertの更新

SELECT TRY_PARSE('10/15/2008 10:06:32 PM' AS DATETIME USING 'en-us');
SELECT TRY_PARSE('15/10/2008 10:06:32 PM' AS DATETIME USING 'en-gb');

結果:

2008-10-15 22:06:32.000
2008-10-15 22:06:32.000

それでも、他の重要な情報を最初に用意する必要があります。ネイティブT-SQLを使用して、6/9/20126月9日か9月6日かを判別することはできません。


1
問題は、文字列を日時に変換するのではなく、日時に文字列を変換する方法だったと思います。
David Hergert、

1
TRY_PARSEは完璧でした。共有していただきありがとうございます、日付「2016年9月22日(木)」の解析に問題がありました。
Simon

11

この問題の解決策として、SQL Server 2005でCLR関数を使用して、DateTime.Parse関数またはParseExact関数のいずれかを使用し、指定された形式でDateTime値を返す方法を使用します。



8

やってみませんか

select convert(date,'10/15/2011 00:00:00',104) as [MM/dd/YYYY]

日付形式は、SQL Server Helper> SQL Server Date Formatsにあります。


コード例は機能しません。「文字列から日付や時刻を変換するときに変換に失敗しました。」
セザール・レオン

5
する必要がありますselect convert(date,'10/15/2011 00:00:00',101)docs.microsoft.com/en-us/sql/t-sql/functions/…で
anotherUser

1
8人がこの回答に賛成票を投じましたが、
それでもうまくいき

4

これを理解するのに少し時間がかかったので、誰かを助けるかもしれない場合のためにここにあります:

SQL Server 2012以降では、この関数を使用できます。

SELECT DATEFROMPARTS(2013, 8, 19);

これが、この関数に入れる日付の一部を抽出する方法です。

select
DATEFROMPARTS(right(cms.projectedInstallDate,4),left(cms.ProjectedInstallDate,2),right( left(cms.ProjectedInstallDate,5),2)) as 'dateFromParts'
from MyTable

3

このページには、CONVERT関数で使用できる、指定されたすべての日時変換のリファレンスがあります。値が許容可能なパターンの1つに該当しない場合は、ParseExactルートを使用するのが最善の方法だと思います。


リンクが壊れています。
マイケルポッター、

3

個人的に、あなたが任意または完全に壁のフォーマットを扱う場合、事前に知っているか、または予定していることがわかっていれば、正規表現を使用して、希望する日付のセクションをプルし、有効な日付/日付時刻コンポーネントを形成します。


1

私はこれがたくさんの答えを持つ邪悪な古い投稿であることを知っていますが、多くの人々は、物事をバラバラにしてそれらを元に戻す必要があると考えるか、OPオリジナルが要求した変換を暗黙的に行う方法はないと主張します。

確認し、同じ質問で他の人に簡単に答えられるようにするために、OPは「10/15/2008 10:06:32 PM」をDATETIMEに変換する方法を尋ねました。現在、SQL Serverには時間変換にいくつかの言語依存関係がありますが、言語が英語またはそれに類似したものである場合、これは簡単な問題になります...変換を実行するだけで、形式について心配する必要はありません。たとえば(そしてCONVERTまたはCASTを使用できます)...

 SELECT UsingCONVERT = CONVERT(DATETIME,'10/15/2008 10:06:32 PM')
        ,UsingCAST   = CAST('10/15/2008 10:06:32 PM' AS DATETIME)
;

...そして、それは以下の答えを生み出します。どちらも正しいです。

ここに画像の説明を入力してください

TVコマーシャルで言うように、「待ってください。まだ注文しないでください。追加費用なしで、さらに多くのことができます!」

DATETIMEを使用した時間変換の本当の力を見て、DATETIME2と呼ばれる誤りを部分的に調べてみましょう。DATETIMEが自動で魔法で処理でき、DATETIME2で処理できない奇抜な形式を確認してください。次のコードを実行してください...

--===== Set the language for this example.
    SET LANGUAGE ENGLISH --Same a US-English
;
--===== Use a table constructor as if it were a table for this example.
 SELECT *
        ,DateTimeCONVERT  = TRY_CONVERT(DATETIME,StringDT)
        ,DateTimeCAST     = TRY_CAST(StringDT AS DATETIME)
        ,DateTime2CONVERT = TRY_CONVERT(DATETIME2,StringDT)
        ,DateTime2CAST    = TRY_CAST(StringDT AS DATETIME2)
   FROM (
         VALUES
         ('Same Format As In The OP'    ,'12/16/2001 01:51:01 PM')
        ,('Almost Normal'               ,'16 December, 2001 1:51:01 PM')
        ,('More Normal'                 ,'December 16, 2001 01:51:01 PM')
        ,('Time Up Front + Spaces'      ,'   13:51:01  16 December   2001')
        ,('Totally Whacky Format #01'   ,'  16  13:51:01  December   2001')
        ,('Totally Whacky Format #02'   ,'  16    December 13:51:01  2001  ')
        ,('Totally Whacky Format #03'   ,'  16    December 01:51:01  PM 2001  ')
        ,('Totally Whacky Format #04'   ,' 2001 16    December 01:51:01  PM ')
        ,('Totally Whacky Format #05'   ,' 2001    December 01:51:01  PM  16  ')
        ,('Totally Whacky Format #06'   ,' 2001 16    December  01:51:01 PM  ')
        ,('Totally Whacky Format #07'   ,' 2001 16    December  13:51:01 PM  ')
        ,('Totally Whacky Format #08'   ,' 2001 16  13:51:01 PM  December    ')
        ,('Totally Whacky Format #09'   ,'   13:51:01   PM  2001.12/16 ')
        ,('Totally Whacky Format #10'   ,'   13:51:01   PM  2001.December/16 ')
        ,('Totally Whacky Format #11'   ,'   13:51:01   PM  2001.Dec/16 ')
        ,('Totally Whacky Format #12'   ,'   13:51:01   PM  2001.Dec.16 ')
        ,('Totally Whacky Format #13'   ,'   13:51:01   PM  2001/Dec.16')
        ,('Totally Whacky Format #14'   ,'   13:51:01   PM  2001 . 12/16 ')
        ,('Totally Whacky Format #15'   ,'   13:51:01   PM  2001 . December / 16 ')
        ,('Totally Whacky Format #16'   ,'   13:51:01   PM  2001 . Dec /   16 ')
        ,('Totally Whacky Format #17'   ,'   13:51:01   PM  2001 . Dec .   16 ')
        ,('Totally Whacky Format #18'   ,'   13:51:01   PM  2001 / Dec .   16')
        ,('Totally Whacky Format #19'   ,'   13:51:01   PM  2001 . Dec -   16 ')
        ,('Totally Whacky Format #20'   ,'   13:51:01   PM  2001 - Dec -   16 ')
        ,('Totally Whacky Format #21'   ,'   13:51:01   PM  2001 - Dec .   16')
        ,('Totally Whacky Format #22'   ,'   13:51:01   PM  2001 - Dec /   16 ')
        ,('Totally Whacky Format #23'   ,'   13:51:01   PM  2001 / Dec -   16')
        ,('Just the year'               ,' 2001      ')
        ,('YYYYMM'                      ,' 200112      ')
        ,('YYYY MMM'                    ,'2001 Dec')
        ,('YYYY-MMM'                    ,'2001-Dec')
        ,('YYYY    .     MMM'           ,'2001    .     Dec')
        ,('YYYY    /     MMM'           ,'2001    /     Dec')
        ,('YYYY    -     MMM'           ,'2001    /     Dec')
        ,('Forgot The Spaces #1'        ,'2001December26')
        ,('Forgot The Spaces #2'        ,'2001Dec26')
        ,('Forgot The Spaces #3'        ,'26December2001')
        ,('Forgot The Spaces #4'        ,'26Dec2001')
        ,('Forgot The Spaces #5'        ,'26Dec2001 13:51:01')
        ,('Forgot The Spaces #6'        ,'26Dec2001 13:51:01PM')
        ,('Oddly, this doesn''t work'   ,'2001-12')
        ,('Oddly, this doesn''t work'   ,'12-2001')
        ) v (Description,StringDT)
;

したがって、そうです... SQL Serverには、実際にはあらゆる種類の奇妙な一時形式を処理する非常に柔軟な方法があり、特別な処理は必要ありません。24時間に追加された「PM」を削除する必要すらありませんでした。それは「PFM」(Pure Freakin 'Magic)です。

言語によって多少異なりますが、サーバーに選択した言語ですが、大部分はどちらの方法でも処理されます。

そして、これらの「自動マジック」変換は新しいものではありません。彼らは本当に長い道のりを戻ります。


邪悪な古い質問に対する邪悪な新しい答え。ありがとう!
JosephStyons

フィードバックをありがとう、@ JosephStyons。
ジェフモダン

0

SQL Serverに試行錯誤させたい場合は、CAST CAST( 'whatever' AS datetime)を使用します。ただし、これは一般的に悪い考えです。出てくる国際的な日付の問題があります。そのため、これらの問題を回避するために、ODBCの正規形式の日付を使用したいことがわかりました。つまり、フォーマット番号120、20は2桁の年のフォーマットです。SQL Serverには、ユーザーが指定した形式を提供できる組み込み関数はないと思います。自分で作成することもできますが、オンラインで検索すると見つけられる場合もあります。


1つの列に国際日付がある場合、フォーマット番号を使用することをお勧めします。国際日付と米国日付がすべて1つの列に混在している場合、形式を説明する姉妹列がない限り、2000年7月6日と2000年7月7日のような違いを判断する方法はありません。だからこそ、ソースでのデータ品質が単純に重要なのです。たとえば、すべての米国の日付があることを知っている場合は、暗黙的な変換を実行します。それらが失敗した場合、列の何かを修正する必要があることは確かです。
ジェフモダン

0

暗黙的にMSSQLで文字列を日時に変換する

create table tmp 
(
  ENTRYDATETIME datetime
);

insert into tmp (ENTRYDATETIME) values (getdate());
insert into tmp (ENTRYDATETIME) values ('20190101');  --convert string 'yyyymmdd' to datetime


select * from tmp where ENTRYDATETIME > '20190925'  --yyyymmdd 
select * from tmp where ENTRYDATETIME > '20190925 12:11:09.555'--yyyymmdd HH:MIN:SS:MS



こんにちは、stackoverflowへようこそ。回答いただきありがとうございます。このコードは質問に答えるかもしれませんが、何が問題を解決したのか、どのように解決したのかについて説明を追加することを検討できますか?これは、将来の読者があなたの答えをよりよく理解し、それから学ぶのに役立ちます。
Plutian

-4
dateadd(day,0,'10/15/2008 10:06:32 PM')

3
StackOverflowへようこそ!コードの説明を追加するには、回答編集してください。この質問はほぼ11年前のものであり、すでに多くのよく説明された賛成の回答があります。あなたの答えに説明がないと、これらは他のものに比べてはるかに品質が低く、おそらく反対投票または削除されます。その説明を追加すると、ここに回答の存在を正当化するのに役立ちます。
Das_Geek

うん、でも「よく説明された」投稿は、賛成投票された投稿でさえ、あまりに複雑です。一つは、説明の有無にかかわらず、実際にはより良いものの一つであるここに掲載
ジェフMODEN
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.