Conversion de chaîne de serveur SQL en date

186

Je veux convertir une chaîne comme celle-ci:

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

dans la valeur DATETIME équivalente dans Sql Server.

Dans Oracle, je dirais ceci:

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

Cette question implique que je dois analyser la chaîne dans l'un des formats standard , puis convertir en utilisant l'un de ces codes. Cela semble ridicule pour une opération aussi banale. Y a-t-il un moyen plus simple?

JosephStyons
la source

Réponses:

28

SQL Server (2005, 2000, 7.0) ne dispose d'aucun moyen flexible, voire non flexible, de prendre un datetime arbitrairement structuré au format chaîne et de le convertir en type de données datetime.

Par «arbitrairement», j'entends «une forme que la personne qui l'a écrite, mais peut-être pas vous ou moi ou quelqu'un de l'autre côté de la planète, considérerait comme intuitive et complètement évidente». Franchement, je ne suis pas sûr qu'il existe un tel algorithme.

Philippe Kelley
la source
32
il existe un tel algorithme, Oracle l'a déjà implémenté, et l'absence d'équivalent de SQL Server est une douleur constante.
matao
19
@matao alors s'il vous plaît, éclairez-nous, comment Oracle détermine-t-il comme par magie si un utilisateur qui a tapé 9/6/12signifiait le 6 septembre 2012, le 9 juin 2012, le 6 décembre 2009 ou autre chose?
Aaron Bertrand
13
pas de soucis, ici: techonthenet.com/oracle/functions/to_date.php Évidemment, il doit s'agir d'un format cohérent que vous spécifiez, le développeur, mais beaucoup plus flexible que la poignée de masques de format que MS vous donne, ce qui entraîne une analyse personnalisée douloureuse .
matao
3
@JosphStyons connaissait la fonction TO_DATE d'Oracle, comme indiqué dans son exemple. Il voulait savoir s'il y avait un moyen de convertir des dates en chaînes sans avoir à connaître le format / la structure de la chaîne. SQL ne fait pas cela, et il semble certainement que le TO_DATE d'Oracle ne le fait pas non plus.
Philip Kelley
23
@PhilipKelley Je ne vois pas où l'OP veut savoir comment le faire sans avoir à connaître le format. Il dit explicitement qu'il connaît le format et demande si SQL Server a quelque chose d'équivalent à TO_DATE, c'est-à-dire quelque chose qui permet au développeur d'entrer une chaîne de format arbitraire.
neverfox
306

Essaye ça

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

et

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

Voir CAST et CONVERT (Transact-SQL) pour plus de détails.

gauravg
la source
14
C'est la bonne façon de le faire et doit être marquée comme la bonne réponse. Notez que cela Cast('2011-07-07' as datetime)fonctionne également et élimine l'ambiguïté sur l'ordre du mois et du jour.
Joe DeRose
Cela ne fonctionne pas lorsque le mois est> 12. La mise en forme attend le format mm / jj / aaaa
Chakri
Utilisez Convert (varchar (30), '7/7/2011', 103) lors de la conversion à partir de jj / mm / aaaa
Matias Masso
2
@Chakri si vos dates sont en jj / mm / aaaa à utiliser SET DATEFORMAT dmyavant votre requête
Nathan Griffiths
49

Exécutez-le via votre processeur de requêtes. Il met en forme des dates et / ou des heures comme ça et l'un d'eux devrait vous donner ce que vous recherchez. Il ne sera pas difficile de s'adapter:

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
la source
47

Dans SQL Server Denali, vous pourrez faire quelque chose qui se rapproche de ce que vous recherchez. Mais vous ne pouvez toujours pas simplement passer une chaîne de date farfelue définie arbitrairement et vous attendre à ce que SQL Server s'adapte. Voici un exemple utilisant quelque chose que vous avez publié dans votre propre réponse. La fonction FORMAT () peut également accepter les paramètres régionaux comme argument facultatif - elle est basée sur le format de .Net, donc la plupart sinon tous les formats de jetons que vous vous attendez à voir seront là.

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

Je vous encourage fortement à prendre plus de contrôle et à désinfecter vos entrées de date. L'époque où les gens pouvaient saisir des dates en utilisant le format de leur choix dans un champ de formulaire libre devrait être loin derrière nous. Si quelqu'un entre le 9 août 2011, est-ce le 9 août ou le 8 septembre? Si vous leur faites choisir une date sur un contrôle de calendrier, l'application peut contrôler le format. Peu importe combien vous essayez de prédire le comportement de vos utilisateurs, ils trouveront toujours un moyen plus stupide de saisir une date que vous n'avez pas prévue.

Jusqu'à Denali, cependant, je pense que @Ovidiu a le meilleur conseil à ce jour ... cela peut être rendu assez trivial en implémentant votre propre fonction CLR. Ensuite, vous pouvez écrire un cas / commutateur pour autant de formats non standard farfelus que vous le souhaitez.


MISE À JOUR pour @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');

Résultats:

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

Vous devez tout d'abord avoir cette autre information cruciale. Vous ne pouvez pas utiliser T-SQL natif pour déterminer s'il 6/9/2012s'agit du 9 juin ou du 6 septembre.

Aaron Bertrand
la source
1
Je pense que la question était de savoir comment convertir une chaîne en un datetime, pas un datetime en une chaîne.
David Hergert
1
TRY_PARSE était parfait. Nous avons eu un problème avec l'analyse d'une date «Jeu ​​22 septembre 2016», merci pour le partage!
Simon le
11

Pour ce problème, la meilleure solution que j'utilise est d'avoir une fonction CLR dans Sql Server 2005 qui utilise l'une des fonctions DateTime.Parse ou ParseExact pour renvoyer la valeur DateTime avec un format spécifié.

Ovidiu Pacurar
la source
11

Utilisez ceci:

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

Et reportez-vous au tableau de la documentation officielle pour les codes de conversion.

Simone
la source
8

pourquoi ne pas essayer

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

les formats de date peuvent être trouvés dans SQL Server Helper> Formats de date SQL Server

Scott Gollaglee
la source
Votre exemple de code ne fonctionne pas. "La conversion a échoué lors de la conversion de la date et / ou de l'heure à partir de la chaîne de caractères."
César León
5
Devrait être select convert(date,'10/15/2011 00:00:00',101). Plus de détails sur le format et pourquoi 101, sur docs.microsoft.com/en-us/sql/t-sql/functions/…
anotherUser
1
Huit personnes ont voté cette réponse et cela ne fonctionne même pas ...
David Klempfner
4

Il m'a fallu une minute pour comprendre cela, alors voici au cas où cela pourrait aider quelqu'un:

Dans SQL Server 2012 et mieux, vous pouvez utiliser cette fonction:

SELECT DATEFROMPARTS(2013, 8, 19);

Voici comment j'ai fini par extraire les parties de la date à mettre dans cette fonction:

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

Cette page contient des références pour toutes les conversions datetime spécifiées disponibles pour la fonction CONVERT. Si vos valeurs ne correspondent pas à l'un des modèles acceptables, je pense que la meilleure chose à faire est d'emprunter la voie ParseExact.

Tvanfosson
la source
le lien est rompu.
Michael Potter
3

Personnellement, si vous avez affaire à des formats arbitraires ou totalement décalés, à condition de savoir ce qu'ils sont à l'avance ou ce qu'ils vont être, utilisez simplement l'expression régulière pour extraire les sections de la date que vous voulez et former un composant date / date / heure valide.

SyWill
la source
1

Je sais que c'est un vieux post méchant avec beaucoup de réponses, mais beaucoup de gens pensent qu'ils DOIVENT soit casser les choses et les remettre ensemble, soit insister sur le fait qu'il n'y a aucun moyen de faire implicitement la conversion demandée par l'OP original .

Pour passer en revue et, espérons-le, fournir une réponse facile aux autres avec la même question, l'OP a demandé comment convertir «10/15/2008 10:06:32 PM» en DATETIME. Maintenant, SQL Server a des dépendances linguistiques pour les conversions temporelles, mais si la langue est l'anglais ou quelque chose de similaire, cela devient un problème simple ... faites simplement la conversion et ne vous inquiétez pas du format. Par exemple (et vous pouvez utiliser CONVERT ou CAST) ...

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

... et cela produit les réponses suivantes, qui sont toutes deux correctes.

entrez la description de l'image ici

Comme on dit dans les publicités télévisées, "Mais attendez! Ne commandez pas encore! Sans frais supplémentaires, il peut faire BEAUCOUP plus!"

Voyons la puissance réelle des conversions temporelles avec DATETIME et examinons partiellement l'erreur connue sous le nom de DATETIME2. Découvrez les formats loufoques que DATETIME peut gérer automatiquement et que DATETIME2 ne peut pas. Exécutez le code suivant et consultez ...

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

Donc, oui ... SQL Server a en fait une méthode assez flexible pour gérer toutes sortes de formats temporels bizarres et aucune manipulation particulière n'est requise. Nous n'avons même pas eu besoin de supprimer les "PM" qui ont été ajoutés aux heures de 24 heures. C'est "PFM" (Pure Freakin 'Magic).

Les choses varieront un peu en fonction de la LANGUE que vous avez sélectionnée pour votre serveur, mais une grande partie sera gérée de toute façon.

Et ces conversions "auto-magiques" ne sont pas quelque chose de nouveau. Ils remontent très loin.

Jeff Moden
la source
Une nouvelle réponse méchante pour une vieille question méchante. Merci!
JosephStyons
Merci pour vos commentaires, @JosephStyons.
Jeff Moden le
0

Si vous voulez que SQL Server essaie de le comprendre, utilisez simplement CAST CAST ('quel que soit' comme date / heure). Cependant, c'est une mauvaise idée en général. Il y a des problèmes avec les dates internationales qui pourraient survenir. Donc, comme vous l'avez constaté, pour éviter ces problèmes, vous souhaitez utiliser le format canonique ODBC de la date. C'est le format numéro 120, 20 est le format pour les années à deux chiffres seulement. Je ne pense pas que SQL Server ait une fonction intégrée qui vous permet de fournir un format donné à l'utilisateur. Vous pouvez écrire le vôtre et même en trouver un si vous effectuez une recherche en ligne.

Will Rickards
la source
Si vous avez des dates internationales dans une seule colonne, je conviens absolument que l'utilisation d'un numéro de format est une bonne idée. Si vous avez des dates internationales et des dates américaines toutes mélangées dans une seule colonne, il n'y a tout simplement aucun moyen de déterminer la différence entre quelque chose comme 7/6/2000 et 6/7/2000, sauf si vous avez une colonne sœur qui explique le format. C'est pourquoi la qualité des données à la source DOIT simplement être une chose. Si vous SAVEZ que vous avez, disons, toutes les dates américaines, laissez les conversions implicites faire leur travail. S'ils échouent, vous savez avec certitude que quelque chose dans la colonne doit être corrigé.
Jeff Moden
0

convertir implicitement une chaîne en datetime dans 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
la source
Bonjour et bienvenue sur stackoverflow, et merci d'avoir répondu. Bien que ce code puisse répondre à la question, pouvez-vous envisager d'ajouter des explications sur le problème que vous avez résolu et comment vous l'avez résolu? Cela aidera les futurs lecteurs à mieux comprendre votre réponse et à en tirer des leçons.
plutien
-4
dateadd(day,0,'10/15/2008 10:06:32 PM')
Yaroslav
la source
3
Bienvenue dans StackOverflow! Veuillez modifier votre réponse pour ajouter une explication à votre code. Cette question a presque onze ans et a déjà de nombreuses réponses bien expliquées et votées. Sans une explication dans votre réponse, elle est de bien moins bonne qualité que ces autres et sera probablement rejetée ou supprimée. L'ajout de cette explication aidera à justifier l'existence de votre réponse ici.
Das_Geek
Ouais, mais les messages "bien expliqués", même ceux qui ont été votés, sont bien trop complexes. Celui publié ici est en fait l'un des meilleurs, avec ou sans explication,
Jeff Moden