Skip to content

Commit ea10b42

Browse files
committed
#31 - WeekdayName parser.
1 parent beaab05 commit ea10b42

File tree

6 files changed

+257
-1
lines changed

6 files changed

+257
-1
lines changed

readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ https://github.com/Apress/beg-sql-server-reporting-services/blob/master/Beginnin
301301
| Date & Time | TimeValue | Complete | |
302302
| Date & Time | Today | Complete | |
303303
| Date & Time | Weekday | Complete | |
304-
| Date & Time | WeekdayName | Not started | |
304+
| Date & Time | WeekdayName | Complete | |
305305
| Date & Time | Year | Not started | |
306306

307307
### Math

src/ReportViewer.NET/Extensions/DateTimeExtensions.cs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,11 @@ public static int ParseWeekday(this DateTime dtt, FirstDayOfWeek fdow)
216216
return currentDayOfWeek + 1;
217217
}
218218

219+
public static string ParseWeekdayName(this DateTime dtt, FirstDayOfWeek fdow, bool abbreviate)
220+
{
221+
return !abbreviate ? AdjustedWeekdayName(dtt, fdow) : AdjustedWeekdayNameAbbreviated(dtt, fdow);
222+
}
223+
219224
public static string FormatDateTime(this DateTime dtt, DateFormat format)
220225
{
221226
switch (format)
@@ -298,5 +303,66 @@ private static int AdjustedDayOfWeek(DateTime dtt, FirstDayOfWeek fdow)
298303
return (int)calendar.GetDayOfWeek(dtt);
299304
}
300305
}
306+
307+
private static string AdjustedWeekdayName(DateTime dtt, FirstDayOfWeek fdow)
308+
{
309+
CultureInfo cultureInfo = CultureInfo.CurrentCulture;
310+
Calendar calendar = cultureInfo.Calendar;
311+
312+
// Using typeof(DayOfWeek) as this is the enum type returned by GetDayOfWeek.
313+
314+
switch (fdow)
315+
{
316+
case FirstDayOfWeek.Monday:
317+
return Enum.GetName(typeof(DayOfWeek), AdjustWeekdayBounds((int)calendar.GetDayOfWeek(dtt) + 1));
318+
case FirstDayOfWeek.Tuesday:
319+
return Enum.GetName(typeof(DayOfWeek), AdjustWeekdayBounds((int)calendar.GetDayOfWeek(dtt) + 2));
320+
case FirstDayOfWeek.Wednesday:
321+
return Enum.GetName(typeof(DayOfWeek), AdjustWeekdayBounds((int)calendar.GetDayOfWeek(dtt) + 3));
322+
case FirstDayOfWeek.Thursday:
323+
return Enum.GetName(typeof(DayOfWeek), AdjustWeekdayBounds((int)calendar.GetDayOfWeek(dtt) + 4));
324+
case FirstDayOfWeek.Friday:
325+
return Enum.GetName(typeof(DayOfWeek), AdjustWeekdayBounds((int)calendar.GetDayOfWeek(dtt) + 5));
326+
case FirstDayOfWeek.Saturday:
327+
return Enum.GetName(typeof(DayOfWeek), AdjustWeekdayBounds((int)calendar.GetDayOfWeek(dtt) + 6));
328+
default:
329+
return Enum.GetName(typeof(DayOfWeek), (int)calendar.GetDayOfWeek(dtt));
330+
}
331+
}
332+
333+
private static int AdjustWeekdayBounds(int dayOfWeek)
334+
{
335+
if (dayOfWeek > 6)
336+
{
337+
return dayOfWeek -= 7;
338+
}
339+
340+
return dayOfWeek;
341+
}
342+
343+
private static string AdjustedWeekdayNameAbbreviated(DateTime dtt, FirstDayOfWeek fdow)
344+
{
345+
var weekdayName = AdjustedWeekdayName(dtt, fdow);
346+
347+
switch (weekdayName)
348+
{
349+
case "Sunday":
350+
return "Sun";
351+
case "Monday":
352+
return "Mon";
353+
case "Tuesday":
354+
return "Tue";
355+
case "Wednesday":
356+
return "Wed";
357+
case "Thursday":
358+
return "Thu";
359+
case "Friday":
360+
return "Fri";
361+
case "Saturday":
362+
return "Sat";
363+
}
364+
365+
return string.Empty;
366+
}
301367
}
302368
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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 WeekdayNameParser : BaseParser
11+
{
12+
public static Regex WeekdayNameRegex = RegexCommon.GenerateMultiParamParserRegex("WeekdayName");
13+
14+
public WeekdayNameParser(
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, WeekdayNameRegex, 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 = WeekdayNameRegex.Match(this.CurrentString);
36+
var matchValue = match.Value;
37+
38+
// Remove the surrounding WeekdayName including open & close brace so we can inspect inner members and see if they too contain program flow expressions.
39+
matchValue = matchValue.MatchValueSubString(12);
40+
41+
var foundParameters = this.ParseParenthesis(matchValue);
42+
43+
if (foundParameters.Item2.Count < 1 || foundParameters.Item2.Count > 3)
44+
{
45+
// The Weekday function expects at least 1 parameter but no more than 3.
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 == 3)
63+
{
64+
var fdowString = foundParameters.Item2[2].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(string);
78+
79+
if (foundParameters.Item2.Count == 1 || foundParameters.Item2[1].Trim().EqualsIgnore("false"))
80+
{
81+
this.CurrentExpression.Value = date.ParseWeekdayName(fdow, false);
82+
}
83+
else
84+
{
85+
this.CurrentExpression.Value = date.ParseWeekdayName(fdow, true);
86+
}
87+
}
88+
}
89+
}

src/ReportViewer.NET/Parsers/ExpressionFieldOperator.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ public enum ExpressionFieldOperator
7171
TimeValue,
7272
Today,
7373
Weekday,
74+
WeekdayName,
7475
FormatCurrency,
7576
RowNumber
7677
}

src/ReportViewer.NET/Parsers/ExpressionParser.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,15 @@ ref string proposedString
650650
weekdayParser.Parse();
651651
proposedString = weekdayParser.GetProposedString();
652652
}
653+
654+
if (WeekdayNameParser.WeekdayNameRegex.IsMatch(currentString) &&
655+
(currentExpression.Operator == ExpressionFieldOperator.None || WeekdayNameParser.WeekdayNameRegex.Match(currentString).Index < currentExpression.Index)
656+
)
657+
{
658+
var weekdayNameParser = new WeekdayNameParser(currentString, ExpressionFieldOperator.WeekdayName, currentExpression, dataSetResults, values, currentRowNumber, dataSets, activeDataset, _report);
659+
weekdayNameParser.Parse();
660+
proposedString = weekdayNameParser.GetProposedString();
661+
}
653662
}
654663

655664
private void SearchMathFunctions()
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2+
using ReportViewer.NET.DataObjects;
3+
using ReportViewer.NET.Extensions;
4+
using ReportViewer.NET.Parsers;
5+
6+
namespace ReportViewer.NET.Tests.Parsers.DateAndTime
7+
{
8+
[TestClass]
9+
public class WeekdayNameParserTests
10+
{
11+
private ExpressionParser _expressionParser;
12+
private ReportRDL _report;
13+
14+
public WeekdayNameParserTests()
15+
{
16+
var report = TestHelper.PrimeReport();
17+
18+
_report = report;
19+
_expressionParser = new ExpressionParser(report);
20+
}
21+
22+
[TestMethod]
23+
public void WeekdayName_Returns_String()
24+
{
25+
// System defaults first day to Sunday, January 15 2010 is a Friday so we expect Friday to be returned.
26+
27+
// Arrange
28+
var expr = "=WeekdayName(\"January 15, 2010 14:15:30\")";
29+
30+
// Act
31+
var result = _expressionParser.ParseReportExpressionString(
32+
expr,
33+
null,
34+
null,
35+
1,
36+
_report.DataSets,
37+
null,
38+
null
39+
).ExpressionAsString();
40+
41+
// Assert
42+
Assert.AreEqual("Friday", result);
43+
}
44+
45+
[TestMethod]
46+
public void WeekdayName_Returns_String_First_Day_Tuesday()
47+
{
48+
// January 15 2010 is a Friday. Setting first day to Tuesday will make this return Sunday as there are 2 days between system default and Tuesday.
49+
50+
// Arrange
51+
var expr = "=WeekdayName(\"January 15, 2010 14:15:30\", False, FirstDayOfWeek.Tuesday)";
52+
53+
// Act
54+
var result = _expressionParser.ParseReportExpressionString(
55+
expr,
56+
null,
57+
null,
58+
1,
59+
_report.DataSets,
60+
null,
61+
null
62+
).ExpressionAsString();
63+
64+
// Assert
65+
Assert.AreEqual("Sunday", result);
66+
}
67+
68+
[TestMethod]
69+
public void WeekdayName_Returns_String_First_Day_Tuesday_Abbreviated()
70+
{
71+
// January 15 2010 is a Friday. Setting first day to Tuesday will make this return Sunday as there are 2 days between system default and Tuesday.
72+
73+
// Arrange
74+
var expr = "=WeekdayName(\"January 15, 2010 14:15:30\", True, FirstDayOfWeek.Tuesday)";
75+
76+
// Act
77+
var result = _expressionParser.ParseReportExpressionString(
78+
expr,
79+
null,
80+
null,
81+
1,
82+
_report.DataSets,
83+
null,
84+
null
85+
).ExpressionAsString();
86+
87+
// Assert
88+
Assert.AreEqual("Sun", result);
89+
}
90+
}
91+
}

0 commit comments

Comments
 (0)