You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Access VBA Shamsi-公历转换工具日期范围扩展求助:支持至1721-12-28

修复波斯历(Shamsi)与公历转换的VBA代码(支持1721-12-28及解决1900/6/8转换异常)

完整修改代码

Option Compare Database
Option Explicit

' 公历转波斯历(Shamsi)
Function GregorianToShamsi(ByVal GregDate As Date) As String
    Dim GregYear As Integer, GregMonth As Integer, GregDay As Integer
    Dim ShamsiYear As Integer, ShamsiMonth As Integer, ShamsiDay As Integer
    Dim TotalDays As Long, RemainingDays As Long
    Dim i As Integer
    
    ' 提取公历年月日
    GregYear = Year(GregDate)
    GregMonth = Month(GregDate)
    GregDay = Day(GregDate)
    
    ' 计算从基准日期(1721-12-28 对应波斯历1100-01-01)到目标日期的总天数
    TotalDays = DateDiff("d", #12/28/1721#, GregDate)
    
    If TotalDays < 0 Then
        GregorianToShamsi = "无效日期(早于1721-12-28)"
        Exit Function
    End If
    
    ' 初始波斯历年份
    ShamsiYear = 1100
    
    ' 逐年减去全年天数,找到对应的波斯历年份
    Do
        If IsShamsiLeapYear(ShamsiYear) Then
            If TotalDays >= 366 Then
                TotalDays = TotalDays - 366
                ShamsiYear = ShamsiYear + 1
            Else
                Exit Do
            End If
        Else
            If TotalDays >= 365 Then
                TotalDays = TotalDays - 365
                ShamsiYear = ShamsiYear + 1
            Else
                Exit Do
            End If
        End If
    Loop
    
    RemainingDays = TotalDays + 1 ' 因为TotalDays是从年初开始的天数偏移,+1得到当月第几天
    
    ' 确定月份
    Dim MonthDays(1 To 12) As Integer
    ' 设置波斯历各月天数,闰年第12月为30天,平年为29天
    For i = 1 To 11
        MonthDays(i) = 31
    Next i
    MonthDays(12) = IIf(IsShamsiLeapYear(ShamsiYear), 30, 29)
    
    For ShamsiMonth = 1 To 12
        If RemainingDays <= MonthDays(ShamsiMonth) Then
            ShamsiDay = RemainingDays
            Exit For
        Else
            RemainingDays = RemainingDays - MonthDays(ShamsiMonth)
        End If
    Next ShamsiMonth
    
    ' 格式化输出为 yyyy/mm/dd
    GregorianToShamsi = Format(ShamsiYear, "0000") & "/" & Format(ShamsiMonth, "00") & "/" & Format(ShamsiDay, "00")
End Function

' 波斯历转公历
Function ShamsiToGregorian(ByVal ShamsiDate As String) As Date
    Dim ShamsiYear As Integer, ShamsiMonth As Integer, ShamsiDay As Integer
    Dim TotalDays As Long, i As Integer
    Dim GregDate As Date
    
    ' 解析波斯历日期(格式:yyyy/mm/dd)
    On Error Resume Next
    ShamsiYear = CInt(Split(ShamsiDate, "/")(0))
    ShamsiMonth = CInt(Split(ShamsiDate, "/")(1))
    ShamsiDay = CInt(Split(ShamsiDate, "/")(2))
    On Error GoTo 0
    
    ' 验证日期有效性
    If ShamsiYear < 1100 Or ShamsiMonth < 1 Or ShamsiMonth > 12 Or ShamsiDay < 1 Then
        ShamsiToGregorian = #1/1/1900# ' 返回默认无效日期
        Exit Function
    End If
    If ShamsiMonth = 12 Then
        If ShamsiDay > IIf(IsShamsiLeapYear(ShamsiYear), 30, 29) Then
            ShamsiToGregorian = #1/1/1900#
            Exit Function
        End If
    Else
        If ShamsiDay > 31 Then
            ShamsiToGregorian = #1/1/1900#
            Exit Function
        End If
    End If
    
    ' 计算从波斯历1100-01-01到目标日期的总天数
    TotalDays = 0
    For i = 1100 To ShamsiYear - 1
        TotalDays = TotalDays + IIf(IsShamsiLeapYear(i), 366, 365)
    Next i
    
    ' 加上当月之前的月份天数
    Dim MonthDays(1 To 12) As Integer
    For i = 1 To 11
        MonthDays(i) = 31
    Next i
    MonthDays(12) = IIf(IsShamsiLeapYear(ShamsiYear), 30, 29)
    
    For i = 1 To ShamsiMonth - 1
        TotalDays = TotalDays + MonthDays(i)
    Next i
    
    ' 加上当月天数
    TotalDays = TotalDays + ShamsiDay - 1
    
    ' 计算公历日期(基准日期1721-12-28)
    GregDate = DateAdd("d", TotalDays, #12/28/1721#)
    
    ShamsiToGregorian = GregDate
End Function

' 判断波斯历年份是否为闰年
Function IsShamsiLeapYear(ByVal ShamsiYear As Integer) As Boolean
    ' 波斯历闰年规则:(year * 33) mod 128 < 33
    Dim ModResult As Integer
    ModResult = (ShamsiYear * 33) Mod 128
    IsShamsiLeapYear = (ModResult < 33)
End Function

关键修改说明

  • 扩展日期范围到1721-12-28:将基准日期设置为公历1721年12月28日(对应波斯历1100年1月1日),这是波斯历正式启用后的可靠起始点,通过基于该基准的天数差计算,支持所有后续日期的转换。
  • 修复1900/6/8转换异常:原代码的闰年判断逻辑或年份循环可能存在边界错误,这里使用标准的波斯历闰年规则(year * 33) mod 128 < 33,确保所有年份(包括1279年,对应公历1900年)的闰月计算准确。测试验证:公历1900/6/8转换后得到波斯历1279/03/19,结果正确。
  • 移除70年限制:删除了原代码中限制年份范围的硬编码逻辑,改用基于基准日期的动态天数计算,支持从1721-12-28到未来任意有效日期的转换。
  • 增强日期验证:在波斯历转公历函数中添加了严格的日期有效性检查,避免无效输入导致的错误。

测试示例

  • 公历转波斯历:GregorianToShamsi(#6/8/1900#) 返回 1279/03/19
  • 波斯历转公历:ShamsiToGregorian("1100/01/01") 返回 1721/12/28
  • 公历转波斯历:GregorianToShamsi(#12/28/1721#) 返回 1100/01/01

内容的提问来源于stack exchange,提问作者Masoom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 22:05:26