关于Excel VBA:Excel VBA-从格式错误的日期中提取正确的日期?

Excel VBA - Extract the correct dates from badly formatted dates?

我目前正在通过练习来学习VBA编程,并且遇到了以下情况,对于您的帮助,我将不胜感激。理想情况下,不仅要找到解决方案,还要了解解决方案的方式和原因。

假设有一个数据库,可以从中导出数据电子表格。其中一列具有日期值,但是它们在导出时格式错误。系统将日期发送为mm / dd / yyyy hh:mm AM / PM,例如04/11/2014 09:24 AM,但是电子表格将此日期标识为dd / mm / ...,这意味着它将输入04作为日期,将11输入为这个月。

在此列中,如果日期在该月的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

看一下这个。让我们以您的公式为例:

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

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]是快捷方式Evaluate函数,也可以写为Evaluate("A1")
我用它来指代公式中的单元格A1。您可以像下面这样使用常规的Range Object参考:Range("A1")。我使用了快捷方式,因为它看起来更干净。但是在海量数据集中不建议这样做。

对于您的时间公式:

=IF(IFERROR(FIND("/",A1),0)>0,TIME(MID(A1,12,2),MID(A1,15,2),"00"),TEXT(A1,"h:mm AM/PM"))

等效代码:

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

不知道上面是否真的可以解决您的问题。
从数据库中提取日期时间戳时,只有很多可能性。
如果您提到的场景只是遇到的问题,那么上述解决方案可能会起作用。