VBA日期排序后首列始终出现'30-12-1899'问题求助
日期排序Sub过程中第二列首个日期异常问题分析与解决
我来帮你拆解这个问题——你遇到的第二列首个日期固定为30-12-1899的情况,本质是Excel日期的数值特性加上数组初始化的逻辑漏洞导致的,咱们一步步说清楚:
问题成因
- 数组初始化的默认值陷阱:你在Do循环里反复执行
ReDim daty(wiersz)、ReDim daty_int(wiersz)这类语句,每次ReDim都会把数组的所有元素重置为默认值——字符串数组是空字符串,数值数组则是0。而在Excel的日期系统里,数值0对应的就是1899-12-30(这是Excel设定的日期起始基准)。后续循环从i=0开始处理时,daty(0)其实是空字符串,转成日期数值后就是0,最终输出成那个异常日期。 - 循环边界的逻辑错误:你的Do循环用来统计行数,但循环结束后数组的长度和实际有效数据行数不匹配,导致数组里多了一个未被赋值的初始元素,被当成有效数据参与了排序和输出。
解决方法
核心思路是先准确统计有效数据行数,再针对性初始化数组,避免处理空的数组元素。下面是修正后的完整代码:
Function dzien(data As Date) As String Select Case Day(data) Case Is < 10 dzien = "0" & CStr(Day(data)) Case Is >= 10 dzien = CStr(Day(data)) End Select End Function Function miesiac(data As Date) As String Select Case Month(data) Case Is < 10 miesiac = "0" & CStr(Month(data)) Case Is >= 10 miesiac = CStr(Month(data)) End Select End Function Sub Sortuj_daty() Dim wb As Workbook Dim ws As Worksheet Set wb = ActiveWorkbook Set ws = wb.Worksheets(1) Dim i As Long Dim j As Long Dim daty() As Date Dim daty_int() As Double Dim daty_uporzadkowane() As Date Dim daty_calk As String Dim wiersz As Long ' 先统计第一列的有效数据行数 wiersz = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row ' 根据实际行数初始化数组 ReDim daty(1 To wiersz) ReDim daty_int(1 To wiersz) ReDim daty_uporzadkowane(1 To wiersz) ' 读取日期数据 For i = 1 To wiersz daty(i) = ws.Cells(i, 1).Value daty_int(i) = CDbl(daty(i)) ' 直接转数值,无需额外Format Next i ' 排序并写入第二列 daty_calk = "" For j = 1 To wiersz daty_uporzadkowane(j) = CDate(Application.WorksheetFunction.Small(daty_int, j)) ws.Cells(j, 2).Value = daty_uporzadkowane(j) ' 拼接年份拆分的字符串(按日-月-年格式拼接) daty_calk = daty_calk & dzien(daty_uporzadkowane(j)) & "-" & miesiac(daty_uporzadkowane(j)) & "-" & Year(daty_uporzadkowane(j)) & " " Next j ' 写入第三列 ws.Cells(1, 3).Value = Trim(daty_calk) End Sub
额外做了几个实用优化:
- 把函数的参数类型从
String改成Date,避免字符串转日期的额外开销和潜在错误 - 用
ws.Cells(ws.Rows.Count, 1).End(xlUp).Row更高效地统计有效行数,替代原来的Do循环 - 直接用
CDbl(daty(i))转换日期数值,去掉冗余的Format操作 - 调整数组索引从1开始,更符合Excel单元格的索引习惯,彻底规避空元素问题
内容的提问来源于stack exchange,提问作者Paweł
相关产品推荐
相关产品推荐

