Chuỗi máy chủ Sql để chuyển đổi ngày


186

Tôi muốn chuyển đổi một chuỗi như thế này:

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

vào giá trị DATETIME tương đương trong Sql Server.

Trong Oracle, tôi sẽ nói điều này:

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

Câu hỏi này ngụ ý rằng tôi phải phân tích chuỗi thành một trong các định dạng chuẩn và sau đó chuyển đổi bằng một trong các mã đó. Điều đó có vẻ ngớ ngẩn cho một hoạt động trần tục như vậy. Có cách nào dễ hơn không?


Câu trả lời:


28

SQL Server (2005, 2000, 7.0) không có bất kỳ cách linh hoạt hoặc thậm chí không linh hoạt nào để lấy một datetime có cấu trúc tùy ý ở định dạng chuỗi và chuyển đổi nó thành kiểu dữ liệu datetime.

Theo "tùy tiện", tôi có nghĩa là "một hình thức mà người viết nó, mặc dù có lẽ không phải bạn hoặc tôi hoặc ai đó ở phía bên kia hành tinh, sẽ coi là trực quan và hoàn toàn rõ ràng." Thành thật mà nói, tôi không chắc có bất kỳ thuật toán như vậy.


32
Có một thuật toán như vậy, Oracle đã triển khai nó và SQL Server thiếu tương đương là một nỗi đau không đổi.
matao

19
@matao vì vậy xin hãy khai sáng cho chúng tôi, làm thế nào để Oracle xác định một cách kỳ diệu liệu người dùng đã nhập 9/6/12có nghĩa là ngày 6 tháng 9 năm 2012, ngày 9 tháng 6 năm 2012, ngày 6 tháng 12 năm 2009 hay điều gì khác?
Aaron Bertrand

13
không phải lo lắng, ở đây: techonthenet.com/oracle/fifts/to_date.php Rõ ràng nó phải là một định dạng nhất quán mà nhà phát triển chỉ định, nhưng linh hoạt hơn nhiều so với một số mặt nạ định dạng mà MS cung cấp cho bạn, dẫn đến việc phân tích cú pháp tùy chỉnh đau đớn .
matao

3
@JosphStyons đã biết về hàm TO_DATE của Oracle, như thể hiện trong mẫu của anh ấy. Anh ta muốn biết liệu có cách nào để chuyển đổi ngày theo chuỗi mà không cần phải biết định dạng / cấu trúc của chuỗi không. SQL không làm điều đó và chắc chắn rằng TO_DATE của Oracle cũng không làm điều đó.
Philip Kelley

23
@PhilipKelley Tôi không thấy OP muốn biết cách thực hiện mà không cần phải biết định dạng. Anh ta nói rõ ràng rằng anh ta biết định dạng và đang hỏi liệu SQL Server có thứ gì đó tương đương với TO_DATE hay không, tức là thứ gì đó cho phép nhà phát triển nhập một chuỗi định dạng tùy ý.
neverfox

305

Thử cái này

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

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

Xem CAST và CONVERT (Transact-SQL) để biết thêm chi tiết.


14
Đây là cách đúng để làm điều đó, và nên được đánh dấu là câu trả lời đúng. Lưu ý rằng Cast('2011-07-07' as datetime)cũng hoạt động và loại bỏ sự mơ hồ trong đơn đặt hàng tháng và ngày.
Joe DeRose

Điều này không hoạt động khi tháng là> 12. Định dạng mong đợi định dạng mm / dd / yyyy
Chakri

Sử dụng Chuyển đổi (varchar (30), '7/7/2011', 103) khi chuyển đổi từ dd / mm / yyyy
Matias Masso

2
@Chakri nếu ngày của bạn được sử dụng dd / mm / yyyy SET DATEFORMAT dmytrước truy vấn của bạn
Nathan Griffiths

48

Chạy này thông qua bộ xử lý truy vấn của bạn. Nó định dạng ngày và / hoặc thời gian như vậy và một trong số này sẽ cung cấp cho bạn những gì bạn đang tìm kiếm. Sẽ không khó để thích nghi:

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

Trong SQL Server Denali, bạn sẽ có thể làm điều gì đó tiếp cận những gì bạn đang tìm kiếm. Nhưng bạn vẫn không thể vượt qua bất kỳ chuỗi ngày lập dị được xác định tùy ý và mong muốn SQL Server phù hợp. Đây là một ví dụ sử dụng một cái gì đó bạn đã đăng trong câu trả lời của riêng bạn. Hàm FORMAT () và cũng có thể chấp nhận các ngôn ngữ làm đối số tùy chọn - nó dựa trên định dạng của .Net, do đó, hầu hết nếu không phải tất cả các định dạng mã thông báo bạn muốn thấy sẽ ở đó.

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

Tôi đặc biệt khuyến khích bạn kiểm soát nhiều hơn và vệ sinh đầu vào ngày của bạn. Ngày nay, cho phép mọi người nhập ngày bằng bất kỳ định dạng nào họ muốn vào trường biểu mẫu freetext sẽ bị bỏ lại phía sau chúng ta. Nếu ai đó nhập ngày 8/9/2011 là ngày 9 tháng 8 hay ngày 8 tháng 9? Nếu bạn bắt họ chọn một ngày trên điều khiển lịch, thì ứng dụng có thể kiểm soát định dạng. Cho dù bạn cố gắng dự đoán hành vi của người dùng bao nhiêu đi chăng nữa, họ sẽ luôn tìm ra một cách ngu ngốc để nhập ngày mà bạn không lên kế hoạch.

Tuy nhiên, cho đến khi Denali, tôi nghĩ rằng @Ovidiu có lời khuyên tốt nhất cho đến nay ... điều này có thể được thực hiện khá tầm thường bằng cách thực hiện chức năng CLR của riêng bạn. Sau đó, bạn có thể viết một trường hợp / chuyển đổi cho nhiều định dạng không chuẩn mà bạn muốn.


CẬP NHẬT cho @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');

Các kết quả:

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

Bạn vẫn cần phải có thông tin quan trọng khác trước. Bạn không thể sử dụng T-SQL gốc để xác định xem 6/9/2012là ngày 9 tháng 6 hay ngày 6 tháng 9.


1
Tôi nghĩ câu hỏi là làm thế nào để chuyển đổi một chuỗi thành một datetime chứ không phải một datetime thành một chuỗi.
David Hergert

1
TRY_PARSE là hoàn hảo. Chúng tôi đã gặp sự cố khi phân tích ngày 'Thu tháng 9 năm 2016', cảm ơn vì đã chia sẻ!
Simon

11

Đối với vấn đề này, giải pháp tốt nhất tôi sử dụng là có chức năng CLR trong Sql Server 2005 sử dụng một trong các hàm DateTime.Pude hoặc ParseExact để trả về giá trị DateTime với định dạng đã chỉ định.


11

Dùng cái này:

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

Và tham khảo bảng trong tài liệu chính thức cho các mã chuyển đổi.


8

Sao không thử nhỉ

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

định dạng ngày có thể được tìm thấy tại SQL Server Helper> SQL Server Định dạng ngày


Ví dụ mã của bạn không hoạt động. "Chuyển đổi không thành công khi chuyển đổi ngày và / hoặc thời gian từ chuỗi ký tự."
César León

5
Nên select convert(date,'10/15/2011 00:00:00',101). Thêm chi tiết về định dạng và lý do 101, trên docs.microsoft.com/en-us/sql/t-sql/fifts/ ám
otherUser

1
Tám người đã bỏ phiếu cho câu trả lời này và nó thậm chí không hoạt động ...
David Klempfner

4

Mất một phút để tôi hiểu điều này vì vậy đây là trường hợp có thể giúp được ai đó:

Trong SQL Server 2012 và tốt hơn bạn có thể sử dụng chức năng này:

SELECT DATEFROMPARTS(2013, 8, 19);

Đây là cách tôi kết thúc trích xuất các phần của ngày để đưa vào chức năng này:

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

3

Đây trang có một số tài liệu tham khảo cho tất cả các chuyển đổi datetime định sẵn cho các chức năng CONVERT. Nếu các giá trị của bạn không thuộc một trong các mẫu có thể chấp nhận, thì tôi nghĩ điều tốt nhất là đi theo tuyến đường ParseExact.


liên kết bị hỏng.
Michael Potter

3

Cá nhân nếu bạn giao dịch với các định dạng tường tùy ý hoặc hoàn toàn tắt, với điều kiện bạn biết họ đang đi trước thời hạn hoặc sau đó sẽ sử dụng regrec để kéo các phần của ngày bạn muốn và tạo thành một thành phần ngày / giờ hợp lệ.


1

Tôi biết đây là một bài viết cũ độc ác với rất nhiều câu trả lời nhưng rất nhiều người nghĩ rằng họ CẦN phải phá vỡ mọi thứ và đặt chúng lại với nhau hoặc họ khẳng định rằng không có cách nào để thực hiện chuyển đổi mà OP ban đầu yêu cầu .

Để xem xét và hy vọng cung cấp một câu trả lời dễ dàng cho những người khác có cùng câu hỏi, OP đã hỏi cách chuyển đổi '10 / 15/2008 10:06:32 PM 'thành một cơ sở dữ liệu. Bây giờ, SQL Server có một số phụ thuộc ngôn ngữ cho chuyển đổi tạm thời nhưng nếu ngôn ngữ là tiếng Anh hoặc một cái gì đó tương tự, thì điều này trở thành một vấn đề đơn giản ... chỉ cần thực hiện chuyển đổi và đừng lo lắng về định dạng. Ví dụ: (và bạn có thể sử dụng CONVERT hoặc CAST) ...

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

... Và điều đó tạo ra các câu trả lời sau, cả hai đều đúng.

nhập mô tả hình ảnh ở đây

Giống như họ nói trên quảng cáo trên TV, "Nhưng đợi đã! Đừng đặt hàng! Không mất thêm chi phí, nó có thể làm được nhiều hơn thế!"

Chúng ta hãy xem sức mạnh thực sự của các chuyển đổi tạm thời với DATETIME và kiểm tra một phần lỗi được gọi là DATETIME2. Kiểm tra các định dạng kỳ quặc mà DATETIME có thể xử lý tự động một cách kỳ diệu và rằng DATETIME2 không thể. Chạy đoạn mã sau và xem ...

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

Vì vậy, yeah ... SQL Server DOES thực sự có một phương pháp khá linh hoạt để xử lý tất cả các loại định dạng tạm thời kỳ lạ và không cần xử lý đặc biệt. Chúng tôi thậm chí không cần phải xóa "PM" đã được thêm vào 24 giờ. Đó là "PFM" (Ma thuật thuần túy của Freakin).

Mọi thứ sẽ thay đổi một chút tùy thuộc vào NGÔN NGỮ là bạn đã chọn cho máy chủ của mình nhưng toàn bộ nó sẽ được xử lý theo một trong hai cách.

Và những chuyển đổi "tự động ma thuật" này không phải là một cái gì đó mới. Họ đi một chặng đường dài thực sự trở lại.


Một câu trả lời mới độc ác cho một câu hỏi cũ độc ác. Cảm ơn!
JosephStyons

Cảm ơn phản hồi, @JosephStyons.
Jeff Moden

0

Nếu bạn muốn SQL Server thử và tìm ra nó, chỉ cần sử dụng CAST CAST ('any' AS datetime) Tuy nhiên, đó là một ý tưởng tồi nói chung. Có những vấn đề với ngày quốc tế sẽ đến. Vì vậy, như bạn đã tìm thấy, để tránh những vấn đề đó, bạn muốn sử dụng định dạng chính tắc ODBC của ngày. Đó là định dạng số 120, 20 là định dạng chỉ hai năm chữ số. Tôi không nghĩ SQL Server có chức năng tích hợp cho phép bạn cung cấp định dạng do người dùng cung cấp. Bạn có thể tự viết và thậm chí có thể tìm thấy nếu bạn tìm kiếm trực tuyến.


Nếu bạn có ngày quốc tế trong một cột duy nhất, tôi hoàn toàn đồng ý rằng sử dụng số định dạng là một ý tưởng tốt. Nếu bạn có ngày quốc tế và ngày ở Hoa Kỳ được trộn lẫn trong một cột duy nhất, sẽ không có cách nào để xác định sự khác biệt giữa thứ gì đó như 7/6/2000 và 6/7/2000 trừ khi bạn có một cột chị em giải thích định dạng. Đó là lý do tại sao chất lượng dữ liệu tại nguồn chỉ đơn giản là PHẢI. Nếu bạn BIẾT rằng bạn có, giả sử, tất cả các ngày ở Hoa Kỳ, hãy để chuyển đổi ngầm làm việc của họ. Nếu họ thất bại, thì bạn biết chắc chắn rằng một cái gì đó trong cột cần phải được sửa chữa.
Jeff Moden

0

chuyển đổi chuỗi thành datetime trong MSSQL ngầm

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



Xin chào và chào mừng đến stackoverflow, và cảm ơn bạn đã trả lời. Mặc dù mã này có thể trả lời câu hỏi, bạn có thể xem xét thêm một số giải thích cho vấn đề bạn đã giải quyết và cách bạn giải quyết nó không? Điều này sẽ giúp người đọc trong tương lai hiểu câu trả lời của bạn tốt hơn và học hỏi từ nó.
Plutian

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

3
Chào mừng bạn đến với StackOverflow! Vui lòng chỉnh sửa câu trả lời của bạn để thêm một lời giải thích cho mã của bạn. Câu hỏi này đã gần mười một tuổi và đã có nhiều câu trả lời được giải thích rõ ràng. Nếu không có lời giải thích trong câu trả lời của bạn , nó có chất lượng thấp hơn nhiều so với những câu hỏi khác và rất có thể sẽ bị hạ cấp hoặc loại bỏ. Thêm lời giải thích đó sẽ giúp chứng minh sự tồn tại của câu trả lời của bạn ở đây.
Das_Geek

Vâng, nhưng các bài viết "giải thích tốt", ngay cả những bài viết được nâng cấp, quá phức tạp. Người được đăng ở đây thực sự là một trong những người tốt hơn, có hoặc không có lời giải thích,
Jeff Moden
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.