高手请指教:输入两个日期,返回两个日期之间所有月份的最后一天等

suihen 2004-12-20 01:31:02
比如:

input:

dtpicker1.value=2004-1-3
dtpicker2.value=2004-4-9

返回时间:返回一个数组,数组元素的值如下,同时返回数组大小为5

2003-12-31(这是上个月的最后一天)
2004-1-31(这是输入第一个日期求出的该月的最后一天)
2004-2-29
2004-3-31
2004-4-9(注意这是输入的第二个时间参数)

请注意:要考虑跨年的问题。拜谢!!!!!

...全文
326 28 打赏 收藏 转发到动态 举报
写回复
用AI写文章
28 条回复
切换为时间正序
请发表友善的回复…
发表回复
viena 2004-12-21
  • 打赏
  • 举报
回复
惭愧,没看清题就在这儿瞎掺和,无地自容了~
只看了标题,没看内容,
误解了,我还以为是只要day呢,原来是要日期~
viena 2004-12-21
  • 打赏
  • 举报
回复
狼行天下的这句Erase x真的不错,还记得释放动态数组,高!
x(i) = DateSerial(Year(date1), Month(date1) + i, 0)
把改成
x(i) = DateSerial(Year(date1), Month(date1) + i, 1 - 1)好一些吧
韧恒 2004-12-21
  • 打赏
  • 举报
回复
没想到随便写的这一小段代码让两位争得如此激烈,大致看了看,的确,狼行天下的这句DateSerial(Year(date1), Month(date1) + i, 0)真的不错。
viena 2004-12-21
  • 打赏
  • 举报
回复
错误改过了,测试通过:
Dim countArr As Integer '目标的个数
Dim arrTarget() As Integer '目标数组
Sub getDay(date1 As Date, date2 As Date)
Dim arrDaysOfMonth(12) As Integer '数组,存放12个月的最后一天
arrDaysOfMonth(1) = 31
arrDaysOfMonth(2) = 28 '暂时的,如果不是,改为29
arrDaysOfMonth(3) = 31
arrDaysOfMonth(4) = 30
arrDaysOfMonth(5) = 31
arrDaysOfMonth(6) = 30
arrDaysOfMonth(7) = 31
arrDaysOfMonth(8) = 31
arrDaysOfMonth(9) = 30
arrDaysOfMonth(10) = 31
arrDaysOfMonth(11) = 30
arrDaysOfMonth(12) = 31

Dim month1 As Integer '第一个日期的月份
Dim month2 As Integer '第二个日期的月份
month1 = Month(date1)
month2 = Month(date2)

countArr = DateDiff("m", date1, date2) + 2

ReDim arrTarget(countArr - 1) As Integer

Dim tmpDate As Date
Dim tmpMonth As Integer
Dim TmpYear As Integer

'得到第一个日期上个月的最后一天
tmpMonth = month1 - 1
If tmpMonth = 0 Then tmpMonth = 12 '第一个日期上个月的月份
If tmpMonth = 2 Then
tmpDate = DateSerial(Year(date1), "2", "28")
If Month(tmpDate + 1) = 3 Then '下一天是三月,最后一天就是28
arrTarget(0) = 28
Else
arrTarget(0) = 29
End If
Else
arrTarget(0) = arrDaysOfMonth(tmpMonth) '查数组得到此月最后一天
End If

Dim i As Integer
For i = 1 To countArr - 2
tmpMonth = month1 - 1
If tmpMonth = 0 Then tmpMonth = 12 '第一个日期上个月的月份
tmpMonth = tmpMonth + i
TmpYear = -1
While tmpMonth > 12
tmpMonth = tmpMonth - 12
TmpYear = TmpYear + 1 '跨的年数
Wend

If tmpMonth = 2 Then
tmpDate = DateSerial(Year(date1) + TmpYear, "2", "28")
If Month(tmpDate + 1) = 3 Then '下一天是三月,最后一天就是28
arrTarget(i) = 28
Else
arrTarget(i) = 29
End If
Else
arrTarget(i) = arrDaysOfMonth(tmpMonth) '查数组得到此月最后一天
End If
Next
arrTarget(countArr - 1) = Day(date2)
End Sub

Private Sub Form_Load()
Call getDay(CDate("2003-1-3"), CDate("2005-4-9"))
Dim i As Integer
Debug.Print "9999999999999"
For i = 0 To countArr - 1
Debug.Print arrTarget(i)
Next
End Sub
1v1chen 2004-12-21
  • 打赏
  • 举报
回复
为什么这么复杂呢?
直接取下个月的一号再减去一天不就行了
xinliangyu 2004-12-21
  • 打赏
  • 举报
回复
投"northwolves(狼行天下)"一票。
另外我想说,楼上有几位在求2月有几天的问题时考虑有一点点不周到的:即能被4整除的年份不一定是润年,其2月当然就不一定是29天呐。须知“能被4整除的年份,如当其也能被100整除时,则也须被400整除才是润年”,如2100,2200、2300年都不是润年,2400年才是润年。
viena 2004-12-21
  • 打赏
  • 举报
回复
KAO,有一处错误,月份差没有考虑跨年的情况
countArr = month2 - month1 + 2
应该是
DateDiff("m", Date1, Date2) + 2

to gemaohui(gmh):
你不说效率吗?
/*我觉得songyaowu的代码已很明确地说明了任何月的最后一天都无需判断,VB就可以计算出来的,无论是大小月,还是闰年的二月*/
你这句话自相矛盾,既然无需判断,还计算什么?我说的判断就是你说的计算,我是直接从数组中查出来的,而songyaowu
tDate = DateAdd("m", 1, tDate)
d(j) = CDate(DateAdd("d", -1, DateSerial(Year(tDate), Month(tDate), "1")))
每次循环要进行6次函数调用,而我的只有2月,需要调用函数
你现在怎么不强调效率的问题了?
gemaohui 2004-12-21
  • 打赏
  • 举报
回复
To: gemaohui(gmh)小妹妹瞧瞧这个吧,循环数减到最少,而且函数调用很少,效率够高吧?

你真的是“实心木头人”?我觉得songyaowu的代码已很明确地说明了任何月的最后一天都无需判断,VB就可以计算出来的,无论是大小月,还是闰年的二月。因为DateAdd函数就可以计算的,你根本无需做这些事情。还定义了一长串的数组,我晕!你只需用当前月的第一天(因为任何月都有1号)减去一天就求得了上月的最后一天了,跨年的也是如此嘛。你又何必判断是否跨年?是否为闰年的二月呢?
更何况你修改后的这段代码还有问题呢!正象你说的,“循环次数减到最少”,至于少到什么程序呢?你将Call getDay(CDate("2004-1-3"), CDate("2004-4-9"))改为Call getDay(CDate("2003-1-3"), CDate("2004-1-9")), 也就是月份相同,年份不同,连一次循环都没发生。 哈....
northwolves 2004-12-20
  • 打赏
  • 举报
回复
Sub getall(ByVal date1 As Date, ByVal date2 As Date, Optional ByRef months As Integer, Optional ByRef out As String)
Dim x() As String, i As Integer
date1 = DateSerial(Year(date1), Month(date1), 0)
months = DateDiff("m", date1, date2) + 1
ReDim x(1 To months)
For i = 1 To months
x(i) = DateSerial(Year(date1), Month(date1) + i, 0)
Next
x(months) = date2
out = Join(x, vbCrLf)
Erase x
MsgBox out, vbOKOnly, months
End Sub

Private Sub Command1_Click()
getall #1/3/2003#, #4/9/2004#
End Sub
viena 2004-12-20
  • 打赏
  • 举报
回复
gemaohui(gmh)小妹妹瞧瞧这个吧,循环数减到最少,而且函数调用很少,效率够高吧?
viena 2004-12-20
  • 打赏
  • 举报
回复
★★★★★★★★★★★★★★★★★
只判断2月,其它从数组中取得,最高效
终结版:
Dim countArr As Integer '目标的个数
Dim arrTarget() As Integer '目标数组
Sub getDay(date1 As Date, date2 As Date)
Dim arrDaysOfMonth(12) As Integer '数组,存放12个月的最后一天
arrDaysOfMonth(1) = 31
arrDaysOfMonth(2) = 28 '暂时的,如果不是,改为29
arrDaysOfMonth(3) = 31
arrDaysOfMonth(4) = 30
arrDaysOfMonth(5) = 31
arrDaysOfMonth(6) = 30
arrDaysOfMonth(7) = 31
arrDaysOfMonth(8) = 31
arrDaysOfMonth(9) = 30
arrDaysOfMonth(10) = 31
arrDaysOfMonth(11) = 30
arrDaysOfMonth(12) = 31

Dim month1 As Integer '第一个日期的月份
Dim month2 As Integer '第二个日期的月份
month1 = Month(date1)
month2 = Month(date2)

countArr = month2 - month1 + 2

ReDim arrTarget(countArr - 1) As Integer

Dim tmpDate As Date
Dim tmpMonth As Integer
Dim TmpYear As Integer

'得到第一个日期上个月的最后一天
tmpMonth = month1 - 1
If tmpMonth = 0 Then tmpMonth = 12 '第一个日期上个月的月份
If tmpMonth = 2 Then
tmpDate = DateSerial(Year(date1), "2", "28")
If Month(tmpDate + 1) = 3 Then '下一天是三月,最后一天就是28
arrTarget(0) = 28
Else
arrTarget(0) = 29
End If
Else
arrTarget(0) = arrDaysOfMonth(tmpMonth) '查数组得到此月最后一天
End If

Dim i As Integer
For i = 1 To countArr - 2
tmpMonth = month1 - 1 + i
While tmpMonth > 12
tmpMonth = tmpMonth - 12
TmpYear = TmpYear + 1 '跨的年数
Wend

If tmpMonth = 2 Then
tmpDate = DateSerial(Year(date1) + TmpYear, "2", "28")
If Month(tmpDate + 1) = 3 Then '下一天是三月,最后一天就是28
arrTarget(i) = 28
Else
arrTarget(i) = 29
End If
Else
arrTarget(i) = arrDaysOfMonth(tmpMonth) '查数组得到此月最后一天
End If
Next
arrTarget(countArr - 1) = Day(date2)
End Sub

Private Sub Form_Load()
Call getDay(CDate("2004-1-3"), CDate("2004-4-9"))
Dim i As Integer
For i = 0 To countArr - 1
Debug.Print arrTarget(i)
Next
End Sub
dongge2000 2004-12-20
  • 打赏
  • 举报
回复
把NextMonth函数换成tDate = DateAdd("m", 1, tDate)就简单多了,自己写下也算多一分了解。
viena 2004-12-20
  • 打赏
  • 举报
回复
其实只有二月需要判断,其他月都可以直接得到,
这样做是有点蠢,
傻瓜式的程序,没有什么技巧,偶的智商比较低啊
viena 2004-12-20
  • 打赏
  • 举报
回复
是啊,第一个月没有上个月的最后一天作为参照,只能每次加1找到

我觉得用VB最重要的是开发效率,多花很多时间来得到微小的性能改善没有多大实际意义
韧恒 2004-12-20
  • 打赏
  • 举报
回复
是啊,那个小妹妹可能没太看懂,不过楼上的虽然没有循环所有天数,但加28的位置可能不对,因为这个循环还是执行了35次。好象是第一个月的有问题吧。
共同探讨,共同学习。
viena 2004-12-20
  • 打赏
  • 举报
回复
楼上,偶的不是循环所有天数啊,如果找到最后一天下一个就跳到28日了,偶的是最易懂的吧
gemaohui 2004-12-20
  • 打赏
  • 举报
回复
小妹写不出这些代码来,但斗胆说下自己的看法。感觉还是songyaowu的代码比较好,值得学习,易懂且有效率。
viena(维也纳nn-实心木头人石欠歹匕RUKYO) 的代码效率太差了,如果输入2000-1-1至2004-1-1那么getday中的那个While thisDay <= date2循环要循环所有的天数,而songyaowu的只循环所有的月数而已。

而 dongge2000(秋日私语:非[版务].灌!) 就不用说了,他自己都觉得复杂了,且Split(CStr(MyDate), "-")这句限定了日期的间隔符,要知道这与系统的区域设置有关。不好。


小妹直言,多有得罪!
dongge2000 2004-12-20
  • 打赏
  • 举报
回复
楼上的高!
viena 2004-12-20
  • 打赏
  • 举报
回复
我觉得用集合Collection比较方便

忘记Set dayCol = Nothing,呵呵
viena 2004-12-20
  • 打赏
  • 举报
回复
'一个COMMAND控件
'输入直接用字符串常数强制转换为日期型
Option Explicit
Dim dayCol As Collection '用集合来存放所有最后一天
Sub getday(ByVal date1 As Date, ByVal date2 As Date)
Dim thisDay As Date, nextDay As Date
thisDay = date1
While thisDay <= date2
nextDay = thisDay + 1
If Month(nextDay) <> Month(thisDay) Then '月份与前一天不等,月的最后一天
dayCol.Add thisDay '添加到集合
thisDay = thisDay + 28 '一个月的前27天肯定不是,直接到28
Else
thisDay = nextDay
End If
Wend
End Sub

Private Sub Command1_Click()
Dim i As Integer
Set dayCol = New Collection
Call getday(CDate("2004-1-3"), CDate("2004-4-9"))
For i = 1 To dayCol.Count
Debug.Print dayCol.Item(i)
Next
End Sub
加载更多回复(8)

7,763

社区成员

发帖
与我相关
我的任务
社区描述
VB 基础类
社区管理员
  • VB基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧