我目前正在学习VBA编程,并遇到了以下情况,我将非常感谢您的帮助。理想情况下,不仅要找到解决方案,还要了解解决方案的工作原理和原因。
假设有一个数据库,可以从中导出数据电子表格。其中一列具有日期值,但它们的格式与导出格式不同。系统将日期发送为mm / dd / yyyy hh:mm AM / PM,例如04/11/2014 09:24 AM
,但电子表格将其标识为dd / mm / ...,这意味着它将输入04作为日期和11月作为月份。
在此列中,如果该日期在该月的12个月之前或之前,则该单元格将被格式化为日期。如果日期超过12日,则格式化为一般格式。
我的问题是,我可以编写一个可以反转日期和月份值的VBA宏并在新列中创建正确的日期吗?我认为它首先必须确定一个单元格是否被格式化为日期,然后以某种方式提取日期和月份在正确的位置,或者如果它被格式化为一般格式,然后使用不同的代码来提取正确的日期。
如果对于这个社区来说这个问题太基础了,而另一个社区更适合我,那么我很乐意在那里重新提出我的问题。
修改
在我的评论下面,我玩了一些功能,并寻找其他类似的功能,可能有助于做我需要的,用月值切换日期值,到目前为止,我有:
'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代码中对我来说似乎更“干净”,使用公式对我来说就像一个易变的解决方案。我不确定如何正确解释这个问题,但我在数据操作背后的正确编码方面更加舒适。
EDIT2:
我已经解决了工作表函数解决方案,如下所示。我花了一段时间才弄清楚如何绕过日期格式化单元格的FIND错误,并且只有在写入= IF时Excel中建议的列表中偶然发现了IFERROR函数。
'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翻译感兴趣,并将继续搜索这些公式。
答案 0 :(得分:0)
检查一下。我们以您的公式为例:
=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等效功能:
Find = Instr
日期= DateSerial
文字=格式(不完全相同但最接近)
代码相同:
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"))
代码等效:
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
您还可以检查单元格的格式,如下所示:
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
不确定以上是否能真正解决您的问题
从数据库中提取日期时间戳时,有很多种可能性
如果您提到的方案只是您遇到的问题,那么上述解决方案可能会有效。
答案 1 :(得分:0)
这现在是一个旧线程,但是如果有人遇到类似问题(如我所做)时偶然发现它,我会提供它。
我为此建议的VBA功能如下所示。它的风格并不严格遵循纯粹的编程实践(变量的声明等);而是相对容易理解的。
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