Перетворення рядка сервера Sql до дати


186

Я хочу перетворити такий рядок:

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

в еквівалентне значення DATETIME на сервері Sql.

В Oracle я б сказав так:

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

Це питання означає, що я повинен проаналізувати рядок в одному зі стандартних форматів , а потім перетворити за допомогою одного з цих кодів. Це здається смішним для такої мирської операції. Чи є простіший спосіб?


Відповіді:


28

SQL Server (2005, 2000, 7.0) не має гнучких або навіть не гнучких способів прийняття довільно структурованого часу дати у строковому форматі та перетворення його у тип даних дати.

Під "довільно" я маю на увазі "форму, яку людина, яка її написала, хоч, можливо, не ви, ні я чи хтось з іншого боку планети, вважала б інтуїтивно зрозумілою та цілком очевидною". Чесно кажучи, я не впевнений, що існує такий алгоритм.


32
існує такий алгоритм, Oracle вже реалізував його, а відсутність еквівалента SQL Server - це постійний біль.
матао

19
@matao, будь ласка, просвітліть нас, як Oracle магічно визначає, чи означає користувач, який вводив слово: 9/6/126 вересня 2012 року, 9 червня 2012 року, 6 грудня 2009 року, чи щось інше?
Аарон Бертран

13
не хвилюйтесь, тут: techonthenet.com/oracle/functions/to_date.php Очевидно, що це повинен бути послідовний формат, який ви визначаєте розробник, але набагато більш гнучким, ніж жменька форматних масок, що дає вам MS, що призводить до болісного спеціального аналізу .
матао

3
@JosphStyons знав про функцію TO_DATE Oracle, як показано в його зразку. Він хотів дізнатися, чи існує спосіб перетворення рядків дати-як-рядки, не знаючи формат / структуру рядка. SQL цього не робить, і, безумовно, здається, що TO_DATE Oracle також не робить цього.
Філіп Келлі

23
@PhilipKelley Я не бачу, де ОП хоче знати, як це зробити, не знаючи формату. Він прямо говорить, що знає формат і запитує, чи є у 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

Це не працює, коли місяць становить> 12. Форматування очікує мм / дд / гггр формат
Chakri

Використовуйте конвертувати (varchar (30), '7/7/2011', 103) при переході від dd / mm / yyyy
Matias Masso

2
@Chakri, якщо ваші дати в DD / mm / yyyy використовуйте SET DATEFORMAT dmyперед запитом
Nathan Griffiths

49

Запустіть це через ваш процес запиту. Він форматує дати та / або такі рази, і один із них повинен дати вам те, що ви шукаєте. Це не буде важко адаптуватися:

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 вміститься. Ось один приклад використання чого-небудь, що ви розмістили у власній відповіді. Функція 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);

Я настійно закликаю вас взяти більше контролю та санітувати свої дані. Дні, коли люди дозволяють вводити дати, використовуючи потрібний формат, у поле вільного тексту, на сьогоднішній день повинні бути далеко позаду. Якщо хтось входить в 8/9/2011, це 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/2012це 9 червня, чи 6 вересня.


1
Я думаю, питання полягало у тому, як перетворити рядок у дату, а не дату в рядок.
Девід Гергерт

1
TRY_PARSE був ідеальним. У нас виникла проблема з розбором дати "Чт 22 вересня 2016", дякую за обмін!
Саймон

11

Для цієї проблеми найкращим рішенням, який я використовую, є функція CLR на Sql Server 2005, яка використовує одну з функцій DateTime.Parse або ParseExact для повернення значення DateTime у заданому форматі.



8

чому б не спробувати

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

Формати дати можна знайти в Helper SQL Server> Формати дати SQL Server


Ваш приклад коду не працює. "Перетворення не вдалося при перетворенні дати та / або часу з символьного рядка."
Сезар Леон

5
Повинно бути select convert(date,'10/15/2011 00:00:00',101). Більш детально про формат і чому 101, на docs.microsoft.com/en-us/sql/t-sql/functions/…
іншеУчас

1
За цю відповідь проголосували вісім людей, але це навіть не працює ...
Девід Клемпфнер

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. Якщо ваші значення не входять до однієї з прийнятних моделей, я вважаю, що найкраще - пройти маршрут ParseExact.


посилання розірвано.
Майкл Поттер

3

Особисто, якщо ви маєте справу з довільними або повністю відхиленими від форматів стін, за умови, що ви знаєте, що вони випереджають або збираєтеся потім, просто скористайтеся regexp, щоб витягнути розділи потрібної дати та сформувати дійсний компонент дата / дата.


1

Я знаю, що це злий старий пост з великою кількістю відповідей, але багато людей думають, що їм НЕОБХІДНО або розбити речі і скласти їх назад, або вони наполягають на тому, що немає способу неявно зробити перетворення оригіналу ОР, просив якого .

Щоб переглянути та сподіватися надати просту відповідь іншим на те саме питання, ОП запитала, як перетворити '10 / 15/2008 22:06:32 PM 'у ДАТЕТИМ. Тепер у 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)
;

... і це дає наступні відповіді, обидва з яких є правильними.

введіть тут опис зображення

Як кажуть у телерекламі: "Але зачекайте! Не замовляйте ще! Без зайвих витрат, це може зробити набагато більше!"

Давайте подивимось реальну силу тимчасових перетворень із 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 годин. Це "PFM" (Pure Freakin 'Magic).

Речі будуть дещо відрізнятися залежно від МОВИ - це те, що ви вибрали для свого сервера, але ціла кількість з нього буде оброблятися в будь-якому випадку.

І ці автоматичні перетворення не є чимось новим. Вони йдуть по-справжньому далеко назад.


Зла нова відповідь на зле старе питання. Дякую!
JosephStyons

Дякуємо за відгук, @JosephStyons.
Джефф Моден

0

Якщо ви хочете, щоб SQL Server спробував розібратися в цьому, просто використовуйте CAST CAST ("будь-який" AS datetime). Однак це взагалі погана ідея. Є проблеми з міжнародними датами, які можуть з’явитися. Отже, як ви виявили, щоб уникнути цих проблем, ви хочете використовувати канонічний формат ODBC дати. Тобто формат № 120, 20 - це формат всього за два цифри. Я не думаю, що SQL Server має вбудовану функцію, яка дозволяє надати формат, заданий користувачем. Ви можете написати свій власний і навіть знайти його, якщо шукати в Інтернеті.


Якщо у вас є міжнародні дати в одній колонці, я абсолютно погоджуюся, що використання номера формату є хорошою ідеєю. Якщо у вас є змішані дати та дати США, змішані в одному стовпчику, просто неможливо визначити різницю між чимось на зразок 7/6/2000 та 6/7/2000, якщо у вас немає сестринського стовпця, який пояснює формат. Ось чому якість даних у джерелі ОБОВ'ЯЗКОВО бути річчю. Якщо ви знаєте, що у вас є, скажімо, усі дати в США, нехай конверсії, що явно, роблять свою справу. Якщо вони не вдається, то ви точно знаєте, що щось у стовпці потрібно виправити.
Джефф Моден

0

перетворити рядок у timetime в 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, і дякую за відповідь. Хоча цей код може відповісти на питання, чи можете ви розглянути питання про те, що ви вирішили проблему та як її вирішили? Це допоможе майбутнім читачам краще зрозуміти вашу відповідь та дізнатися її.
Плутіян

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

3
Ласкаво просимо до StackOverflow! Будь ласка , змініть свій відповідь , щоб додати пояснення коду. На це запитання майже одинадцять років , і вже є багато добре пояснених, схвалених відповідей. Без пояснення у вашій відповіді, вона набагато нижчої якості порівняно з цими іншими, і, швидше за все, буде знята або усунена. Додавання цього пояснення допоможе виправдати існування вашої відповіді тут.
Das_Geek

Так, але "добре пояснені" посади, навіть цінні, які надсилаються, занадто складні. Опублікований тут насправді є одним із кращих, із поясненнями чи без них,
Джефф Моден
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.