VBA 日期处理:Date、Now、Format
在 VBA 编程中,日期和时间处理是最频繁的需求之一。无论是记录业务操作时间、生成报表、还是计算时间差,都离不开日期相关函数。本文将详细介绍 VBA 中最常用的三个日期处理函数:Date、Now 和 Format,并通过实际案例展示它们的用法。
一、VBA 日期类型的基本概念
在 VBA 中,日期和时间是以浮点数的形式存储的。整数部分代表日期(从 1899 年 12 月 30 日开始计算),小数部分代表时间(0 表示午夜,0.5 表示中午,0.99999 表示距离午夜不到 1 秒)。理解这一底层机制有助于你更好地掌握日期运算。
日期值 44562.5 = 2022年1月15日中午12:00
二、Date 函数:获取当前日期
Date 函数返回当前系统日期,不包含时间部分。这是 VBA 中获取"今天"最简单直接的方式。
基本语法
Dim today As Date
today = Date
Date 函数不需要任何参数,调用它就会返回当前日期。
实用场景
场景一:记录数据录入日期
Sub RecordEntryDate()
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
' 在A列最后一行写入当前日期
Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row + 1
ws.Cells(lastRow, 1).Value = Date
ws.Cells(lastRow, 2).Value = "新录入"
End Sub
场景二:判断数据是否过期
Sub CheckExpiredItems()
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("库存")
Dim i As Long
For i = 2 To ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
' C列是有效期
If ws.Cells(i, 3).Value < Date Then
ws.Cells(i, 4).Value = "已过期"
ws.Cells(i, 4).Interior.Color = RGB(255, 200, 200)
Else
ws.Cells(i, 4).Value = "有效"
End If
Next i
End Sub
进阶用法:日期计算
由于 VBA 日期本质是数字,你可以直接进行加减运算。
Sub DateCalculation()
Dim today As Date
today = Date
' 一周后的日期
Dim nextWeek As Date
nextWeek = today + 7
' 30天后的日期
Dim thirtyDaysLater As Date
thirtyDaysLater = today + 30
' 上月的最后一天
Dim lastMonthEnd As Date
lastMonthEnd = DateAdd("d", -Day(today), today)
Debug.Print "今天是: " & today
Debug.Print "一周后: " & nextWeek
Debug.Print "30天后: " & thirtyDaysLater
Debug.Print "上月最后一天: " & lastMonthEnd
End Sub
三、Now 函数:获取当前日期和时间
Now 函数返回当前系统的完整日期和时间,精确到秒。与 Date 不同,Now 同时包含日期和时间信息。
基本语法
Dim now As Date
now = Now
实用场景
场景一:记录操作时间戳
Sub RecordOperationTimestamp()
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("日志")
Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row + 1
ws.Cells(lastRow, 1).Value = Now
ws.Cells(lastRow, 2).Value = Environ("Username") ' 获取用户名
ws.Cells(lastRow, 3).Value = "数据更新"
End Sub
场景二:计算程序执行时间
Sub MeasureExecutionTime()
Dim startTime As Date
Dim endTime As Date
Dim duration As Double
startTime = Now
' ===== 这里是需要计时的代码 =====
Dim i As Long
For i = 1 To 100000
Cells(i Mod 100 + 1, 1).Value = i
Next i
' ===== 计时代码结束 =====
endTime = Now
' 计算耗时(秒)
duration = DateDiff("s", startTime, endTime)
MsgBox "程序执行耗时: " & duration & " 秒"
End Sub
Date 与 Now 的区别
| 函数 | 返回值 | 适用场景 |
|---|---|---|
Date |
2024/3/15 | 只关心日期,如有效期、截止日 |
Now |
2024/3/15 14:30:25 | 需要精确时间,如日志、计时 |
四、Format 函数:格式化日期与时间
Format 函数是 VBA 中最强大的格式化工具,它可以将日期转换为任意你需要的字符串格式。掌握 Format 是日期处理的关键技能。
基本语法
Format(expression, [format], [firstdayofweek], [firstweekofyear])
expression:要格式化的值(日期、数字或字符串)format:格式模板,可选预定义格式或自定义格式
预定义格式
VBA 提供了一系列预定义格式,可以快速使用:
Sub PredefinedFormats()
Dim dt As Date
dt = Now
Debug.Print "General Date: " & Format(dt, "General Date")
Debug.Print "Long Date: " & Format(dt, "Long Date")
Debug.Print "Medium Date: " & Format(dt, "Medium Date")
Debug.Print "Short Date: " & Format(dt, "Short Date")
Debug.Print "Long Time: " & Format(dt, "Long Time")
Debug.Print "Medium Time: " & Format(dt, "Medium Time")
Debug.Print "Short Time: " & Format(dt, "Short Time")
End Sub
输出示例:
General Date: 2024/3/15
Long Date: 2024年3月15日
Medium Date: 24/03/15
Short Date: 2024/3/15
Long Time: 14:30:25
Medium Time: 02:30 下午
Short Time: 14:30
自定义格式
自定义格式让你可以精确控制输出的每一个部分:
Sub CustomFormats()
Dim dt As Date
dt = #3/15/2024 2:30:25 PM#
' 年
Debug.Print "yyyy: " & Format(dt, "yyyy") ' 2024
Debug.Print "yy: " & Format(dt, "yy") ' 24
' 月
Debug.Print "mmmm: " & Format(dt, "mmmm") ' March
Debug.Print "mmm: " & Format(dt, "mmm") ' Mar
Debug.Print "mm: " & Format(dt, "mm") ' 03 (两位数字)
Debug.Print "m: " & Format(dt, "m") ' 3 (一位或两位)
' 日
Debug.Print "dddd: " & Format(dt, "dddd") ' Friday
Debug.Print "ddd: " & Format(dt, "ddd") ' Fri
Debug.Print "dd: " & Format(dt, "dd") ' 15
' 时间
Debug.Print "hh: " & Format(dt, "hh") ' 02 (12小时制)
Debug.Print "HH: " & Format(dt, "HH") ' 14 (24小时制)
Debug.Print "nn: " & Format(dt, "nn") ' 30 (分钟)
Debug.Print "ss: " & Format(dt, "ss") ' 25 (秒)
Debug.Print "AM/PM: " & Format(dt, "AM/PM") ' PM
End Sub
常用格式组合示例
Sub CommonFormatExamples()
Dim dt As Date
dt = Now
' 中文格式
Debug.Print "中文完整: " & Format(dt, "yyyy年mm月dd日") ' 2024年03月15日
Debug.Print "中文短: " & Format(dt, "yy/mm/dd") ' 24/03/15
' 英文格式
Debug.Print "美式: " & Format(dt, "MM/DD/YYYY") ' 03/15/2024
Debug.Print "英式: " & Format(dt, "DD/MM/YYYY") ' 15/03/2024
Debug.Print "ISO: " & Format(dt, "YYYY-MM-DD") ' 2024-03-15
' 带时间格式
Debug.Print "完整: " & Format(dt, "yyyy-mm-dd hh:nn:ss") ' 2024-03-15 14:30:25
Debug.Print "简洁: " & Format(dt, "mm/dd hh:nn") ' 03/15 14:30
Debug.Print "12小时: " & Format(dt, "yyyy-mm-dd hh:nn:ss AM/PM") ' 2024-03-15 02:30:25 PM
' 只显示部分
Debug.Print "只显示月份: " & Format(dt, "mmmm yyyy") ' March 2024
Debug.Print "只显示时间: " & Format(dt, "hh:nn") ' 14:30
Debug.Print "只显示周几: " & Format(dt, "aaaa") ' 星期五
End Sub
格式中的转义字符
如果格式字符本身需要作为普通文本显示,需要用双引号括起来:
Sub FormatWithText()
Dim dt As Date
dt = #3/15/2024#
' 在格式中加入普通文本
Debug.Print "文本1: " & Format(dt, "yyyy年mm月dd日") ' 2024年03月15日
Debug.Print "文本2: " & Format(dt, "今天是 yyyy/mm/dd") ' 今天是 2024/03/15
' 用引号包裹任意文本
Debug.Print "文本3: " & Format(dt, "dd""日"" mm""月""") ' 15日 03月
End Sub
五、综合实战案例
案例一:自动生成带日期的报表文件名
Sub GenerateReportFilename()
Dim reportDate As Date
reportDate = Date
Dim filename As String
filename = "销售报表_" & Format(reportDate, "yyyymmdd") & ".xlsx"
Debug.Print "文件名: " & filename
' 输出: 销售报表_20240315.xlsx
' 实际保存文件
Dim savePath As String
savePath = "C:\Reports\" & filename
' 如果目录不存在则创建
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.FolderExists("C:\Reports") Then
fso.CreateFolder ("C:\Reports")
End If
' 保存工作簿
ThisWorkbook.SaveAs savePath
End Sub
案例二:计算业务年龄和工龄
Sub CalculateServiceYear()
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("员工信息")
Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
Dim i As Long
For i = 2 To lastRow
Dim birthDate As Date
Dim hireDate As Date
Dim today As Date
birthDate = ws.Cells(i, 3).Value ' C列:出生日期
hireDate = ws.Cells(i, 4).Value ' D列:入职日期
today = Date
' 计算年龄(精确到月)
Dim ageMonths As Long
ageMonths = DateDiff("m", birthDate, today)
If Day(today) < Day(birthDate) Then
ageMonths = ageMonths - 1
End If
' 计算工龄(精确到月)
Dim serviceMonths As Long
serviceMonths = DateDiff("m", hireDate, today)
' 写入结果
ws.Cells(i, 5).Value = ageMonths \ 12 & "岁" & ageMonths Mod 12 & "个月"
ws.Cells(i, 6).Value = serviceMonths \ 12 & "年" & serviceMonths Mod 12 & "个月"
' 格式化显示
ws.Cells(i, 5).NumberFormat = "@"
ws.Cells(i, 6).NumberFormat = "@"
Next i
MsgBox "计算完成!"
End Sub
案例三:生成工作日日历
Sub GenerateWorkdayCalendar()
Dim startDate As Date
Dim endDate As Date
Dim currentDate As Date
startDate = Date ' 从今天开始
endDate = DateAdd("m", 3, startDate) ' 三个月后
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("日历")
ws.Cells.Clear
' 写入表头
ws.Range("A1").Value = "日期"
ws.Range("B1").Value = "星期"
ws.Range("C1").Value = "是否工作日"
Dim rowNum As Long
rowNum = 2
currentDate = startDate
Do While currentDate <= endDate
ws.Cells(rowNum, 1).Value = currentDate
ws.Cells(rowNum, 1).NumberFormat = "yyyy-mm-dd"
ws.Cells(rowNum, 2).Value = Format(currentDate, "aaaa")
' 判断是否周末(周六=7,周日=1)
Dim weekDay As Integer
weekDay = Weekday(currentDate, vbSunday)
If weekDay = 1 Or weekDay = 7 Then
ws.Cells(rowNum, 3).Value = "周末"
ws.Cells(rowNum, 3).Interior.Color = RGB(220, 220, 220)
Else
ws.Cells(rowNum, 3).Value = "工作日"
End If
rowNum = rowNum + 1
currentDate = currentDate + 1
Loop
' 自动调整列宽
ws.Columns("A:C").AutoFit
MsgBox "日历生成完成,共 " & (rowNum - 2) & " 天"
End Sub
六、常见问题与解决方案
问题一:日期显示为数字
有时从Excel读取日期时,发现它显示为数字(如44562),这是因为Excel单元格格式被更改。
Sub FixDateDisplay()
Dim cell As Range
For Each cell In Selection
If IsDate(cell.Value) Then
' 恢复为日期格式
cell.NumberFormat = "yyyy-mm-dd"
End If
Next cell
End Sub
问题二:日期比较不准确
比较日期时,时间部分可能导致意外结果。
Sub DateCompareIssue()
Dim date1 As Date
Dim date2 As Date
date1 = #3/15/2024 10:00:00 AM#
date2 = #3/15/2024#
' 直接比较会失败,因为有时间部分
Debug.Print date1 = date2 ' False
' 解决方法:使用 DateValue 去除时间部分
Debug.Print DateValue(date1) = DateValue(date2) ' True
Debug.Print DateValue(date1) = date2 ' True
End Sub
问题三:时区问题
Date 和 Now 获取的是系统本地时间。在跨时区应用中需要注意。
Sub HandleTimezone()
' 获取UTC时间
Dim utcNow As Date
utcNow = Now + TimeZoneOffset() ' 需要自行计算时区差
' 本地时间转UTC
Dim localToUtc As Date
localToUtc = DateAdd("h", -8, Now) ' 假设本地是UTC+8
' 格式化时明确时区
Dim isoFormat As String
isoFormat = Format(utcNow, "yyyy-mm-ddTHH:nn:ss") & "Z" ' Z表示UTC
Debug.Print isoFormat
End Sub
七、日期处理函数速查表
| 函数/关键字 | 作用 | 示例 |
|---|---|---|
Date |
返回当前日期 | Date → 2024/3/15 |
Now |
返回当前日期和时间 | Now → 2024/3/15 14:30 |
Time |
返回当前时间 | Time → 14:30:25 |
Format |
格式化日期/时间 | Format(d, "yyyy-mm-dd") |
DateValue |
提取日期部分 | DateValue(Now) → 2024/3/15 |
TimeValue |
提取时间部分 | TimeValue(Now) → 14:30:25 |
DateDiff |
计算日期间隔 | DateDiff("d", d1, d2) |
DateAdd |
添加时间间隔 | DateAdd("m", 1, d) |
Weekday |
返回星期几 | Weekday(d, vbSunday) |
Day |
提取日 | Day(d) → 15 |
Month |
提取月 | Month(d) → 3 |
Year |
提取年 | Year(d) → 2024 |
掌握这三个核心函数——Date、Now 和 Format——能够满足 VBA 开发中 90% 以上的日期处理需求。建议在实际项目中多多练习,将这些函数的使用内化为本能。

暂无评论,快来抢沙发吧!