Skip to content

Commit 964af19

Browse files
committed
ref qax-os#65: new formula function WEEKNUM
1 parent a0396ed commit 964af19

File tree

2 files changed

+101
-0
lines changed

2 files changed

+101
-0
lines changed

calc.go

+81
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,7 @@ type formulaFuncs struct {
719719
// VDB
720720
// VLOOKUP
721721
// WEEKDAY
722+
// WEEKNUM
722723
// WEIBULL
723724
// WEIBULL.DIST
724725
// XIRR
@@ -12803,6 +12804,86 @@ func (fn *formulaFuncs) WEEKDAY(argsList *list.List) formulaArg {
1280312804
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
1280412805
}
1280512806

12807+
// weeknum is an implementation of the formula function WEEKNUM.
12808+
func (fn *formulaFuncs) weeknum(snTime time.Time, returnType int) formulaArg {
12809+
days := snTime.YearDay()
12810+
weekMod, weekNum := days%7, math.Ceil(float64(days)/7)
12811+
if weekMod == 0 {
12812+
weekMod = 7
12813+
}
12814+
year := snTime.Year()
12815+
firstWeekday := int(time.Date(year, time.January, 1, 0, 0, 0, 0, time.UTC).Weekday())
12816+
var offset int
12817+
switch returnType {
12818+
case 1, 17:
12819+
offset = 0
12820+
case 2, 11, 21:
12821+
offset = 1
12822+
case 12, 13, 14, 15, 16:
12823+
offset = returnType - 10
12824+
default:
12825+
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
12826+
}
12827+
padding := offset + 7 - firstWeekday
12828+
if padding > 7 {
12829+
padding -= 7
12830+
}
12831+
if weekMod > padding {
12832+
weekNum++
12833+
}
12834+
if returnType == 21 && (firstWeekday == 0 || firstWeekday > 4) {
12835+
if weekNum--; weekNum < 1 {
12836+
if weekNum = 52; int(time.Date(year-1, time.January, 1, 0, 0, 0, 0, time.UTC).Weekday()) < 4 {
12837+
weekNum++
12838+
}
12839+
}
12840+
}
12841+
return newNumberFormulaArg(weekNum)
12842+
}
12843+
12844+
// WEEKNUM function returns an integer representing the week number (from 1 to
12845+
// 53) of the year. The syntax of the function is:
12846+
//
12847+
// WEEKNUM(serial_number,[return_type])
12848+
//
12849+
func (fn *formulaFuncs) WEEKNUM(argsList *list.List) formulaArg {
12850+
if argsList.Len() < 1 {
12851+
return newErrorFormulaArg(formulaErrorVALUE, "WEEKNUM requires at least 1 argument")
12852+
}
12853+
if argsList.Len() > 2 {
12854+
return newErrorFormulaArg(formulaErrorVALUE, "WEEKNUM allows at most 2 arguments")
12855+
}
12856+
sn := argsList.Front().Value.(formulaArg)
12857+
num, returnType := sn.ToNumber(), 1
12858+
var snTime time.Time
12859+
if num.Type != ArgNumber {
12860+
dateString := strings.ToLower(sn.Value())
12861+
if !isDateOnlyFmt(dateString) {
12862+
if _, _, _, _, _, err := strToTime(dateString); err.Type == ArgError {
12863+
return err
12864+
}
12865+
}
12866+
y, m, d, _, err := strToDate(dateString)
12867+
if err.Type == ArgError {
12868+
return err
12869+
}
12870+
snTime = time.Date(y, time.Month(m), d, 0, 0, 0, 0, time.Now().Location())
12871+
} else {
12872+
if num.Number < 0 {
12873+
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
12874+
}
12875+
snTime = timeFromExcelTime(num.Number, false)
12876+
}
12877+
if argsList.Len() == 2 {
12878+
returnTypeArg := argsList.Back().Value.(formulaArg).ToNumber()
12879+
if returnTypeArg.Type != ArgNumber {
12880+
return returnTypeArg
12881+
}
12882+
returnType = int(returnTypeArg.Number)
12883+
}
12884+
return fn.weeknum(snTime, returnType)
12885+
}
12886+
1280612887
// Text Functions
1280712888

1280812889
// CHAR function returns the character relating to a supplied character set

calc_test.go

+20
Original file line numberDiff line numberDiff line change
@@ -1560,6 +1560,18 @@ func TestCalcCellValue(t *testing.T) {
15601560
"=WEEKDAY(\"12/25/2012\",15)": "5",
15611561
"=WEEKDAY(\"12/25/2012\",16)": "4",
15621562
"=WEEKDAY(\"12/25/2012\",17)": "3",
1563+
// WEEKNUM
1564+
"=WEEKNUM(\"01/01/2011\")": "1",
1565+
"=WEEKNUM(\"01/03/2011\")": "2",
1566+
"=WEEKNUM(\"01/13/2008\")": "3",
1567+
"=WEEKNUM(\"01/21/2008\")": "4",
1568+
"=WEEKNUM(\"01/30/2008\")": "5",
1569+
"=WEEKNUM(\"02/04/2008\")": "6",
1570+
"=WEEKNUM(\"01/02/2017\",2)": "2",
1571+
"=WEEKNUM(\"01/02/2017\",12)": "1",
1572+
"=WEEKNUM(\"12/31/2017\",21)": "52",
1573+
"=WEEKNUM(\"01/01/2017\",21)": "52",
1574+
"=WEEKNUM(\"01/01/2021\",21)": "53",
15631575
// Text Functions
15641576
// CHAR
15651577
"=CHAR(65)": "A",
@@ -3484,6 +3496,14 @@ func TestCalcCellValue(t *testing.T) {
34843496
"=WEEKDAY(0,0)": "#VALUE!",
34853497
"=WEEKDAY(\"January 25, 100\")": "#VALUE!",
34863498
"=WEEKDAY(-1,1)": "#NUM!",
3499+
// WEEKNUM
3500+
"=WEEKNUM()": "WEEKNUM requires at least 1 argument",
3501+
"=WEEKNUM(0,1,0)": "WEEKNUM allows at most 2 arguments",
3502+
"=WEEKNUM(0,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
3503+
"=WEEKNUM(\"\",1)": "#VALUE!",
3504+
"=WEEKNUM(\"January 25, 100\")": "#VALUE!",
3505+
"=WEEKNUM(0,0)": "#NUM!",
3506+
"=WEEKNUM(-1,1)": "#NUM!",
34873507
// Text Functions
34883508
// CHAR
34893509
"=CHAR()": "CHAR requires 1 argument",

0 commit comments

Comments
 (0)