Week number for BPM

So, in a BAQ you can get the week number easily. I thought it would be just as easy in a BPM. Turns out it’s not, as far as I can tell. I’m trying to use the methods on this site Calendar.GetWeekOfYear(DateTime, CalendarWeekRule, DayOfWeek) Method (System.Globalization) | Microsoft Learn to get the week number. But it’s not working for me.

Does anyone know how I can get the week number to populate a UD field on row add?

You can use something like this

DateTime fromDate = new DateTime(2016, 1, 1); // Return Week Number for this date

DateTime startOfYear = fromDate.AddDays(-fromDate.Day + 1).AddMonths(-fromDate.Month + 1);
DateTime endOfYear = startOfYear.AddYears(1).AddDays(-1);
int[] iso8601Correction = { 6, 7, 8, 9, 10, 4, 5 };
int nds = fromDate.Subtract(startOfYear).Days + iso8601Correction[(int)startOfYear.DayOfWeek];
int wk = nds / 7;
DateTime NewDate = fromDate;
switch (wk)
{
    case 0:
        // Return Week Number of Previous Year in some cases (1/1/2016)
        NewDate = startOfYear.AddDays(-1);
        startOfYear = fromDate.AddDays(-NewDate.Day + 1).AddMonths(-NewDate.Month + 1);
        endOfYear = startOfYear.AddYears(1).AddDays(-1);
        nds = NewDate.Subtract(startOfYear).Days + iso8601Correction[(int)startOfYear.DayOfWeek];
        wk = nds / 7;
        break;
    case 53:
        // Adjust
        if (endOfYear.DayOfWeek < DayOfWeek.Thursday)
            {
              wk = 1;
            }
        else
            wk = wk;
        break;
}

//Display Week in Message
Epicor.Customization.Bpm.InfoMessage.Publish(wk.ToString());
1 Like

Will that work in a BPM? in order to populate a UD field upon line creation?

OK, so I got this working. (lots of google.) I had to adjust a couple of things.

I first was trying to do this is a method directive, got it working for new records, but when I tried to set up for updated records, then deleting rows puked. Then I realized I could do in a data directive (should have tried that first) and now it works fine.

this is my code now, note that the ISO8601Correction is no longer ISO, (We need the work week to start on Sunday) so I adjusted that. I created the variables PayRollDate and WK in the BPM. I set PayRollDate before the custom code runs in order to use it in the calcalation, and the custom code sets the WK variable. Then I used a setter to apply WK to my UD field in the table. I had to use the ?? DateTime.MinValue; to make the ParRollDate read. Is what I should do for that? It seems to work, but there were a lot of options I found while googling and I don’t know it that’s the best was to handle that.

DateTime fromDate = PayRollDate ?? DateTime.MinValue;

DateTime startOfYear = fromDate.AddDays(-fromDate.Day + 1).AddMonths(-fromDate.Month + 1);
DateTime endOfYear = startOfYear.AddYears(1).AddDays(-1);
int[] iso8601Correction = { 7, 8, 9, 10, 4, 5, 6 };
int nds = fromDate.Subtract(startOfYear).Days + iso8601Correction[(int)startOfYear.DayOfWeek];
int wk = nds / 7;
DateTime NewDate = fromDate;
switch (wk)
{
    case 0:
        // Return Week Number of Previous Year in some cases (1/1/2016)
        NewDate = startOfYear.AddDays(-1);
        startOfYear = fromDate.AddDays(-NewDate.Day + 1).AddMonths(-NewDate.Month + 1);
        endOfYear = startOfYear.AddYears(1).AddDays(-1);
        nds = NewDate.Subtract(startOfYear).Days + iso8601Correction[(int)startOfYear.DayOfWeek];
        wk = nds / 7;
        break;
    case 53:
        // Adjust
        if (endOfYear.DayOfWeek < DayOfWeek.Thursday)
            {
              wk = 1;
            }
        else
            wk = wk;
        break;
}

this.WK = wk;

Thanks @danbedwards

I can correct it a bit because according to ISO 8601 standard, As a consequence, if 1 January is on a Monday, Tuesday, Wednesday or Thursday, it is in week 01. If 1 January is on a Friday, Saturday or Sunday , it is in week 52 or 53 of the previous year (there is no week 00). 28 December is always in the last week of its year.
Here, I adjust for the last week of the old year, if calculated according to the day of the old year eg 28-31/12 old year, it will be week 52, and calculated according to new year 1/1/new year will be week first

so I can tweak this a bit instead of you using the case for the 53rd week because my test shows 52 weeks for 365 days of the year.
int wk = nds<7? 1: nds / 7;

using System.Globalization;

Console.Clear(); // xóa mà hình dos
Console.BackgroundColor = ConsoleColor.Blue; //đổi màu nền dos
Console.ForegroundColor = ConsoleColor.White; // đổi màu chữ trong dos
Console.WriteLine("Hello, World!");
CultureInfo cul = CultureInfo.CurrentCulture;
DateTimeFormatInfo dfi = DateTimeFormatInfo.CurrentInfo;
Calendar cal = cul.Calendar;
string ngay1 ="2023-01-01", ngay2 = "2022-12-31";
DateTime day1 = DateTime.Parse(ngay1), day2= DateTime.Parse(ngay2);
DateTime day3 = new DateTime(2022, 1, 2), day4 = new DateTime(2022,1,2);
Console.WriteLine("so sánh chuỗi!:"+ (ngay1.Equals(ngay2)).ToString());
Console.WriteLine("tuan cua ngay :" + day1.ToString() + " là: " + cal.GetWeekOfYear(day1, dfi.CalendarWeekRule, dfi.FirstDayOfWeek));
Console.WriteLine("tuan cua ngay :"+day2.ToString()+ " là: " + cal.GetWeekOfYear(day2, dfi.CalendarWeekRule,dfi.FirstDayOfWeek) );
//
DateTime fromDate = new DateTime(2022, 12, 31);

DateTime startOfYear = fromDate.AddDays(-fromDate.Day + 1).AddMonths(-fromDate.Month + 1);
Console.WriteLine("startOfYear: " + startOfYear.ToString());
DateTime endOfYear = startOfYear.AddYears(1).AddDays(-1);
Console.WriteLine("endOfYear: " + endOfYear.ToString());
int[] iso8601Correction = { 7, 8, 9, 10, 4, 5, 6 };

Console.WriteLine("fromDate.Subtract(startOfYear).Days: " + fromDate.Subtract(startOfYear).Days.ToString());
Console.WriteLine("[(int)startOfYear.DayOfWeek]: " + startOfYear.DayOfWeek.ToString());
Console.WriteLine("iso8601Correction[(int)startOfYear.DayOfWeek]: " + iso8601Correction[(int)startOfYear.DayOfWeek].ToString());
int nds = fromDate.Subtract(startOfYear).Days + iso8601Correction[(int)startOfYear.DayOfWeek];
Console.WriteLine("nds: " + nds.ToString());
int wk = nds<7? 1: nds / 7;
DateTime NewDate = fromDate;
switch (wk)
{
    case 0:
        // Return Week Number of Previous Year in some cases (1/1/2016)
        NewDate = startOfYear.AddDays(-1);
        startOfYear = fromDate.AddDays(-NewDate.Day + 1).AddMonths(-NewDate.Month + 1);
        endOfYear = startOfYear.AddYears(1).AddDays(-1);
        nds = NewDate.Subtract(startOfYear).Days + iso8601Correction[(int)startOfYear.DayOfWeek];
        wk = nds / 7;
        break;
    case 53:
        // Adjust
        if (endOfYear.DayOfWeek < DayOfWeek.Thursday)
        {
            wk = 1;
        }
        //else
        //    wk = wk;
        break;
}
Console.WriteLine("tuan cua ngay :" + wk.ToString());
//
Console.Read();

according to the standards of ISO 8601 and System.Globalization; then it’s 1 week apart like 10/14/2022 according to System.Globalization; is the 42nd week because there are 53 weeks but according to ISO 8601 only 41 because there are only 52 weeks

Thank you so much good luck! :smiling_face_with_three_hearts: :smiling_face_with_three_hearts: :thinking: :thinking:

Thinking and remembering out loud here…
MANY Moons ago… I was trying to figure out a way to do fancy date calculations and after much worry about how to do it correctly, i instead simply created a table. The table had a single record for every day (yes, 365 records per year except leap years with 366). That record allowed me to define all sorts of things about the day: Day of week, week number, month number quarter number, and other weird attributes like “This is the first day of the fiscal month”, or “This is the last day of the fiscal month”) etc… since we worked on a 445 calendar, we could also specify the correct fiscal month for each date. This was maintainable and also allowed us to plop in holidays, etc.
Since it was now a table, I could also simply lookup any date to get its attributes. I could search for and find the first fiscal date of any fiscal month. Problem solved… no fancy calculations.

3 Likes

OH… one other advantage… we also had a “manufacturing date” (an integer number) for each working date defined in our calendar… this allowed us to do simple math to find out how many “MDays” were between any two dates… look up date one, look up date two, subtract MDAY1 from MDAY 2, and you know the number of working days between the two days. We could do the same simple math in reverse… Lookup a date to find its MDAY, and lookup MDAY+30 to find the date 30 working days away. it was so simple.