Sql Server строка для преобразования даты

186

Я хочу преобразовать строку следующим образом:

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

в эквивалентное значение DATETIME в Sql Server.

В Oracle я бы сказал так:

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

Этот вопрос подразумевает, что я должен проанализировать строку в одном из стандартных форматов , а затем преобразовать, используя один из этих кодов. Это кажется нелепым для такой мирской операции. Есть ли более простой способ?

JosephStyons
источник

Ответы:

28

SQL Server (2005, 2000, 7.0) не имеет какого-либо гибкого или даже негибкого способа получения произвольно структурированного datetime в строковом формате и преобразования его в тип данных datetime.

Под «произвольно» я подразумеваю «форму, которую человек, который ее написал, хотя, возможно, не вы, я или кто-то на другой стороне планеты, сочли бы ее интуитивной и совершенно очевидной». Честно говоря, я не уверен, что есть такой алгоритм.

Филип Келли
источник
32
такой алгоритм существует, Oracle уже реализовал его, а отсутствие аналога в SQL Server - постоянная проблема.
Матао
19
@matao, пожалуйста, расскажите нам, как Oracle волшебным образом определяет, имел ли в 9/6/12виду введенный пользователь 6 сентября 2012 г., 9 июня 2012 г., 6 декабря 2009 г. или что-то еще?
Аарон Бертран
13
не беспокойтесь, здесь: techonthenet.com/oracle/functions/to_date.php Очевидно, что это должен быть согласованный формат, который вы указываете разработчику, но гораздо более гибкий, чем несколько масок форматирования, которые дает вам MS, что приводит к болезненному пользовательскому анализу ,
Матао
3
@JosphStyons знал о функции Oracle TO_DATE, как показано в его примере. Он хотел знать, существует ли способ преобразования дат как строк без необходимости знать формат / структуру строки. SQL этого не делает, и, похоже, Oracle TO_DATE тоже этого не делает.
Филипп Келли
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) для более подробной информации.

gauravg
источник
14
Это правильный способ сделать это, и должен быть помечен как правильный ответ. Обратите внимание, что это Cast('2011-07-07' as datetime)также работает, и устраняет неоднозначность по месяцам и дням.
Джо ДеРоз
Это не работает, когда месяц> 12. Форматирование предполагает формат мм / дд / гггг
Чакри
Используйте Convert (varchar (30), '
Матиас Массо
2
@ Чакри, если ваши даты указаны в формате дд / мм / гггг SET DATEFORMAT dmyперед вашим запросом
Натан Гриффитс
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)'
Taptronic
источник
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);

Я настоятельно рекомендую вам взять под контроль и обезопасить ваши данные даты. Дни, когда люди могли печатать даты в произвольном формате в нужном формате, должны быть далеко позади. Если кто-то входит 9.09.2011, то это 9 августа или 8 сентября? Если вы заставите их выбрать дату в элементе управления календаря, то приложение сможет контролировать формат. Независимо от того, сколько вы пытаетесь предсказать поведение ваших пользователей, они всегда найдут более тупой способ ввести дату, которую вы не планировали.

До Денали, тем не менее, я думаю, что @Ovidiu имеет лучший совет на данный момент ... это можно сделать довольно тривиальным путем реализации вашей собственной функции CLR. Затем вы можете написать case / switch для любого количества нестандартных нестандартных форматов.


ОБНОВЛЕНИЕ для @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]

форматы дат можно найти в разделе Помощник по SQL Server> Форматы даты в SQL Server.

Скотт Голлагли
источник
Ваш пример кода не работает. Msgstr "Преобразование не удалось при преобразовании даты и / или времени из строки символов."
Сезар Леон
5
Должно быть select convert(date,'10/15/2011 00:00:00',101). Более подробную информацию о формате и почему 101, на docs.microsoft.com/en-us/sql/t-sql/functions/...
anotherUser
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.

tvanfosson
источник
ссылка не работает
Майкл Поттер
3

Лично, если вы имеете дело с произвольными или полностью нестандартными форматами, при условии, что вы знаете, что они опередили или будут делать это, просто используйте regexp, чтобы получить нужные вам отрезки даты и сформировать действительный компонент date / datetime.

SyWill
источник
1

Я знаю, что это злой старый пост с множеством ответов, но многие люди думают, что им НУЖНО либо разбить вещи на части и собрать их обратно, либо они настаивают на том, что нет способа неявно выполнить преобразование, запрошенное оригиналом 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)
;

... и это дает следующие ответы, оба из которых являются правильными.

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

Как говорят в телевизионной рекламе: «Но подождите! Пока не заказывайте! Без дополнительных затрат, это может сделать ГЛАВНОЕ!»

Давайте посмотрим на реальную силу временных преобразований с помощью 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 на самом деле имеет довольно гибкий метод обработки всевозможных странных временных форматов, и никакой специальной обработки не требуется. Нам даже не нужно было удалять «PM», которые были добавлены к 24-часовым временам. Это "PFM" (Pure Freakin 'Magic).

Все будет немного различаться в зависимости от ЯЗЫКА, который вы выбрали для своего сервера, но многое из этого будет обработано в любом случае.

И эти «автоматические» преобразования не являются чем-то новым. Они идут очень далеко назад.

Джефф Моден
источник
Злой новый ответ на злой старый вопрос. Спасибо!
Джозеф Стайонс
Спасибо за отзыв, @JosephStyons.
Джефф Моден
0

Если вы хотите, чтобы SQL Server попытался это выяснить, просто используйте CAST CAST («как угодно», как дата / время). Однако в целом это плохая идея. Есть проблемы с международными датами, которые могут возникнуть. Итак, как вы обнаружили, чтобы избежать этих проблем, вы хотите использовать ODBC канонический формат даты. То есть формат № 120, 20 - это формат для двухзначных лет. Я не думаю, что SQL Server имеет встроенную функцию, которая позволяет вам предоставлять пользовательский формат. Вы можете написать свое собственное и даже найти его, если будете искать в Интернете.

Уилл Рикардс
источник
Если у вас есть международные даты в одном столбце, я абсолютно согласен с тем, что использование числа в формате - это хорошая идея. Если у вас есть международные даты и даты в США, все смешанные в одном столбце, просто невозможно определить разницу между чем-то вроде 7/6/2000 и 6/7/2000, если у вас нет родственного столбца, который объясняет формат. Вот почему качество данных в источнике просто ДОЛЖНО быть. Если вы ЗНАЕТЕ, что у вас есть, скажем, все даты в США, пусть неявные преобразования сделают свое дело. Если они терпят неудачу, то вы точно знаете, что что-то в столбце необходимо исправить.
Джефф Моден
0

неявное преобразование строки в datetime в 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


user12913610
источник
Привет и добро пожаловать в stackoverflow, и спасибо за ответ. Хотя этот код может ответить на вопрос, можете ли вы добавить какое-нибудь объяснение того, какую проблему вы решили и как вы ее решили? Это поможет будущим читателям лучше понять ваш ответ и извлечь из него уроки.
Плутян
-4
dateadd(day,0,'10/15/2008 10:06:32 PM')
Ярослав
источник
3
Добро пожаловать в StackOverflow! Пожалуйста, отредактируйте ваш ответ, чтобы добавить объяснение к вашему коду. Этому вопросу уже почти одиннадцать лет , и у него уже есть много хорошо объясненных ответов. Без объяснения в вашем ответе, он гораздо более низкого качества по сравнению с этими другими и, скорее всего, будет опущен или удален. Добавление этого объяснения поможет оправдать существование вашего ответа здесь.
Das_Geek
Да, но «хорошо объясненные» посты, даже те, которые проголосовали, слишком сложны. Тот, что размещен здесь, на самом деле один из лучших, с объяснениями или без них,
Джефф Моден