version=2.5.0 vdate=15.03.2016 fname=cast_strtodate.bas ns=%NAMESPACE% fpath=/vba/cast {{keywords>vba,cast;String to Date,String to Time,str2date,str2time}} ====== [VBA] strToDate()====== //Diese Funktion parst ein String in ein Date. Im Gegensatz zu cDate() von VBA kann hier das Datumsformat mitgegeben werden. Die meisten Formatzeichen von VBA werden unterstüzt. // ==Version %%version%% - %%vdate%%== {{%%fname%%|Download %%fname%% (V-%%version%%)}} Um die Funktion bei mehrmaliger Anwendung zu beschleunigen, werden die RegExp-Objekte mit den generierten Pattern in ein privates Dictionary-Objekt gespeichert. Das führt zu einer erheblichen Geschwindigkeitsverbesserung bei der Anwendung innerhalb eines SQL-Statements > siehe auch [[vba:classes:date:datetime:index]] ===== Definition ===== date = strToDate(string [,format [,parameters [,erster Tag der Woche [,erste Woche des Jahres [,nanosekunden]]]]]) Public Function strToDate( _ ByVal iDate As Variant, _ Optional ByVal iFormat As String = vbNullString, _ Optional ByVal iParams As tdtParams = tdtIgnoreCase, _ Optional ByVal iFirstDayOfWeek As VbDayOfWeek = vbUseSystemDayOfWeek, _ Optional ByVal iFirstWeekOfYear As VbFirstWeekOfYear = vbUseSystem, _ Optional ByRef oNanoSecounds As Long _ ) As Variant ==== Parameterliste ==== ***iDateS** Der Datumsstring, der in ein Datum geparst werden soll ***//iFormat//** Das Datumsformat. Wird eines der folgenden Zeichen als Trennzeichen verwendet, muss es mit einem \ maskiert werden (siehe Beispiele): M D Y H N S ***//iParams//** Weitere Parameter. Siehe dazu der Enumerator [[#tdtParams]]. DIese sind mit + kombinierbar. Default ist %%tdtIgnoreCase%% ***//iFirstDayOfWeek//** Angabe zum ersten Wochentag. Schweiz -> Montag ***//iFirstWeekOfYear//** Angabe zum ersten Woche im Jahr ***//oNanoSecounds//** Rückgabewert für die Nanosekunden (Siehe Beispiel [[#extraktion_von_nanosekunden|| Extraktion von Nanosekunden]]) ==== Enumerators ==== === tdtParams === Public Enum tdtParams tdtNone = 0 tdtIgnoreCase = 2 ^ 0 'Gross-Kleinschreibung bei Trennzeichen ignorieren tdtExtractDate = 2 ^ 1 'Der String beimnhaltet vor oder nach dem Datum noch andere Werte. Das Datum wird extrahiert tdtIgnoreError = 2 ^ 2 'Fehler werden ignoriert. Im Fehlerfall wird NULL zurückgegeben tdtFomat2 = 2 ^ 3 'Es handelt sich um ein Format im Stil von {$DD}.{$MM} End Enum ==== Formatidentifikatoren ==== ^ Format ^ Beschreibung ^ | m | Monat ohne führende Null (1-12) | | mm | Monat mit führende Null (01-12) | | d | Tag ohne führende Null (1-31) | | dd | Tag mit führende Null (01-31) | | yy | zweistelliges oder vierstelliges Jahr | | yyyy | vierstelliges Jahr | | q | QuartalAnfang (1.1.x - 1.10.x) | | qq | QuartalEnde (31.3.x - 31.12.x)| | h | Stunden ohne führende Null(0-24) | | hh | Stunden mit führende Null(00-24) | | n | Minuten ohne führende Null(0-59) | | nn | Minuten mit führende Null(00-59) | | s | Sekunden ohne führende Null(0-59) | | ss | Sekunden mit führende Null(00-59) | | am/pm | Erwartet eine Angabe von AM oder PM | | a/p | Erwartet eine Angabe von A oder P | | y | Tag des Jahres | | w | Tag der Woche | | ww | Woche im Jahr | | f | Nanosekunden | | @ | Delemiter bei unklarer Trennung (siehe [[#unklare_formate|Beispiel unklare Formate]]) | ==== Fehlerrückgabe ==== ^ Fehlernummer ^ Beschreibung ^ | 13 | Es wurde kein Format mitgegeben und der String lässt sich nicht durch das Sytem in ein Datum wandeln. Siehe cdate() | | -2147221503 (C_SD_ERR_INVALID_FORMAT) | Das Format ist nicht parsbar | | -2147221502 (C_SD_ERR_NOT_PARSEBLE) | Der String passt nicht mit dem Format überein | ==== Access/Excel ==== Excel kennt leider die lebenswichtige Funktion NZ() nicht. Darum muss für Excel diese Funktion hinzuprogrammiert sein. Das steurt man über die Kompilierungskonstante isAccess Am Anfang vom Code befindet sich darum die Zeile \\ Für Access ist dies True, für Excel False #Const isAccess = True ===== Anwendungsbeispiele ===== Hier einige Anwendungsbeispiele > Für die Ausgabe der Resultate verwendete ich die Funktion [[:vba:functions:print_r:]]. === Ohne Format === Es wird intern cDate angewendet print_r strToDate("5.9.2013") 05.09.2013 === Mit Format === Diverse Formatierungen mit Formaten 'Mit dem Format den Tag und Monat genau zuordnern. Damit aus 5.9 der 9te Mai wird print_r strToDate("5.9.2013", "m.d.yyyy") 09.05.2013 'Einen String ohne Trennzeichen print_r strToDate("05092013", "mmddyyyy") 09.05.2013 'und mit Uhrzeit print_r strToDate("05092013_151765", "mmddyyyy_hhnnss") 09.05.2013 15:18:05 'und mit AM/PM print_r strToDate("05092013_121765_AM", "mmddyyyy_hhnnss_am/pm") 09.05.2013 00:18:05 'nur die Zeit print_r strToDate("17:6:65", "h:n:s") 17:07:05 'Quartalsanfang print_r strToDate("Q3 2015", "\QQ YYYY") 01.07.2015 'Und das Quartalsende print_r strToDate("Q3 2015", "\QQQ YYYY") 30.09.2015 === Länder Formatchaos === Ein Datum kann je nach Land unterschiedlich geschrieben werden. Dass kann zu Fehler führen. Nehmen wir das Amerikanische Format MM/DD/YYYY. In der Schweiz und in Deutschland haben wir DD.MM.YYYY. VBA nimmt die Ländereinstellung vom PC-Profil. Wenn der Tag kleiner oder gleich 12 ist, dann haben wir ein Problem. Dann erkennt VBA den Tag als Monat und das Resultat ist Falsch. \\ Als Beispiel der 5. Januar 2017. Im Amerikanischen Format 01/05/2017. cDate mit Schweizer Einstellung macht daraus den 1. Mai 2017. 'Einfacher cDate. Der Tag ist Kleinergleich als 12. Das Resultat ist falsch print_r cDate("01/05/2017") 01.05.2017 'Wenn die zweite Position über 12 ist, erkennt VBA, dass es sich um den Tag handeln muss print_r cDate("01/15/2017") 15.01.2017 'Mit strToDate und einem definierten Format wird das Datum richtig umgesetzt print_r strToDate("01/05/2017", "MM/DD/YYYY") 05.01.2017 === Unklare Formate === Mit Trennzeichen, die auch Formate sind. Darum müsse diese Zeichen im Format mit einem \ maskiert werden Das Format ist: D gefolgt vom Tag (1-31), M gefolgt von einem Monat (01-12) und Y gefolgt vom Jahr print_r strToDate("D1M05Y2013", "\DD\MMM\YYYYY") 01.05.2013 Ein Bespiel, bei dem nicht klar ist wo die Trennung ist. In Dem Fall der 133te Tag im Jahr 2015. print_r strToDate("1332015", "YYYYY") 15.01.1332 'Und jetzt mit einem @ als Delemiter um genau anzugeben wo der neue Pattern beginnt print_r strToDate("1332015", "Y@YYYY") 13.05.2015 === Die Funktion der Paramters === 'Ohne tdtExtractDate print_r strToDate("Heute ist der 1.12.2014", "d.m.yyyy") -> Fehler -2147221502 'Mit tdtExtractDate print_r strToDate("Heute ist der 1.12.2014", "d.m.yyyy", tdtExtractDate) 01.12.2014 'Mit tdtExtractDate, ohne tdtIgnoreCase. Man beachte, der 'Monat' ist im Format klein geschrieben (und maskiert) print_r strToDate("Heute ist der 1te des 12ten Monats 2014", "dte \de\s mte\n \mo\nat\s yyyy", tdtExtractDate) -> Fehler -2147221502 'Und kombiniert mit tdtIgnoreCase print_r strToDate("Heute ist der 1te des 12ten Monats 2014", "dte \de\s mte\n \mo\nat\s yyyy", tdtExtractDate + tdtIgnoreCase) 01.12.2014 === FirstDayOfWeek und FirstWeekOfYear === Bei Formaten mit Wochentage und Wochennummer ist es entscheidend, was als Erste Woche des Jahres gerechnet wird und mit welchem Tag die Woche beginnt. 'Zweiter Wochentag in der 3ten Woche im Jahr 2015 nach Systemeinstellungen Schweiz print_r strToDate("2/3/2015", "W/WW/YYYY") 13.01.2015 'Dasselbe wenn die Erste Woche als die erste Volle Woche gerechnet wird print_r strToDate("2/3/2015", "W/WW/YYYY",,,vbFirstFullWeek) 20.01.2015 'Und dann noch di Ienstellung, dass der erste tag in der Woche der Sonntag ist (ja, das gibt es in gewissen Ländern) print_r strToDate("2/3/2015", "W/WW/YYYY",,vbSunday,vbFirstFullWeek) 19.01.2015 === Extraktion von Nanosekunden === Leider können die Nanosekunden nicht im Datumsformat ausgegeben werde. Das ist so von VBA nicht vorgesehen. Über den Rückgabeparameter oNanoSecounds kann trotzdem darauf zugegriffen werden Dim nano As Long Dim dt As Date dt = strToDate("12:13:34.01234", "HH:MM:NN.F", , , , nano) print_r dt -> 31.12.2000 12:34:00 print_r nano -> 12340000 === Datumsstring umformatieren === Noch ein kleines Beispiel zum umformatieren eines Datum-Strings in ein anderer. Das brauche ich häufig wenn ich mit Schnittstellen zu anderen System arbeite. \\ In dem Beispiel habe ich ein Datum im Format ''ddmmyyyy''. Für das andere System brauche ich das Format ''m/d/yyyy'', wobei hier ''/'' nicht für den Loakalen Seperator steht, sondern für den String ''/''. Darum muss er für den VBA-Befehl format() mit \ maskiert werden. print_r format(strToDate("01061972", "ddmmyyyy"), "m\/d\/yyyy") '6/1/1972' ===== Code ===== {{tag>vba:Functions vba:Date VBA}}