【问题标题】:Aggregate weekly data into Month data giving weight to first and last week将每周数据汇总为月份数据,赋予第一周和上周的权重
【发布时间】:2021-01-23 01:16:50
【问题描述】:

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

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

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

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

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

  • 2020 年 53 月(部分,仅 3 天)
  • 2021 年 01 月
  • 2021 年 02 月
  • 2021 年 03 月 等等。



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);
}

【问题讨论】:

  • 我已经看到一个错误:(daysInTheMonth/7) 是一个整数除法。你想要(daysInTheMonth/7m),否则8/7 = 1,或者你可以直接daysInTheMonth * priceValue / 7(先乘再除),priceValuedecimal,所以乘法有保证的提升。
  • @xanatos 谢谢纠正。 (这里的代码是动态写的,VS中还没有。我需要找到正确的算法)
  • 我看到了另一个问题... 一个跨度为 1 月底和 2 月初的一周...您会在 1 月计算一块,在 2 月计算一块...但是您的方法有输入的月份,但无法与调用者沟通同一周必须在下个月“重复使用”。可能将month 设置为ref 以便方法可以更改它。
  • @xantos,是的,这正是我在我的问题中要问的,获取一个月中的部分天数以计算周的重量。它们可以在开头,也可以在结尾。我怎样才能得到它们?

标签: c# linq


【解决方案1】:

如果你想用 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作为输出参数(如果必须拆分加权价格) .

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-02
    • 1970-01-01
    相关资源
    最近更新 更多