Expression.Error: A cyclic reference was encountered during evaluation. - using custom function NetWorkDays in Power Query - function

I have created a custom function from a blank query to calculate the number of days excluding holidays and the weekends, the function is below
Query1 = (StartDate as date, EndDate as date) as number =>
let
DateList = List.Dates(StartDate, Number.From(EndDate - StartDate) , #duration(1, 0, 0, 0)),
RemoveWeekends = List.Select(DateList, each Date.DayOfWeek(_, Day.Monday) < 5),
RemoveHolidays = List.RemoveItems(RemoveWeekends, Holidays),
CountDays = List.Count(RemoveHolidays)
in
CountDays,
Custom1 = Query1
in
Custom1
Everything is working in the file on my computer, but the issue is when anyone else from my team is trying to use the file with queries there. We are getting error <Expression.Error: A cyclic reference was encountered during evaluation.>
I've tried to trace steps and find out when the error is occurring and it's always pointing at the custom function.
Please help me, I need to fix it asap so my team can use this.
Function screen
Calendar before function
Calendar after function
I was using this youtube guide to create function: https://www.youtube.com/watch?v=e2ic432NvhY

try changing your function to
(StartDate as date, EndDate as date) as number =>
let DateList = List.Dates(StartDate, Number.From(EndDate - StartDate) , #duration(1, 0, 0, 0)),
RemoveWeekends = List.Select(DateList, each Date.DayOfWeek(_, Day.Monday) < 5),
RemoveHolidays = List.RemoveItems(RemoveWeekends, Holidays),
CountDays = List.Count(RemoveHolidays)
in CountDays
then, assuming Holidays is a query with some list of dates like
= {#date(2022,6,15),#date(2022,1,18)}
then
= Table.AddColumn(#"Changed Type", "Custom", each NetWorkDays([StartDate],[EndDate]))
works fine

Thanks everyone for such quick answers.
My issue was that first I've created custom function based on list of holidays and calendar and then i've used it in calendar as well. When I removed custom function from the calendar query, leaving only starting date of the week, ending date and week number it started to work again.

Related

Using .addDateExclusion()

I'm creating school class calendar with repeating events, how do I use .addDateExclusion(new Date()), I tried a lot of combinations none of witch worked
function makeCalendar(name, begin, end, calendar) {
var eventSeries = CalendarApp.getCalendarById(calendar).createEventSeries(
name,
begin,
end,
CalendarApp.newRecurrence()
.addDateExclusion(new Date(2019, 1, 5, 0, 0, 0, 0))
.addWeeklyRule().interval(2).until(krajdat)
);
}
EDIT 1:
This is only ting that actually worked
function makeCalendar(name, begin, end, calendar) {
var eventSeries = CalendarApp.getCalendarById(calendar).createEventSeries(
name,
begin,
end,
CalendarApp.newRecurrence()
.addDateExclusion(begin)
.addWeeklyRule().interval(2).until(krajdat)
);
}
code above does what it is supposed to do that is ignore first occurrence, but whatever I did to that date like adding days didn't work
EDIT 2:
var d = new Date(begin);
d.setMonth(9);
d.setDate(9);
var eventSeries = CalendarApp.getCalendarById(calendar).createEventSeries(
name,
begin,
end,
CalendarApp.newRecurrence()
.addDateExclusion(d)
.addWeeklyRule().interval(2).until(krajdat)
);
This actually worked, but setting full year didn't.
Still not optimal result because I want to pass recurrence to function, but we are getting somewhere.
EDIT 3:
I think the problem here are actually time zones, I looked the logs and that was the only difference between working and non working dates.
Found error, problem were time zones that i needed to set in preferences .addDateExclusion() doesn't work if used with different time zones.

Multiple Or in an IIF function

Given this data: Complete Dataset
I only want to get the Total_AR of those TransactionYrMonth=ParameterPeriod so I produced it using this code:
=IIF(
IsNothing(Sum(Fields!Total_AR.Value)),0,
Sum(IIF(Cdate(Fields!TransactionYrMnth.Value)=Cdate(Parameters!Period.Value),
Fields!Total_AR.Value,0)
)
)
From there, I got this dataset:
Filtered Dataset
Now, what I need to do is to get the sum of the first 3 service months starting from January to March that is equal to the latest transaction month which is April.
So the sum should be equal to $204,329 + -$96,640 + -$259,008 = -$151,319
To make it possible, I tried to use a code like this:
=Sum(IIF(
Cdate(Fields!TransactionYrMnth.Value)=Cdate(Parameters!Period.Value) And (
Cdate(Fields!ServiceYrMnth.Value)=DateAdd(DateInterval.Month, -3, CDate(Parameters!Period.Value)) Or
Cdate(Fields!ServiceYrMnth.Value)=DateAdd(DateInterval.Month, -2, CDate(Parameters!Period.Value)) Or
Cdate(Fields!ServiceYrMnth.Value)=DateAdd(DateInterval.Month, -1, CDate(Parameters!Period.Value))), Fields!Total_AR.Value,0
))
I have no luck producing it. I even got an error saying
‘Textbox11.Paragraphs[0].TextRuns[0]’ contains an error: [BC30516] Overload resolution failed because no accessible 'IIf' accepts this number of arguments.
Anyone, please help?
I got a solution already using this code:
=Sum(IIF(
Cdate(Fields!TransactionYrMnth.Value)=Cdate(Parameters!Period.Value) And
CDate(Fields!ServiceYrMnth.Value) >= DateAdd(DateInterval.Month, -3, CDate(Parameters!Period.Value)) And
CDate(Fields!ServiceYrMnth.Value) <= DateAdd(DateInterval.Month, -1, CDate(Parameters!Period.Value)), Fields!Total_AR.Value, 0
)
)

How do I create a SQL calendar with reccuring events that can be easily queried?

I checked several older questions regarding this topic like this one: Calendar Recurring/Repeating Events - Best Storage Method however, the answers are pretty bad performance-wise and cumbersome in implementation. From another answer, it's easy to tell why the accepted answer is a bad idea: a month of events takes 90 queries. Which is unacceptable.
Anyways, here's the issue I'm facing so that you don't have re-read those questions:
Storing events in such a way to allow them to recur. Think Google Calendar where you can specify patterns like "happens on the 1st of the month, every month" or "happens every 2nd monday of the month" (the latter is less important to me.
Querying a list of events for a time period. For example, I want to show someone a list of events for the next 2 months and I don't want to query for every single day of the month. Doing that would just kill the server (per user among thousands of rows of events)
DB agnostic. I use PgSQL and saw many answers for this question on other forums using either MS SQL-specific stuff or Oracle.
I'd appreciate any help! I read a couple of papers on the topic and still can't find something I can make work in SQL specifically.
The solution I have come up with is that I have an event table that has five fields defining the recurrence of the event, as defined below. I then also have a schedule table which I populate with the actual occurrence of the events. I do require an end date, and even when they specify something to go out to a couple years out, it is a monthly type event which does not create that many entries into the schedule table.
So, the event is stored in an event table, with a startDateTime and an endDateTime that describe the entire duration of the event if there is no recurrence. These two datetime fields also define the overall start and end of the event if it is a recurring event. In that same event table, we have the five fields defining recurrence, as laid out below.
The Schedule table stores individual occurrences of each event. So it has an eventId, startDateTime, and endDateTime. This start and end refer only to each occurrence, not the overall span.
For querying for all the scheduled occurrences happening in a period of time, I just query the schedule table checking for any occurrences that match this condition:
select * from schedule where schedule.startDateTime < #queryPeriodEnd and schedule.endDateTime > #queryPeriodStart
This query gives me only the schedule entries that happen partially or wholly within my query period. For getting the event data, it's a simple matter of joining to the event table.
The interesting part is calculating something like the second thursday of the month. That happens in the actual code for figuring out all the scheduled occurrences for a given event. I am also enclosing my code for that below.
EVENT RECURRENCE FIELDS
recurs
0=no recurrence
1=daily
2=weekly
3=monthly
recurs_interval
this is how many of the periods between recurrences. If the event recurs every 5 days, recurs_interval will have a 5 and recurs will have 1. If the event recurs every 3 weeks, recurs_interval will have a 3 and recurs will have a 2.
recurs_day
If the user selected monthly type recurrence, on a given day of the month (ex: 10th or the 14th). This has that date. The value is 0 if the user did not select monthly or specific day of month recurrence. The value is 1 to 31 otherwise.
recurs_ordinal
if the user selected a monthly type recurrence, but an ordinal type of day (ex: first monday, second thursday, last friday). This will have that ordinal number. The value is 0 if the user did not select this type of recurrence.
1=first
2=second
3=third
4=fourth
5=last
recurs_weekdays
for weekly and monthly-ordinal recurrence this stores the weekdays where the recurrence happens. 1=Sunday
2=Monday
4=Tuesday
8=Wednesday
16=Thursday
32=Friday
64=Saturday
So, every 4 weeks on Saturday and Sunday would be
recurs=2, recurs_interval=4, recurs_weekdays=65 (64 + 1)
Similarly, Every three months on the first Friday of the month would be
recurs=3, recurs_interval=3, recurs_ordinal=1, recurs_weekdays=32
CODE
thisEvent.occurrences = new List<ScheduleInstance>();
DateTime currentDateTime = (DateTime) thisEvent.start;
DateTime currentEndTime;
BitArray WeekDayRecurrenceBits = new BitArray(new Byte[] {(Byte) thisEvent.recursWeekdays});
while (currentDateTime < thisEvent.end)
{
currentEndTime = new DateTime(currentDateTime.Year, currentDateTime.Month, currentDateTime.Day,
thisEvent.end.Value.Hour, thisEvent.end.Value.Minute, thisEvent.end.Value.Second);
switch (thisEvent.recurs)
{
case (RecurrenceTypeEnum.None):
AddOccurrenceToRooms(thisEvent, currentDateTime, currentEndTime);
currentDateTime = (DateTime)thisEvent.end;
break;
case (RecurrenceTypeEnum.Daily):
AddOccurrenceToRooms(thisEvent, currentDateTime, currentEndTime);
currentDateTime = currentDateTime.AddDays(thisEvent.recursInterval);
break;
case (RecurrenceTypeEnum.Weekly):
int indexIntoCurrentWeek = (int) currentDateTime.DayOfWeek;
while ((indexIntoCurrentWeek < 7) && (currentDateTime < thisEvent.end))
{
if (WeekDayRecurrenceBits[(int) currentDateTime.DayOfWeek])
{
AddOccurrenceToRooms(thisEvent, currentDateTime, currentEndTime);
}
currentDateTime = currentDateTime.AddDays(1);
currentEndTime = currentEndTime.AddDays(1);
indexIntoCurrentWeek++;
}
currentDateTime = currentDateTime.AddDays(7 * (thisEvent.recursInterval - 1));
break;
case (RecurrenceTypeEnum.Monthly):
if (thisEvent.recursDay == 0)
{
DateTime FirstOfTheMonth = new DateTime(currentDateTime.Year, currentDateTime.Month, 1);
int daysToScheduleOccurrence = ((thisEvent.recursWeekdays - (int)FirstOfTheMonth.DayOfWeek + 7) % 7)
+ ((thisEvent.recursOrdinal - 1) * 7)
- currentDateTime.Day + 1;
if (daysToScheduleOccurrence >= 0)
{
currentDateTime = currentDateTime.AddDays(daysToScheduleOccurrence);
currentEndTime = currentEndTime.AddDays(daysToScheduleOccurrence);
if (currentDateTime < thisEvent.end)
{
AddOccurrenceToRooms(thisEvent, currentDateTime, currentEndTime);
}
}
}
else
{
if (currentDateTime.Day <= thisEvent.recursDay && thisEvent.recursDay <= DateTime.DaysInMonth(currentDateTime.Year, currentDateTime.Month) )
{
currentDateTime = currentDateTime.AddDays(thisEvent.recursDay - currentDateTime.Day);
currentEndTime = currentEndTime.AddDays(thisEvent.recursDay - currentEndTime.Day);
AddOccurrenceToRooms(thisEvent, currentDateTime, currentEndTime);
}
}
currentDateTime = currentDateTime.AddDays((currentDateTime.Day - 1) * -1).AddMonths(thisEvent.recursInterval);
break;
default:
break;
}
}

Why does my function tell me that I have a Type Mismatch?

I'm trying to get the following function to work:
Private Function FirstOfMonth(MonthsAgo As Integer) As Date
FirstOfMonth = DateSerial(Year(Now()), Month(Now() - MonthsAgo), 1)
End Function
I'm passing in a value as follows:
FirstOfMonth(4)
The aim of the function is to return the date for the first of the month a number of 'MonthsAgo'.
However, whenever I run it it tells me that I have a Type Mismatch.
I'm new to programming, so if there's anyone that can point me in the right direction as to where I'm going wrong, I'd be very grateful. It's slowing me down solving a fairly simple problem.
I think what you meant to be doing was:
' Note the brackets change around 'Month(Now()) - MonthsAgo'
FirstOfMonth = DateSerial(Year(Now()), Month(Now()) - MonthsAgo, 1)
However, even this won't work. Consider the case where the month is January (1). In that scenario you will end up with a Date of 2012/-3/1 which is obviously complete nonsense!
You will instead need to use the DateAdd function:
DateAdd("m", 4, Now())
So your entire function looks like
Private Function FirstOfMonth(MonthsAgo As Integer) As Date
Dim newDate
newDate = DateAdd("m", 0 - MonthsAgo , Now())
FirstOfMonth = DateSerial(Year(newDate), Month(newDate), 1)
End Function
You must pass FirstOfMonth(4) into a "Date" variable

Inherited database has leap year code that compiler doesn't like

In my job, I have inherited an Access 97 database. This database is very unstable and I need to remedy that in one way or another. I have been trying to go through and debug the current version so that I can migrate it to 2007. I have run across some code that the compiler doesn't like and not sure how to fix it...here is the code:
Function DaysInMonth(ByVal D As Date) As Long
' Requires a date argument because February can change
' if it's a leap year.
Select Case Month(D)
Case 2
If LeapYear(Year(D)) Then
DaysInMonth = 29
Else
DaysInMonth = 28
End If
Case 4, 6, 9, 11
DaysInMonth = 30
Case 1, 3, 5, 7, 8, 10, 12
DaysInMonth = 31
End Select
End Function
I get a compile error: Sub or Function not defined and it highlights the first "LeapYear".
Any help at all would be greatly appreciated! Thanks!
LeapYear is another function or procedure that appears not be present in your modules or has been made Private. LeapYear isn't a VBA function. There must have been a function that takes a year Year(D) and returns TRUE or FALSE if it's a leapyear. either insert one or set the existing one to Public
Edit:You could use IsLeapYear but change to 'LeapYear' and call using IsLeapYear(D)
The code in question is idiotic -- it was clearly written by somebody who didn't have a clue about VBA dates, which already know everything that is needed without needed to encode this crap into a CASE SELECT.
This expression will get you the number of days in a month:
Day(DateAdd("m", 1, DateValue(Month(Date()) & "/1/" & Year(Date()))) - 1)
What this does is get the first of the current month, adds a month to it (for the first of the next month), and then subtracts 1 from it. Since the integer part of the VBA date type is the day part, that will get you the last day of the current month. Then you take the result and pull the day out with the Day() function.
Coding that up as a function:
Function DaysInMonth(ByVal dteDate As Date) As Integer
Dim dteFirstOfMonth As Date
Dim dteLastOfMonth As Date
dteFirstOfMonth = DateValue(Month(dteDate) & "/1/" & Year(dteDate))
dteLastOfMonth = DateAdd("m", 1, dteFirstOfMonth) - 1
DaysInMonth = Day(dteLastOfMonth)
End Function
You could also code this up using the fact that the DateSerial() function treats the zeroth day as the last of the previous month:
Function DaysInMonth(ByVal dteDate As Date) As Integer
Dim dteOneMonthFromDate As Date
Dim dteLastOfThisMonth As Date
dteOneMonthFromDate = DateAdd("m", 1, dteDate)
dteLastOfThisMonth = DateSerial(Year(dteOneMonthFromDate), Month(dteOneMonthFromDate), 0)
DaysInMonth = Day(dteLastOfThisMonth)
End Function
But that doesn't make it any shorter...
None of this requires figuring out leap year rules -- those are built into the VBA date type.
And, of course, the function should not return a Long, but an Integer, since the maximum value it can ever return is 31.
LeapYear may not be your only issue.
In Access '97, go to the VBA editor and click "Tools/References":
Look in the references of your '97 project and see what DLLs are listed.
A screen will appear that shows you the ActiveX DLLs that can be used for the project. The ones that are checked are the ones currently used:
Odds are there is a DLL there that needs to be referenced in your new 2007 database.