Skip to content

Commit b91cc9a

Browse files
committed
#30 - Weekday parser.
1 parent bdf5a0c commit b91cc9a

File tree

5 files changed

+197
-0
lines changed

5 files changed

+197
-0
lines changed

src/ReportViewer.NET/Extensions/DateTimeExtensions.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,14 @@ public static int ParseDatePartShortString(this DateTime dtt, string dateInterva
208208
return 0;
209209
}
210210

211+
public static int ParseWeekday(this DateTime dtt, FirstDayOfWeek fdow)
212+
{
213+
var currentDayOfWeek = (int)AdjustedDayOfWeek(dtt, fdow);
214+
215+
// TODO: Does SSRS increment by 1 to get a sane week number?
216+
return currentDayOfWeek + 1;
217+
}
218+
211219
public static string FormatDateTime(this DateTime dtt, DateFormat format)
212220
{
213221
switch (format)
@@ -266,5 +274,29 @@ private static CalendarWeekRule FirstWeekOfYearToCalendarWeekRule(FirstWeekOfYea
266274
return cultureInfo.DateTimeFormat.CalendarWeekRule;
267275
}
268276
}
277+
278+
private static int AdjustedDayOfWeek(DateTime dtt, FirstDayOfWeek fdow)
279+
{
280+
CultureInfo cultureInfo = CultureInfo.CurrentCulture;
281+
Calendar calendar = cultureInfo.Calendar;
282+
283+
switch (fdow)
284+
{
285+
case FirstDayOfWeek.Monday:
286+
return ((int)calendar.GetDayOfWeek(dtt) + 6) % 7;
287+
case FirstDayOfWeek.Tuesday:
288+
return ((int)calendar.GetDayOfWeek(dtt) + 5) % 7;
289+
case FirstDayOfWeek.Wednesday:
290+
return ((int)calendar.GetDayOfWeek(dtt) + 4) % 7;
291+
case FirstDayOfWeek.Thursday:
292+
return ((int)calendar.GetDayOfWeek(dtt) + 3) % 7;
293+
case FirstDayOfWeek.Friday:
294+
return ((int)calendar.GetDayOfWeek(dtt) + 2) % 7;
295+
case FirstDayOfWeek.Saturday:
296+
return ((int)calendar.GetDayOfWeek(dtt) + 1) % 7;
297+
default:
298+
return (int)calendar.GetDayOfWeek(dtt);
299+
}
300+
}
269301
}
270302
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
using Microsoft.VisualBasic;
2+
using ReportViewer.NET.DataObjects;
3+
using ReportViewer.NET.Extensions;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Text.RegularExpressions;
7+
8+
namespace ReportViewer.NET.Parsers.DateAndTime
9+
{
10+
public class WeekdayParser : BaseParser
11+
{
12+
public static Regex WeekdayRegex = RegexCommon.GenerateMultiParamParserRegex("Weekday");
13+
14+
public WeekdayParser(
15+
string currentString,
16+
ExpressionFieldOperator op,
17+
ReportExpression currentExpression,
18+
IEnumerable<IDictionary<string, object>> dataSetResults,
19+
IDictionary<string, object> values,
20+
int currentRowNumber,
21+
IEnumerable<DataSet> dataSets,
22+
DataSet activeDataset,
23+
ReportRDL report
24+
) : base(currentString, op, currentExpression, dataSetResults, values, currentRowNumber, dataSets, activeDataset, WeekdayRegex, report)
25+
{
26+
}
27+
28+
public override (Type, object) ExtractExpressionValue(string fieldName, string dataSetName)
29+
{
30+
throw new NotImplementedException();
31+
}
32+
33+
public override void Parse()
34+
{
35+
var match = WeekdayRegex.Match(this.CurrentString);
36+
var matchValue = match.Value;
37+
38+
// Remove the surrounding Weekday including open & close brace so we can inspect inner members and see if they too contain program flow expressions.
39+
matchValue = matchValue.MatchValueSubString(8);
40+
41+
var foundParameters = this.ParseParenthesis(matchValue);
42+
43+
if (foundParameters.Item2.Count < 1 || foundParameters.Item2.Count > 2)
44+
{
45+
// The Weekday function expects at least 1 parameter but no more than 2.
46+
return;
47+
}
48+
49+
// DateTime will either come directly from database or will be calculated from other expression.
50+
var date = this.Report.Parser.ParseReportExpressionString(
51+
foundParameters.Item2[0],
52+
this.DataSetResults,
53+
this.Values,
54+
this.CurrentRowNumber,
55+
this.DataSets,
56+
this.ActiveDataset,
57+
null
58+
).ExpressionAsDateTime();
59+
60+
FirstDayOfWeek fdow = FirstDayOfWeek.System;
61+
62+
if (foundParameters.Item2.Count > 1)
63+
{
64+
var fdowString = foundParameters.Item2[1].Trim();
65+
66+
if (int.TryParse(fdowString, out var fdowInt))
67+
{
68+
fdow = (FirstDayOfWeek)fdowInt;
69+
}
70+
else
71+
{
72+
fdow = (FirstDayOfWeek)Enum.Parse(typeof(FirstDayOfWeek), fdowString.Substring(15, fdowString.Length - 15));
73+
}
74+
}
75+
76+
this.CurrentExpression.Index = match.Index;
77+
this.CurrentExpression.ResolvedType = typeof(int);
78+
this.CurrentExpression.Value = date.ParseWeekday(fdow);
79+
}
80+
}
81+
}

src/ReportViewer.NET/Parsers/ExpressionFieldOperator.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ public enum ExpressionFieldOperator
7070
TimeString,
7171
TimeValue,
7272
Today,
73+
Weekday,
7374
FormatCurrency,
7475
RowNumber
7576
}

src/ReportViewer.NET/Parsers/ExpressionParser.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,7 @@ ref string proposedString
516516
}
517517

518518
if (DayParser.DayRegex.IsMatch(currentString) &&
519+
((WeekdayParser.WeekdayRegex.IsMatch(currentString) && DayParser.DayRegex.Match(currentString).Index < WeekdayParser.WeekdayRegex.Match(currentString).Index) || !WeekdayParser.WeekdayRegex.IsMatch(currentString)) &&
519520
(currentExpression.Operator == ExpressionFieldOperator.None || DayParser.DayRegex.Match(currentString).Index < currentExpression.Index)
520521
)
521522
{
@@ -640,6 +641,15 @@ ref string proposedString
640641
todayParser.Parse();
641642
proposedString = todayParser.GetProposedString();
642643
}
644+
645+
if (WeekdayParser.WeekdayRegex.IsMatch(currentString) &&
646+
(currentExpression.Operator == ExpressionFieldOperator.None || WeekdayParser.WeekdayRegex.Match(currentString).Index < currentExpression.Index)
647+
)
648+
{
649+
var weekdayParser = new WeekdayParser(currentString, ExpressionFieldOperator.Weekday, currentExpression, dataSetResults, values, currentRowNumber, dataSets, activeDataset, _report);
650+
weekdayParser.Parse();
651+
proposedString = weekdayParser.GetProposedString();
652+
}
643653
}
644654

645655
private void SearchMathFunctions()
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2+
using ReportViewer.NET.DataObjects;
3+
using ReportViewer.NET.Extensions;
4+
using ReportViewer.NET.Parsers;
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Linq;
8+
using System.Text;
9+
using System.Threading.Tasks;
10+
11+
namespace ReportViewer.NET.Tests.Parsers.DateAndTime
12+
{
13+
[TestClass]
14+
public class WeekdayParserTests
15+
{
16+
private ExpressionParser _expressionParser;
17+
private ReportRDL _report;
18+
19+
public WeekdayParserTests()
20+
{
21+
var report = TestHelper.PrimeReport();
22+
23+
_report = report;
24+
_expressionParser = new ExpressionParser(report);
25+
}
26+
27+
[TestMethod]
28+
public void Weekday_Returns_Integer()
29+
{
30+
// System defaults first day to Sunday, January 15 2010 is a Friday so this will be 6.
31+
32+
// Arrange
33+
var expr = "=Weekday(\"January 15, 2010 14:15:30\")";
34+
35+
// Act
36+
var result = _expressionParser.ParseReportExpressionString(
37+
expr,
38+
null,
39+
null,
40+
1,
41+
_report.DataSets,
42+
null,
43+
null
44+
).ExpressionAsInt();
45+
46+
// Assert
47+
Assert.AreEqual(6, result);
48+
}
49+
50+
[TestMethod]
51+
public void Weekday_Returns_Integer_First_Day_Tuesday()
52+
{
53+
// January 15 2010 is a Friday. Setting first day to Tuesday will make this 4.
54+
55+
// Arrange
56+
var expr = "=Weekday(\"January 15, 2010 14:15:30\", FirstDayOfWeek.Tuesday)";
57+
58+
// Act
59+
var result = _expressionParser.ParseReportExpressionString(
60+
expr,
61+
null,
62+
null,
63+
1,
64+
_report.DataSets,
65+
null,
66+
null
67+
).ExpressionAsInt();
68+
69+
// Assert
70+
Assert.AreEqual(4, result);
71+
}
72+
}
73+
}

0 commit comments

Comments
 (0)