首页 > 解决方案 > 将每周数据汇总为月份数据,赋予第一周和上周的权重

问题描述

我有一个数据库,其中包含基于周数(ISO8601 定义)的产品几年的价格值。

现在我需要按月汇总这些数据,但还要考虑每个月一周的权重。例如,如果当月一周只有 3 天,我需要给这周赋予 3/7 的权重,因此价格值为 (3/7)*price。

我已经开始编写这段代码,但我完全不知道如何继续。有没有一种简单的方法可以做到这一点,或者我需要逐个循环遍历所有年月,并以这种方式计算重量?(可能直接使用 LINQ 或 SQL)

此外,我无法获得我正在循环的月份中包含的周数(ISO-8601 定义,1 到 53)

例如,在 2021 年 1 月,我们有几个星期:




public static decimal GetWeightedMonthlyPrice(int year, int week, int month, decimal priceValue)
{
    DateTime startDate = FirstDateOfWeekISO8601(year,week);
    
    //get weight of the week in the month
    int daysInTheMonth=0;
    for(int i=0;i<7;i++){
        if(startDate.AddDays(i).Month==month){
            daysInTheMonth++;
        }
    }
    decimal weightedPrice= (daysInTheMonth/7m)*priceValue; //the weighted price for the current month
    return weightedPrice;
}


public static DateTime FirstDateOfWeekISO8601(int year, int weekOfYear)
{
    DateTime jan1 = new DateTime(year, 1, 1);
    int daysOffset = DayOfWeek.Thursday - jan1.DayOfWeek;
    DateTime firstThursday = jan1.AddDays(daysOffset);
    var cal = CultureInfo.CurrentCulture.Calendar;
    int firstWeek = cal.GetWeekOfYear(firstThursday, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
    var weekNum = weekOfYear;
    if (firstWeek == 1)
    {
        weekNum -= 1;
    }
    var result = firstThursday.AddDays(weekNum * 7);
    return result.AddDays(-3);
}

标签: c#linq

解决方案


如果您想在 C# 中执行此操作,可能类似于:

/// <summary>
/// 
/// </summary>
/// <param name="year"></param>
/// <param name="week"></param>
/// <param name="priceValue"></param>
/// <param name="month1">0 == december of year - 1</param>
/// <param name="weightedPrice1"></param>
/// <param name="month2">13 == january of year + 1, null == the week is fully contained in month1</param>
/// <param name="weightedPrice2">null == the week is fully contained in month1</param>
public static void GetWeightedMonthlyPrice(int year, int week, decimal priceValue, out int month1, out decimal weightedPrice1, out int? month2, out decimal? weightedPrice2)
{
    DateTime startDate = FirstDateOfWeekISO8601(year, week);

    month1 = startDate.Month;

    int days1 = DateTime.DaysInMonth(year, month1) - startDate.Day + 1;
    weightedPrice1 = days1 * priceValue / 7m;

    int days2 = 7 - days1;

    if (days2 != 0)
    {
        month2 = month1 + 1;
        weightedPrice2 = days2 * priceValue / 7m;
    }
    else
    {
        month2 = null;
        weightedPrice2 = null;
    }

    if (month1 == 12)
    {
        month1 = 0;
    }
}

注意month不是输入参数,而是输出参数,输出参数可以有两个months(如果必须拆分加权价格)。

firstThursday如果您可以缓存调用之间的of FirstDateOfWeekISO8601(不是说它“慢”,但我不想知道它每年被重新计算 52 或 53 次),则可以在 C# 中构建更快的解决方案。解决方案甚至可以建在 SQL 端。


推荐阅读