Excel VBA - Extract the correct dates from badly formatted dates?
我目前正在通过练习来学习VBA编程,并且遇到了以下情况,对于您的帮助,我将不胜感激。理想情况下,不仅要找到解决方案,还要了解解决方案的方式和原因。
假设有一个数据库,可以从中导出数据电子表格。其中一列具有日期值,但是它们在导出时格式错误。系统将日期发送为mm / dd / yyyy hh:mm AM / PM,例如
在此列中,如果日期在该月的12日之前或包括在内,则该单元格的格式为日期。如果一天是12日之后,则该单元格将采用常规格式进行格式化。
我的问题是,我可以编写一个VBA宏来反转日期和月份的值,并在新列中创建正确的日期吗?我认为,它首先必须确定单元格的格式是否为日期,然后以某种方式提取日期和月份的正确位置,或者是否将其格式设置为常规格式,然后使用其他代码提取正确的格式。日期。
如果这对于该社区来说太基本了,那么还有另一个更合适的社区,我很乐意在此重新提出我的问题。
编辑:
在下面的评论之后,我尝试了一些功能,并寻找了其他类似的功能来帮助我完成所需的工作,将日值与月值切换,到目前为止,我有了:
1 2 3 4 5 6 7 | 'for dates with general format: 04/14/2014 11:20 AM =DATE(MID(A1,7,4),LEFT(A1,2),MID(A1,4,2)) 'in a column for the date =TIME(MID(A1,12,2),MID(A1,15,2),"00") 'in a column for time, since I may need this 'for dates with a date format: 4/11/2014 7:35:00 PM =DATE(TEXT(A1,"yyyy"),TEXT(A1,"dd"),TEXT(A1,"mm")) 'in a column for the date =TEXT(A1,"hh:mm AM/PM") 'in a column for time |
现在,我只需要找出一个条件函数来确定何时根据值或格式或列A来应用每组公式。
但是,是否有通过VBA实现此功能的等效功能?我需要这些日期和时间列仅保存值,而不保存公式,以便可以直接从中导出数据。对我来说,以某种方式将其放入VBA代码中似乎更"干净",使用公式对我来说就像一个易失的解决方案。我不确定如何正确解释这一点,但是我对数据操作背后的正确编码感到更加自在。
编辑2:
我已经解决了以下工作表功能解决方案。我花了一段时间才弄清楚如何解决日期格式的单元格的FIND错误,并且在Excel提示编写= IF时,偶然发现了IFERROR函数。
1 2 3 4 | 'to get the correct date =IF(IFERROR(FIND("/",A1),0)>0,DATE(MID(A1,7,4),LEFT(A1,2),MID(A1,4,2)),DATE(TEXT(A1,"yyyy"),TEXT(A1,"dd"),TEXT(A1,"mm"))) 'to get the correct time =IF(IFERROR(FIND("/",A1),0)>0,TIME(MID(A1,12,2),MID(A1,15,2),"00"),TEXT(A1,"h:mm AM/PM")) |
现在至少我有一个可行的解决方案,但我仍然对这些公式的VBA转换感兴趣,并将继续搜索这些公式。
现在这是一个旧线程,但如果有人遇到类似问题而偶然发现它(如我所做的那样),我将提供它。
我为此建议的VBA功能如下所示。它的风格并不严格遵循纯粹的编程实践(声明变量等);而是相对容易理解的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | Function Date_Text_Convert( _ date_text As String, _ return_with_month_letters As Boolean, _ return_as_date_time_value As Boolean) ' Patrick S., June 2018 ' Intention: to enable mm/dd/yyyy[etc] imported text-string dates ' to be switched to dd/mm/yyyy[etc]. Can be adapted for other cases. ' Usage examples: if cell A2 contains the text-string: ' 06/26/2018 09:24 AM ' then in, for example, cell B2, type: ' =Date_Text_Convert(A2,TRUE,FALSE) or =Date_Text_Convert(A2,FALSE,FALSE) ' which returns: ' 26-Jun-2018 09:24 am or 26/06/2018 09:24 am ' To return a date-and-time value instead of a string, use, for example: ' =Date_Text_Convert(A2,TRUE,TRUE) ' establish the positions where the day and month digits start daypos = 4 mthpos = 1 rempos = 7 ' starting position of remaining part of the string ' establish the length of the relevant text sections: 2 characters each, in this case daylen = 2 mthlen = 2 ' so that, daytext = Mid(date_text, daypos, daylen) mthtext = Mid(date_text, mthpos, mthlen) remtext = Mid(date_text, rempos, 999) ' the remainder of the text string ' format the output according to 'return_with_month_letters' ' there are 2 options available, each using a different separator sep_stroke ="/" sep_hyphen ="-" If return_with_month_letters = True Then mthnum = mthtext * 1 mthindex = ((mthnum - 1) * 3) + 1 mthname = Mid("JanFebMarAprMayJunJulAugSepOctNovDec", mthindex, 3) newtext = daytext & sep_hyphen & mthname & sep_hyphen & LCase(remtext) ' LCase optional Else newtext = daytext & sep_stroke & mthtext & sep_stroke & UCase(remtext) ' UCase optional End If ' finally, return the output through the function name: either as a date, or as the text equivalent If return_as_date_time_value = True Then newdate = DateValue(newtext) + TimeValue(newtext) Date_Text_Convert = newdate Else Date_Text_Convert = newtext End If End Function |
看一下这个。让我们以您的公式为例:
VBA等效功能:
查找=指令
日期= DateSerial
文字=格式(不完全相同,但最接近)
等效代码:
1 2 3 4 5 6 7 8 9 10 11 | Dim mydate As Date Dim myformat As String myformat ="mm/dd/yyyy hh:mm AM/PM" If InStr(1, [A1],"/") > 0 Then mydate = DateSerial(Mid(Format([A1], myformat), 7, 4), _ Left(Format([A1], myformat), 2), Mid(Format([A1], myformat), 4, 2)) Else mydate = DateSerial(Year([A1]), Month([A1]), Day([A1])) End If [B1] = mydate |
请注意,
我用它来指代公式中的单元格A1。您可以像下面这样使用常规的
对于您的时间公式:
等效代码:
1 2 3 4 5 6 7 8 | Dim mytime As Date If InStr(1, [A1],"/") > 0 Then mytime = TimeValue([A1]) Else '~~> myformat is declared above mytime = TimeValue(Format([A1], myformat)) End If [C1] = mytime |
您还可以检查单元格的格式,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 | Select Case True Case [A1].NumberFormat ="General" mydate = DateSerial(Year([A1]), Month([A1]), Day([A1])) mytime = TimeValue(Format([A1], myformat)) Case [A1].NumberFormat = myformat '~~> again this is declared above mydate = DateSerial(Mid(Format([A1], myformat), 7, 4), _ Left(Format([A1], myformat), 2), Mid(Format([A1], myformat), 4, 2)) mytime = TimeValue([A1]) Case Else MsgBox"Invalid Format. Cannot be evaluated" End Select [B1] = mydate: [C1] = mytime |
不知道上面是否真的可以解决您的问题。
从数据库中提取日期时间戳时,只有很多可能性。
如果您提到的场景只是遇到的问题,那么上述解决方案可能会起作用。