编写VBA函数以查找期间编号。第一周持续13期

时间:2018-12-07 22:04:14

标签: excel vba excel-vba

概述:我基本上想编写一个MONTH函数的版本,以在13个工作年的时间内工作...

(免责声明:我是VBA的新手)将日期/月/日的日期重新格式化为周期号(1-13)和星期号(1-4)的最佳方法是什么?我已经使用WEEKNUM函数来解决这个问题,但是我似乎不太明白。我认为问题在于新年的开始(时段1,第1周)在18/30/18,在excel中,根据其衡量方式,该日期被视为第5周甚至第6周。

每周从星期日开始,一年中的每个时期(13)都有4周。到目前为止,我已经尝试过:

  • 这是一个自写函数的基本部分,它仅使周数部分起作用,并且只给我#value,但msgbox中没有错误(如果它起作用了,我也许可以找出休息):

     Function PeriodNum(serial_num As Date, number_periods As Integer, start_date As Date)
    
    Dim first_week As Integer
    Dim second_week As Integer
    Dim third_week As Integer
    Dim fourth_week As Integer
    Dim day As Integer
    
    first_week = 1
    second_week = 2
    third_week = 3
    fourth_week = 4
    day = serial_num
    
    If day >= start_date Or day <= start_date + 7 Then
    Selection.Value = first_week
        ElseIf day > start_date + 7 Or day <= start_date + 14 Then
            Selection.Value = second_week
        ElseIf day > start_date + 14 Or day <= start_date + 21 Then
            Selection.Value = third_week
        ElseIf day > start_date + 21 Or day <= start_date + 28 Then
            Selection.Value = fourth_week
        Else
        Selection.Value = "error"
    End If
    
    End Function
    

-我也尝试过使用WEEKNUM函数,但是我不知道如何获取每个透视图周期的1-4号

非常感谢您的帮助!非常感谢

3 个答案:

答案 0 :(得分:1)

1)根据VBA的代码规则,存在一个问题:

对每个 函数PeriodNum(serial_num作为日期,number_periods作为整数,start_date作为日期) 定义,您还应该使用row:

PeriodNum = ...

通过这种方式,您正在从函数中返回一个值(类似于return x;在其他语言中)

2)使用Selection对象是不可预测的,并且可以在调用方法时更改您在Excel中处于活动状态的任何单元格。如果要使用计算方法,则应使用类似的方法:

Function weekCompute(date1)
    '...
    weekCompute = "val1"
End Function

使用此功能,您可以使用以下单元格公式: = weekCompute(A1)

答案 1 :(得分:0)

您可以计算周数:

LngPeriod = int((day - start_date +1)/7)
If lngPeriod >4 then
     PeriodNum = “error”
Else
    PeriodNum = lngPeriod
End if

PeriodNum函数返回建议的变体。

答案 2 :(得分:0)

在Excel中,无论是内置函数(即SUM,COUNT)还是用户定义的函数(如PeriodNum),通常都会向其输入的单元格返回一个值。它们不会修改工作簿对象,例如{{ 1}}是的成员。过程Selection修改对象,但没有返回值。

@VitezslavSimon在其答案中提到,您需要在代码中的某个位置-SubPeriodNum = 1中给函数名称分配一个值。

将返回类型显式添加到函数中也是一个好主意。在您的情况下,如果您不对返回值进行任何算术计算,则可以使用PeriodNum ="error";如果您想在进一步的计算中使用返回值,则可以使用String。您的函数定义将为:

Variant

函数错误的迭代方法

我将您的代码复制到标准VBA模块中,并在行Function PeriodNum(serial_num As Date, number_periods As Integer, start_date As Date) As Variant 上放置了一个断点,以便在将其输入单元格后可以逐步执行该功能。为了对其进行测试,我将您的first_week = 1放在单元格C2中,并将start_date放在C3中。我通过在D3中输入serial_num来调用该函数。

单步执行代码时,行=PeriodNum(C3,13,$C$2)导致函数结束并在D3中返回day = serial_num错误。

#VALUE!是由UDF返回的唯一出错的错误。您不会在UDF中获得大量的运行时错误,因此调查的唯一方法是单步执行代码并查看错误原因。

我测试的日期是18/30/18,序列号为43464。您定义的#VALUE!必须在-32,768到32,767之间。因此潜在的错误是day As Integer,因为43464在Overflow的允许值之外。

第二名。迭代

Integer更改为Integer可以解决该错误,但是

Long

对于If day >= start_date Or day <= start_date + 7 Then PeriodNum = first_week > = serial_num总是返回1或对于start_date <"error"返回serial_num。测试的第二部分start_date并不重要,因为如果是Or day <= start_date + 7,则另一个测试是FALSE。我通过将日期扩展到C381并将其延续到2020年来进行了测试。因此,请回到图纸板上!

第三次迭代

将所有TRUE更改为Or可以确保第二部分得到评估。

And

在Excel中,我注意到1/6/19(应该是期间2的第一天)显示为1。因此测试有问题。将If day >= start_date And day <= start_date + 7 Then PeriodNum = first_week ElseIf day > start_date + 7 And day <= start_date + 14 Then PeriodNum = second_week ElseIf day > start_date + 14 And day <= start_date + 21 Then PeriodNum = third_week ElseIf day > start_date + 21 And day <= start_date + 28 Then PeriodNum = fourth_week Else PeriodNum = "error" End If 更改为day <= start_date + 7应该可以解决,但返回day < start_date + 7。这是因为后续测试不允许使用"error"

第四名。迭代

day = start_date + 7

返回Excel,在向下滚动之前看起来不错。 19/1/27,下面的所有内容均返回 If day >= start_date And day < start_date + 7 Then PeriodNum = first_week ElseIf day >= start_date + 7 And day < start_date + 14 Then PeriodNum = second_week ElseIf day >= start_date + 14 And day < start_date + 21 Then PeriodNum = third_week ElseIf day >= start_date + 21 And day < start_date + 28 Then PeriodNum = fourth_week Else PeriodNum = "error" End If "error"显然不能超过day

第五名。迭代start_date + 28更改为day = serial_num,然后进行测试以查看与0、7、14、21和28相关的数字。

day = (serial_num - start_date) Mod 28

返回Excel,一切看起来都很好。

最终迭代-完善

仍有一些改进:

  • day = (serial_num - start_date) Mod 28 If day >= 0 And day < 7 Then PeriodNum = first_week ElseIf day >= 7 And day < 14 Then PeriodNum = second_week ElseIf day >= 14 And day < 21 Then PeriodNum = third_week ElseIf day >= 21 And day < 28 Then PeriodNum = fourth_week Else PeriodNum = "error" End If 未使用,因此将其删除
  • 函数number_periods As Integer WeekInPeriod`
  • 将保留字或VBA函数用作变量名不是一个好习惯--
  • PeriodNum name is deceptive. It isn't returning a period but a week in a period so是VBA函数(返回月份中的日期)。我将其更改为day。描述性的变量名称使用户更容易解析。
  • 我也将DayInPeriod28更改为serial_num
  • MyDate比嵌套的Ifs更紧凑。
  • 不要声明和定义只使用一次的变量。这是浪费时间和空间。

    Select Case