C# 在C中将DST规则转换为DateTime#

C# 在C中将DST规则转换为DateTime#,c#,datetime,timezone,dst,C#,Datetime,Timezone,Dst,我有这样的DST规则: “2,-11.36亿” 2是以零为基的月份 -1是包含日期的周数,-1是包含日期的月份的最后一周 1是一周中的一天,从1号星期天到7号星期六 3600000是从指定日期的午夜开始的毫秒,DST的变更将发生,并以包括DST在内的当地时间表示,因此DST切换时间的结束以DST表示 在C#DateTime中转换它的正确方法是什么 到目前为止,我已经做到了: public static DateTime ConvertDstRule(int year, string rule

我有这样的DST规则:

“2,-11.36亿”

  • 2是以零为基的月份
  • -1是包含日期的周数,-1是包含日期的月份的最后一周
  • 1是一周中的一天,从1号星期天到7号星期六
  • 3600000是从指定日期的午夜开始的毫秒,DST的变更将发生,并以包括DST在内的当地时间表示,因此DST切换时间的结束以DST表示
在C#DateTime中转换它的正确方法是什么

到目前为止,我已经做到了:

public static DateTime ConvertDstRule(int year, string rule, bool isEndRule)
{
    const int DaysInWeek = 7;
    var ruleName = isEndRule ? "endRule" : "startRule";

    var startStrings = rule.Split(',');
    var month = Convert.ToInt32(startStrings[0]);
    if ((month < 0) || (month > 11))
    {
        throw new ArgumentOutOfRangeException(ruleName, "The month value must be between 0 and 11");
    }

    var week = Convert.ToInt32(startStrings[1]);
    if ((week < -1) || (week > 5))
    {
        throw new ArgumentOutOfRangeException(ruleName, "The week value must be between -1 and 5");
    }

    if ((Convert.ToInt32(startStrings[2]) < 1) || (Convert.ToInt32(startStrings[2]) > 7))
    {
        throw new ArgumentOutOfRangeException(ruleName, "The day value must be between 1 and 7");
    }

    var day = (DayOfWeek)(Convert.ToInt32(startStrings[2]) - 1); // DayOfWeek is zero based so shift by one.
    var timeOffset = Convert.ToInt64(startStrings[3]);
    if ((timeOffset / 1000 / 60) > 86400)
    {
        throw new ArgumentOutOfRangeException(ruleName, "The time offset is limited to one day");
    }

    // Find the start of the relevant year.
    var startTime = new DateTime(year, 1, 1);

    // Add on the month to get to the start of the selected month.
    startTime = startTime.AddMonths(month);

    // If the week is negative then go to the first occurance of the day in
    // the next month, adding a negative week number will jump back into
    // the previous month.
    if (week < 0)
    {
        startTime = startTime.AddMonths(1);
    }
    else
    {
        week = week - 1;
    }

    // Jump to the first occurence of the day to switch in that month.
    var monthStartsOn = startTime.DayOfWeek;
    var daysToSwitchDay = (int)day - (int)monthStartsOn;

    // This is likely to be negative as most zones switch on a Sunday
    if (daysToSwitchDay < 0)
    {
        daysToSwitchDay = DaysInWeek + daysToSwitchDay; // daysToSwitchDay is negative so add it.
    }

    startTime = startTime.AddDays(daysToSwitchDay); // Now on the correct day.

    startTime = startTime.AddDays(week * 7); // Week counts from 1.

    startTime = startTime.AddMilliseconds(timeOffset);
    if (isEndRule)
    {
        startTime = startTime.AddHours(-1); // Take off the DST hour to convert it to UTC.
    }

    return startTime;
}
publicstaticdatetime-convertdsrule(int-year,string规则,bool-isEndRule)
{
const int DaysInWeek=7;
var ruleName=isEndRule?“endRule”:“startRule”;
var startStrings=rule.Split(',');
var月=转换为32(起始字符串[0]);
如果((月<0)| |(月>11))
{
抛出新ArgumentOutOfRangeException(ruleName,“月值必须介于0和11之间”);
}
var week=转换为32(开始字符串[1]);
如果((周<-1)| |(周>5))
{
抛出新ArgumentOutOfRangeException(ruleName,“周值必须介于-1和5之间”);
}
if((转换为32(起始字符串[2])<1)| |(转换为32(起始字符串[2])>7))
{
抛出新ArgumentOutOfRangeException(ruleName,“日期值必须介于1和7之间”);
}
var day=(DayOfWeek)(Convert.ToInt32(startString[2])-1);//DayOfWeek是基于零的,所以移位1。
var timeOffset=Convert.ToInt64(startStrings[3]);
如果((时间偏移/1000/60)>86400)
{
抛出新ArgumentOutOfRangeException(ruleName,“时间偏移限制为一天”);
}
//找到相关年份的开始。
var startTime=新日期时间(年,1,1);
//添加月份以到达所选月份的开始。
startTime=startTime.AddMonths(月);
//如果本周为负数,则转到本周当天的第一个事件
//下个月,增加一个负的周数将跳回
//上个月。
如果(周<0)
{
startTime=startTime.AddMonths(1);
}
其他的
{
周=第1周;
}
//跳转到当月要切换的第一个事件。
var monthStartsOn=startTime.DayOfWeek;
var daysToSwitchDay=(整数)天-(整数)月开始;
//这可能是负面的,因为大多数区域在周日切换
if(daysToSwitchDay<0)
{
daysToSwitchDay=DaysInWeek+daysToSwitchDay;//daysToSwitchDay为负数,因此添加它。
}
startTime=startTime.AddDays(daysToSwitchDay);//现在是正确的一天。
startTime=startTime.AddDays(周*7);//周从1开始计数。
startTime=startTime.add毫秒(时间偏移);
如果(isEndRule)
{
startTime=startTime.AddHours(-1);//去掉DST小时,将其转换为UTC。
}
返回起始时间;
}
它是否考虑了半小时DST的变化,比如在印度?你能找出这段代码中的错误吗?

有几点:

  • 您描述的输入类型称为“转换规则”。或者在时区之外,它是一种特殊类型的“重复规则”。它简单地描述了一种模式,用于根据月份、星期和工作日确定特定时间点在给定年份的发生时间

  • 转换规则不会告诉您计算时区值所需的所有信息。特别是,它不会告诉您在转换之前或之后与UTC的偏移量是多少,也不会告诉您偏移量的调整方向。此外,您还需要一套这些,因为通常每年有两套,但也可以有任意数量的。例如,2014年,以及。同时考虑到这些规则随着时间的推移而改变,所以一条规则,甚至是一对规则,将不会告诉你如何及时转换所有时间点的值。对于给定的时区,您需要一组规则,这就是我们所说的“时区”的意思

  • 在.NET Framework中,
    TimeZoneInfo
    类用于处理时区。它包含子类,
    TimeZoneInfo.AdjustmentRule
    TimeZoneInfo.TransitionTime
    。特别是,在
    TimeZoneInfo
    中有一个名为
    TransitionTimeToDateTime
    的内部函数,它完全满足您的要求。它需要
    TransitionTime
    和一年,并提供一年内发生转换的
    DateTime
    。你可以找到这个

但是,如果您真的想尝试从自己的数据源实现时区规则,那么您应该考虑以下几点:

  • 你真的认为你能比之前的数百人做得更好吗?也许是这样,但不要抱着“这很简单”的态度来讨论这个问题。我建议你,在尝试之前做很多研究

  • 你是否在考虑如何维护这些东西?时区规则经常变化。每年,全世界可能会发生十几次变化。您是否计划监控新闻提要、论坛、政府新闻稿和其他来源?当一个政府不发出那么多警告说它的DST规则将要改变时,你准备好采取行动了吗

  • 当事情不准确时,它会对您的系统产生多大影响?它的范围可以从不多(例如:博客或论坛)到关键(例如:航班时刻表、通信、医疗、财务等)

  • 此外:

    • 使用问题注释的建议是一个很好的建议,但不幸的是,野田佳彦没有任何特定的API来解释单一的转换规则。相反,建议您使用现有的TZDB区域,例如
      “America/New_York”
      。或者,您可以使用