ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 30959|回复: 49

[分享] 农历与公历互相转换的自定义函数(强大)

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2013-1-24 15:56 | 显示全部楼层 |阅读模式
本帖已被收录到知识树中,索引项:自定义函数开发
本帖最后由 时光鸟 于 2013-1-24 16:34 编辑

  1. '公历转农历模块
  2. '原创:互联网
  3. '修正:阿勇 2005/1/12
  4. '// 农历数据定义 //
  5. '先以 H2B 函数还原成长度为 18 的字符串,其定义如下:
  6. '前12个字节代表1-12月:1为大月,0为小月;压缩成十六进制(1-3位)
  7. '第13位为闰月的情况,1为大月30天,0为小月29天;(4位)
  8. '第14位为闰月的月份,如果不是闰月为0,否则给出月份(5位)
  9. '最后4位为当年农历新年的公历日期,如0131代表1月31日;当作数值转十六进制(6-7位)

  10. '农历常量(1899~2100,共202年)
  11. Private Const ylData = "AB500D2,4BD0883," _
  12.         & "4AE00DB,A5700D0,54D0581,D2600D8,D9500CC,655147D,56A00D5,9AD00CA,55D027A,4AE00D2," _
  13.         & "A5B0682,A4D00DA,D2500CE,D25157E,B5500D6,56A00CC,ADA027B,95B00D3,49717C9,49B00DC," _
  14.         & "A4B00D0,B4B0580,6A500D8,6D400CD,AB5147C,2B600D5,95700CA,52F027B,49700D2,6560682," _
  15.         & "D4A00D9,EA500CE,6A9157E,5AD00D6,2B600CC,86E137C,92E00D3,C8D1783,C9500DB,D4A00D0," _
  16.         & "D8A167F,B5500D7,56A00CD,A5B147D,25D00D5,92D00CA,D2B027A,A9500D2,B550781,6CA00D9," _
  17.         & "B5500CE,535157F,4DA00D6,A5B00CB,457037C,52B00D4,A9A0883,E9500DA,6AA00D0,AEA0680," _
  18.         & "AB500D7,4B600CD,AAE047D,A5700D5,52600CA,F260379,D9500D1,5B50782,56A00D9,96D00CE," _
  19.         & "4DD057F,4AD00D7,A4D00CB,D4D047B,D2500D3,D550883,B5400DA,B6A00CF,95A1680,95B00D8," _
  20.         & "49B00CD,A97047D,A4B00D5,B270ACA,6A500DC,6D400D1,AF40681,AB600D9,93700CE,4AF057F," _
  21.         & "49700D7,64B00CC,74A037B,EA500D2,6B50883,5AC00DB,AB600CF,96D0580,92E00D8,C9600CD," _
  22.         & "D95047C,D4A00D4,DA500C9,755027A,56A00D1,ABB0781,25D00DA,92D00CF,CAB057E,A9500D6," _
  23.         & "B4A00CB,BAA047B,B5500D2,55D0983,4BA00DB,A5B00D0,5171680,52B00D8,A9300CD,795047D," _
  24.         & "6AA00D4,AD500C9,5B5027A,4B600D2,96E0681,A4E00D9,D2600CE,EA6057E,D5300D5,5AA00CB," _
  25.         & "76A037B,96D00D3,4AB0B83,4AD00DB,A4D00D0,D0B1680,D2500D7,D5200CC,DD4057C,B5A00D4," _
  26.         & "56D00C9,55B027A,49B00D2,A570782,A4B00D9,AA500CE,B25157E,6D200D6,ADA00CA,4B6137B," _
  27.         & "93700D3,49F08C9,49700DB,64B00D0,68A1680,EA500D7,6AA00CC,A6C147C,AAE00D4,92E00CA," _
  28.         & "D2E0379,C9600D1,D550781,D4A00D9,DA400CD,5D5057E,56A00D6,A6C00CB,55D047B,52D00D3," _
  29.         & "A9B0883,A9500DB,B4A00CF,B6A067F,AD500D7,55A00CD,ABA047C,A5A00D4,52B00CA,B27037A," _
  30.         & "69300D1,7330781,6AA00D9,AD500CE,4B5157E,4B600D6,A5700CB,54E047C,D1600D2,E960882," _
  31.         & "D5200DA,DAA00CF,6AA167F,56D00D7,4AE00CD,A9D047D,A2D00D4,D1500C9,F250279,D5200D1"

  32. Private Const ylMd0 = "初一初二初三初四初五初六初七初八初九初十十一十二十三十四十五" _
  33.         & "十六十七十八十九二十廿一廿二廿三廿四廿五廿六廿七廿八廿九三十 "

  34. Private Const ylMn0 = "正二三四五六七八九十冬腊"
  35. Private Const ylTianGan0 = "甲乙丙丁戊已庚辛壬癸"
  36. Private Const ylDiZhi0 = "子丑寅卯辰巳午未申酉戌亥"
  37. Private Const ylShu0 = "鼠牛虎兔龙蛇马羊猴鸡狗猪"

  38. '公历日期转农历
  39. Function GetYLDate(ByVal strDate As String) As String

  40. On Error GoTo aErr

  41.     If Not IsDate(strDate) Then Exit Function
  42.    
  43.     Dim setDate As Date, tYear As Integer, tMonth As Integer, tDay As Integer
  44.     setDate = CDate(strDate)
  45.     tYear = Year(setDate): tMonth = Month(setDate): tDay = Day(setDate)
  46.    
  47.     '如果不是有效有日期,退出
  48.     If tYear > 2100 Or tYear < 1900 Then Exit Function
  49.    
  50.     Dim daList() As String * 18, conDate As Date, thisMonths As String
  51.     Dim AddYear As Integer, AddMonth As Integer, AddDay As Integer, getDay As Integer
  52.     Dim YLyear As String, YLShuXing As String
  53.     Dim dd0 As String, mm0 As String, ganzhi(0 To 59) As String * 2
  54.     Dim RunYue As Boolean, RunYue1 As Integer, mDays As Integer, i As Integer
  55.    
  56.     '加载2年内的农历数据
  57.     ReDim daList(tYear - 1 To tYear)
  58.     daList(tYear - 1) = H2B(Mid(ylData, (tYear - 1900) * 8 + 1, 7))
  59.     daList(tYear) = H2B(Mid(ylData, (tYear - 1900 + 1) * 8 + 1, 7))
  60.    
  61.     AddYear = tYear

  62. initYL:

  63.     AddMonth = CInt(Mid(daList(AddYear), 15, 2))
  64.     AddDay = CInt(Mid(daList(AddYear), 17, 2))
  65.     conDate = DateSerial(AddYear, AddMonth, AddDay)     '农历新年日期
  66.    
  67.     getDay = DateDiff("d", conDate, setDate) + 1        '相差天数
  68.     If getDay < 1 Then AddYear = AddYear - 1: GoTo initYL
  69.    
  70.     thisMonths = Left(daList(AddYear), 14)
  71.     RunYue1 = Val("&H" & Right(thisMonths, 1))           '闰月月份
  72.     If RunYue1 > 0 Then                                  '有闰月
  73.         thisMonths = Left(thisMonths, RunYue1) & Mid(thisMonths, 13, 1) & Mid(thisMonths, RunYue1 + 1)
  74.     End If
  75.     thisMonths = Left(thisMonths, 13)
  76.    
  77.     For i = 1 To 13                                      '计算天数
  78.         mDays = 29 + CInt(Mid(thisMonths, i, 1))
  79.         If getDay > mDays Then
  80.             getDay = getDay - mDays
  81.         Else
  82.             If RunYue1 > 0 Then
  83.                 If i = RunYue1 + 1 Then RunYue = True
  84.                 If i > RunYue1 Then i = i - 1
  85.             End If
  86.             
  87.             AddMonth = i
  88.             AddDay = getDay
  89.             Exit For
  90.         End If
  91.     Next
  92.    
  93.     dd0 = Mid(ylMd0, (AddDay - 1) * 2 + 1, 2)
  94.     mm0 = Mid(ylMn0, AddMonth, 1) + "月"
  95.    
  96.     For i = 0 To 59
  97.         ganzhi(i) = Mid(ylTianGan0, (i Mod 10) + 1, 1) + Mid(ylDiZhi0, (i Mod 12) + 1, 1)
  98.     Next i

  99.     YLyear = ganzhi((AddYear - 4) Mod 60)
  100.     YLShuXing = Mid(ylShu0, ((AddYear - 4) Mod 12) + 1, 1)
  101.     If RunYue Then mm0 = "闰" & mm0
  102.    
  103.     GetYLDate = "农历" & YLyear & "(" & YLShuXing & ")年" & mm0 & dd0

  104. aErr:
  105.    
  106. End Function


  107. '农历转公历日期
  108. 'secondMonth 为真,则天示当 tMonth 是闰月时,取第二个月
  109. Function GetDate(ByVal tYear As Integer, tMonth As Integer, tDay As Integer, Optional secondMonth As Boolean = False) As String

  110. On Error GoTo aErr

  111.     If tYear > 2100 Or tYear < 1899 Or tMonth > 12 Or tMonth < 1 Or tDay > 30 Or tDay < 1 Then Exit Function
  112.    
  113.     Dim thisMonths As String, ylNewYear As Date, toMonth As Integer
  114.     Dim mDays As Integer, RunYue1 As Integer, i As Integer
  115.     thisMonths = H2B(Mid(ylData, (tYear - 1899) * 8 + 1, 7))
  116.    
  117.     If tDay > 29 + CInt(Mid(thisMonths, tMonth, 1)) Then Exit Function
  118.    
  119.     ylNewYear = DateSerial(tYear, CInt(Mid(thisMonths, 15, 2)), CInt(Mid(thisMonths, 17, 2)))     '农历新年日期
  120.    
  121.     thisMonths = Left(thisMonths, 14)
  122.     RunYue1 = Val("&H" & Right(thisMonths, 1))           '闰月月份
  123.    
  124.     toMonth = tMonth - 1
  125.     If RunYue1 > 0 Then                                  '有闰月
  126.         thisMonths = Left(thisMonths, RunYue1) & Mid(thisMonths, 13, 1) & Mid(thisMonths, RunYue1 + 1)
  127.         If tMonth > RunYue1 Or (secondMonth And tMonth = RunYue1) Then toMonth = tMonth
  128.     End If
  129.     thisMonths = Left(thisMonths, 13)
  130.         
  131.     mDays = 0
  132.     For i = 1 To toMonth
  133.         mDays = mDays + 29 + CInt(Mid(thisMonths, i, 1))
  134.     Next
  135.     mDays = mDays + tDay
  136.    
  137.     GetDate = ylNewYear + mDays - 1

  138. aErr:
  139.    
  140. End Function

  141. '将压缩的阴历字符还原
  142. Private Function H2B(ByVal strHex As String) As String
  143.     Dim i As Integer, i1 As Integer, tmpV As String
  144.     Const hStr = "0123456789ABCDEF"
  145.     Const bStr = "0000000100100011010001010110011110001001101010111100110111101111"
  146.    
  147.     tmpV = UCase(Left(strHex, 3))
  148.    
  149.     '十六进制转二进制
  150.     For i = 1 To Len(tmpV)
  151.         i1 = InStr(hStr, Mid(tmpV, i, 1))
  152.         H2B = H2B & Mid(bStr, (i1 - 1) * 4 + 1, 4)
  153.     Next
  154.    
  155.     H2B = H2B & Mid(strHex, 4, 2)
  156.    
  157.     '十六进制转十进制
  158.     H2B = H2B & "0" & CStr(Val("&H" & Right(strHex, 2)))
  159. End Function
复制代码


评分

4

查看全部评分

TA的精华主题

TA的得分主题

发表于 2013-1-24 16:09 | 显示全部楼层
'公历转农历模块
'原创:互联网
'修正:阿勇 2005/1/12

TA的精华主题

TA的得分主题

 楼主| 发表于 2013-1-24 16:15 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 时光鸟 于 2013-1-24 16:35 编辑
840205910 发表于 2013-1-24 16:09
'公历转农历模块
'原创:互联网
'修正:阿勇 2005/1/12

互联网是这个函数的作者?还是说摘自互联网?我搜了下,有个网页上的确有这个信息,我加上去。

TA的精华主题

TA的得分主题

发表于 2013-1-28 21:59 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
太强大了。{:soso_e179:}

TA的精华主题

TA的得分主题

发表于 2013-5-25 16:14 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
太强了,不董,但能用了,谢谢!

TA的精华主题

TA的得分主题

发表于 2013-5-25 17:39 | 显示全部楼层
农历转公历sGetDate这个函数该怎么用呢?要转换的农历格式是什么样的?

TA的精华主题

TA的得分主题

发表于 2013-5-25 17:59 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2013-5-25 20:10 | 显示全部楼层
这个公历转农历好用,但农历转公历如何运用呢?公式如何表达?

TA的精华主题

TA的得分主题

发表于 2013-6-16 13:07 | 显示全部楼层
经测试,里面的自定义函数GetYLDate有问题,如农历日期1955年十月初一,对应的公历日期应为1955-11-14,但这个自定义函数显示为1955-11-13,再如农历日期2013年五月初一,对应的公历日期应为2013-6-8,自定义函数显示为2013-6-9,不知能不能修正,实际上上面那两个日期所在的农历月份公农历都对不上

TA的精华主题

TA的得分主题

发表于 2013-11-13 20:55 | 显示全部楼层
农历转公历显示格式为2014年1月1日怎么改?现在是1204/1/1。
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-9-29 06:28 , Processed in 0.045874 second(s), 9 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表