SQL Server dizeden tarihe dönüştürme


186

Ben böyle bir dize dönüştürmek istiyorum:

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

Sql Server'da eşdeğer DATETIME değerine dönüştürün.

Oracle'da şunu söyleyebilirim:

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

Bu soru , standart biçimlerden birine dizeyi ayrıştırmak ve sonra bu kodlardan birini kullanarak dönüştürmek gerektiğini ima eder . Böyle sıradan bir operasyon için gülünç görünüyor. Daha kolay bir yol var mı?


Yanıtlar:


28

SQL Server'ın (2005, 2000, 7.0) isteğe bağlı olarak yapılandırılmış tarih saatini dize biçiminde alıp datetime veri türüne dönüştürmenin esnek, hatta esnek olmayan bir yolu yoktur.

"Keyfi" ile kastediyorum, "onu yazan kişinin belki de siz ya da ben ya da gezegenin diğer tarafındaki biri değil, sezgisel ve tamamen açık olduğunu düşündüğü bir formdur." Açıkçası, böyle bir algoritma olduğundan emin değilim.


32
böyle bir algoritma var, Oracle zaten uyguladı ve SQL Server'ın eşdeğeri eksikliği sürekli bir acıdır.
Matao

19
@matao lütfen bizi aydınlatın, Oracle yazan bir kullanıcının 9/6/126 Eylül 2012, 9 Haziran 2012, 6 Aralık 2009 veya başka bir şey ifade edip etmediğini sihirli bir şekilde nasıl belirler ?
Aaron Bertrand

13
Endişelenmenize gerek yok, burada: techonthenet.com/oracle/functions/to_date.php Açıkçası geliştiricinin belirttiği tutarlı bir format olmalı, ancak MS'in size verdiği birkaç biçim maskesinden çok daha esnek, bu da acı verici özel ayrıştırma ile sonuçlanıyor .
Matão

3
@JosphStyons, örneğinde gösterildiği gibi Oracle'ın TO_DATE işlevinin farkındaydı. Dizenin biçimini / yapısını bilmeden dizeleri tarih olarak dönüştürmenin bir yolu olup olmadığını bilmek istiyordu . SQL bunu yapmaz ve kesinlikle Oracle'ın TO_DATE'i de bunu yapmaz gibi görünüyor.
Philip Kelley

23
@PhilipKelley OP'nin formatı bilmek zorunda kalmadan nasıl yapılacağını bilmek istediğini anlamıyorum. Biçimi bildiğini ve SQL Server'ın TO_DATE ile eşdeğer bir şey olup olmadığını, yani geliştiricinin rasgele bir biçim dizesi girmesine izin veren bir şey olup olmadığını sorduğunu açıkça söylüyor.
neverfox

306

Bunu dene

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

ve

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

Daha fazla bilgi için CAST ve CONVERT (Transact-SQL) konularına bakın.


14
Bunu yapmanın doğru yolu budur ve doğru cevap olarak işaretlenmelidir. Cast('2011-07-07' as datetime)Ayrıca, ay ve gün siparişindeki belirsizliği ortadan kaldırdığını ve ortadan kaldırdığını unutmayın .
Joe DeRose

Ay> 12 olduğunda bu çalışmaz. Biçimlendirme, aa / gg / yyyy biçimini bekliyor
Chakri

Gg / aa /
yyyy'den

2
@Chakri Tarihleriniz gg / aa / yyyy ise SET DATEFORMAT dmysorgunuzdan önce kullanın
Nathan Griffiths

49

Bunu sorgu işlemciniz üzerinden çalıştırın. Tarihleri ​​ve / veya saatleri biçimlendirir ve bunlardan biri size aradığınızı verir. Uyum sağlamak zor olmayacak:

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'de aradığınıza yaklaşan bir şey yapabileceksiniz. Ancak yine de rastgele tanımlanmış tuhaf tarih dizesini iletemez ve SQL Server'ın uyum sağlamasını bekleyebilirsiniz. İşte kendi yanıtınıza gönderdiğiniz bir şeyi kullanan bir örnek. FORMAT () işlevi ve yerel ayarları isteğe bağlı bir argüman olarak da kabul edebilir - .Net'in biçimine dayanır, bu yüzden görmeyi beklediğiniz token formatlarının tümü olmasa bile çoğu orada olacaktır.

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);

Daha fazla kontrol almanızı ve tarih girişlerinizi sterilize etmenizi şiddetle tavsiye ediyorum. İnsanların bir freetext form alanına istedikleri formatı kullanarak tarih yazmasına izin verme günleri şimdiye kadar geride kalmalı. Birisi 8/9/2011 girerse bu 9 Ağustos ya da 8 Eylül midir? Bir takvim denetiminde bir tarih seçmelerini sağlarsanız, uygulama biçimi denetleyebilir. Kullanıcılarınızın davranışını ne kadar tahmin etmeye çalışırsanız çalışın, planlanmadığınız bir tarihi girmek için her zaman daha iyi bir yol bulurlar.

Denali'ye kadar, @Ovidiu'nun şimdiye kadarki en iyi tavsiyeye sahip olduğunu düşünüyorum ... Bu, kendi CLR işlevinizi uygulayarak oldukça önemsiz hale getirilebilir. Ardından istediğiniz kadar tuhaf standart dışı format için bir vaka / anahtar yazabilirsiniz.


@Dhergert için GÜNCELLEME :

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');

Sonuçlar:

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

Öncelikle bu diğer önemli bilgilere sahip olmanız gerekir. 6/9/20129 Haziran mı yoksa 6 Eylül mi olduğunu belirlemek için yerel T-SQL'i kullanamazsınız .


1
Ben soru nasıl bir dize bir datetime, bir datetime bir dize dönüştürmek olduğunu düşünüyorum.
David Hergert

1
TRY_PARSE mükemmeldi. '22 Eyl 2016' tarihli bir tarihi ayrıştırırken bir sorun yaşadık, paylaştığınız için teşekkürler!
Simon

11

Bu sorun için kullandığım en iyi çözüm, Sql Server 2005'te DateTime.Parse veya ParseExact işlevinden birini kullanarak DateTime değerini belirtilen biçimde döndürmek için bir CLR işlevine sahip olmaktır.


11

Bunu kullan:

SELECT convert(datetime, '2018-10-25 20:44:11.500', 121) -- yyyy-mm-dd hh:mm:ss.mmm

Ve dönüşüm kodları için resmi belgelerdeki tabloya bakın .


8

neden denemiyorsun

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

tarih biçimlerini SQL Server Yardımcısı> SQL Server Tarih Biçimleri'nde bulabilirsiniz


Kod örneğiniz çalışmıyor. "Karakter dizesinden tarih ve / veya saat dönüştürülürken dönüşüm başarısız oldu."
César León

5
Olmalı select convert(date,'10/15/2011 00:00:00',101). Biçim ve neden 101 hakkında daha fazla bilgi için docs.microsoft.com/en-us/sql/t-sql/functions/…
anotherUser

1
Sekiz kişi bu cevaba oy verdi ve işe yaramıyor ...
David Klempfner

4

Bunu anlayabilmem için bir dakikamı aldım, bu yüzden birisine yardım etmesi durumunda:

SQL Server 2012 ve sonraki sürümlerde bu işlevi kullanabilirsiniz:

SELECT DATEFROMPARTS(2013, 8, 19);

İşte ben bu işlevi koymak için tarih bölümlerini ayıklamak nasıl sona erdi:

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

3

Bu sayfada , CONVERT işlevi tarafından kullanılabilen belirtilen tüm tarih / saat dönüşümleri için bazı referanslar bulunmaktadır. Değerleriniz kabul edilebilir kalıplardan birine düşmezse, en iyi şeyin ParseExact yoluna gitmek olduğunu düşünüyorum.


bağlantı koptu.
Michael Potter

3

Şahsen, vaktinden önce ya da tamamen duvar formatları ile uğraşmanız durumunda, neyin vaktinden önce olduğunu ya da ne olacağını bilmiyorsanız, istediğiniz tarih bölümlerini çekmek ve geçerli bir tarih / datetime bileşeni oluşturmak için regexp kullanın.


1

Bunun çok fazla cevabı olan kötü bir eski yazı olduğunu biliyorum, ancak bir çok insan şeyleri parçalayıp tekrar bir araya getirmeye GEREKMEDİĞİNİ düşünüyor veya OP orijinalinin istediği dönüşümü dolaylı olarak yapmanın hiçbir yolu olmadığını ısrar ediyorlar. .

Aynı soruyu inceleyen ve umarım diğerlerine kolay bir cevap vermek için OP '10/15/2008 10:06:32 PM' nin bir DATETIME'a nasıl dönüştürüleceğini sordu. Şimdi, SQL Server geçici dönüşümler için bazı dil bağımlılıklarına sahiptir, ancak dil İngilizce veya benzer bir şeyse, bu basit bir sorun haline gelir ... sadece dönüşümü yapın ve format hakkında endişelenmeyin. Örneğin (ve CONVERT veya CAST kullanabilirsiniz) ...

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

... ve her ikisi de doğru olan aşağıdaki cevapları üretir.

resim açıklamasını buraya girin

TV reklamlarında söyledikleri gibi, "Ama bekleyin! Henüz sipariş vermeyin! Hiçbir ekstra ücret ödemeden daha fazlasını yapabilir!"

DATETIME ile geçici dönüşümlerin gerçek gücünü görelim ve DATETIME2 olarak bilinen hatayı kısmen inceleyelim. DATETIME'ın otomatik olarak işleyebildiği ve DATETIME2'nin yapamadığı whacky biçimlerine bakın. Aşağıdaki kodu çalıştırın ve bakın ...

--===== 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)
;

Yani, evet ... SQL Server aslında her türlü garip-geçici formatları işlemek için oldukça esnek bir yönteme sahiptir ve özel bir işleme gerek yoktur. 24 Saat sürelerine eklenen "PM" lerin kaldırılması bile gerekmiyordu. Bu "PFM" (Pure Freakin 'Magic).

LANGUAGE, sunucunuz için seçtiğiniz şeye bağlı olarak biraz değişecektir, ancak birçoğu her iki şekilde de ele alınacaktır.

Ve bu "otomatik büyü" dönüşümleri yeni bir şey değil. Çok uzun bir yol kat ediyorlar.


Kötü eski bir soru için kötü yeni bir cevap. Teşekkürler!
JosephStyons

Geri bildiriminiz için teşekkürler, @JosephStyons.
Jeff Moden

0

SQL Server denemek ve anlamak istiyorsanız, sadece CAST CAST ('ne olursa olsun' datetime olarak) kullanın Ancak bu genel olarak kötü bir fikir. Uluslararası tarihlerle ilgili sorunlar ortaya çıkacaktır. Bulduğunuz gibi, bu sorunlardan kaçınmak için, tarihin ODBC standart biçimini kullanmak istiyorsunuz. Bu sayı 120'dir, 20 sadece iki haneli yılların formatıdır. SQL Server, kullanıcı tarafından verilen bir biçim sağlamak için yerleşik bir işlevi olduğunu sanmıyorum. Kendinizinkini yazabilirsiniz ve hatta çevrimiçi arama yaparsanız bile bulabilirsiniz.


Tek bir sütunda uluslararası tarihleriniz varsa, kesinlikle bir biçim numarası kullanmanın iyi bir fikir olduğunu kabul ediyorum. Uluslararası tarihleriniz varsa ve ABD tarihlerinin tümü tek bir sütunda karışıksa, biçimi açıklayan bir kardeş sütununuz yoksa 7/6/2000 ve 6/7/2000 gibi bir şey arasındaki farkı belirlemenin bir yolu yoktur. Bu yüzden kaynaktaki veri kalitesi basitçe bir şey OLMALIDIR. Tüm ABD tarihlerine sahip olduğunuzu Bilirseniz, örtük dönüşümlerin işlerini yapmasına izin verin. Başarısız olursa, sütundaki bir şeyin düzeltilmesi gerektiğinden emin olabilirsiniz.
Jeff Moden

0

örtük olarak dize MSSQL datetime dönüştürmek

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



Merhaba ve stackoverflow'a hoş geldiniz ve yanıtladığınız için teşekkür ederiz. Bu kod soruyu cevaplayabilirken, sorunun ne çözdüğünüze ve nasıl çözdüğünüze ilişkin bir açıklama eklemeyi düşünebilir misiniz? Bu, gelecekteki okuyucuların cevabınızı daha iyi anlamalarına ve ondan öğrenmelerine yardımcı olacaktır.
Plutian

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

3
StackOverflow'a hoş geldiniz! Kodunuza bir açıklama eklemek için lütfen cevabınızı düzenleyin . Bu soru neredeyse on bir yaşında ve zaten çok iyi açıklanmış, onaylanmış cevapları var. Bir açıklama yapmadan da cevap, bu diğerlerine göre çok daha düşük kalitede olduğunu ve büyük olasılıkla downvoted veya kaldırılır alacak. Bu açıklamayı eklemek, cevabınızın varlığını burada haklı çıkarmanıza yardımcı olacaktır.
Das_Geek

Evet ama "iyi açıklanmış" gönderiler, yukarıdakiler bile çok karmaşık. Burada yayınlanan bir aslında bir açıklama ile veya bir açıklama olmadan, daha iyi olanlardan biridir,
Jeff Moden
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.