如何创建表示定期事件的DateTimes列表,而不管夏令时?

时间:2013-11-11 02:36:40

标签: c# .net datetime timezone dst

例如,无论是否有夏令时,每周六欧洲中部时间08:00(或夏令时08:00 CEST)都会发生反复发生的事件。我如何提出代表此事件的DateTime列表?

2 个答案:

答案 0 :(得分:0)

你在找这个吗?

List<DateTime> Schedule = new List<DateTime>();

DateTime Base = new DateTime(2013, 11, 9, 8, 0, 0);

for (int i = 0; i < 365; i++)
    Schedule.Add(Base.AddDays(i));

答案 1 :(得分:0)

这是一种获取DateTimeOffset值列表的方法,可以准确地表示您的要求。如果您愿意,可以使用DateTimeresult.DateTime转换为result.UtcDateTime,具体取决于您要查找的内容。这将在今天的下一个N天返回,在提供的时区中,占DST。

public static IEnumerable<DateTimeOffset> GetNextDaysInZone(int count, DayOfWeek dayOfWeek, TimeSpan localTimeOfDay, string timeZoneId)
{
    // get today in the time zone specified
    TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
    DateTime today = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, tz).Date;

    // figure out how many days we are away from the target day of week
    int adjustment = dayOfWeek - today.DayOfWeek + (dayOfWeek < today.DayOfWeek ? 7 : 0);

    // calculate and return the results
    return Enumerable.Range(0, count)
        .Select(x =>
        {
            DateTime dt = today.AddDays(x * 7 + adjustment).Add(localTimeOfDay);
            TimeSpan offset = tz.GetUtcOffset(dt);
            return new DateTimeOffset(dt, offset);
        });
}

使用示例:

DayOfWeek dayOfWeek = DayOfWeek.Saturday;
TimeSpan localTimeOfDay = new TimeSpan(8, 0, 0);

// Note: Despite the name, this represents Central European Time, including both CET and CEST.
string tzid = "Central Europe Standard Time";

var results = GetNextDaysInZone(5, dayOfWeek, localTimeOfDay, tzid);

foreach (var result in results)
{
    Console.WriteLine("{0:yyyy-MM-dd HH:mm:ss zzz} ({1:yyyy-MM-dd HH:mm:ss} UTC)", result, result.UtcDateTime);
}

结果:

2013-11-16 08:00:00 +01:00 (2013-11-16 07:00:00 UTC)
2013-11-23 08:00:00 +01:00 (2013-11-23 07:00:00 UTC)
2013-11-30 08:00:00 +01:00 (2013-11-30 07:00:00 UTC)
2013-12-07 08:00:00 +01:00 (2013-12-07 07:00:00 UTC)
2013-12-14 08:00:00 +01:00 (2013-12-14 07:00:00 UTC)

如果您想放弃内置日期/时间api并使用更强大可靠的内容,我建议您尝试Noda Time。以下是使用Noda Time进行上述操作的方法。

public static IEnumerable<ZonedDateTime> GetNextDaysInZone(int count, IsoDayOfWeek dayOfWeek, LocalTime localTimeOfDay, string timeZoneId)
{
    // get today in the time zone specified
    DateTimeZone tz = DateTimeZoneProviders.Tzdb[timeZoneId];
    Instant now = SystemClock.Instance.Now;
    LocalDate today = now.InZone(tz).Date;

    // figure out how many days we are away from the target day of week
    int adjustment = dayOfWeek - today.IsoDayOfWeek + (dayOfWeek < today.IsoDayOfWeek ? 7 : 0);

    // calculate and return the results
    return Enumerable.Range(0, count)
        .Select(x => (today.PlusDays(x * 7 + adjustment) + localTimeOfDay).InZoneLeniently(tz));
}

示例用法:

IsoDayOfWeek dayOfWeek = IsoDayOfWeek.Saturday;
LocalTime localTimeOfDay = new LocalTime(8, 0, 0);

// This is just one of the zones that follows CET/CEST
string tzid = "Europe/Berlin";

var results = GetNextDaysInZone(5, dayOfWeek, localTimeOfDay, tzid);

LocalDateTimePattern localPattern = LocalDateTimePattern.CreateWithInvariantCulture("yyyy-MM-dd HH:mm:ss");
OffsetPattern offsetPattern = OffsetPattern.CreateWithInvariantCulture("m");
foreach (var result in results)
{
    Console.WriteLine("{0} {1} ({2} UTC)",
        localPattern.Format(result.LocalDateTime),
        offsetPattern.Format(result.Offset),
        localPattern.Format(result.WithZone(DateTimeZone.Utc).LocalDateTime));
}

结果:

2013-11-16 08:00:00 +01:00 (2013-11-16 07:00:00 UTC)
2013-11-23 08:00:00 +01:00 (2013-11-23 07:00:00 UTC)
2013-11-30 08:00:00 +01:00 (2013-11-30 07:00:00 UTC)
2013-12-07 08:00:00 +01:00 (2013-12-07 07:00:00 UTC)
2013-12-14 08:00:00 +01:00 (2013-12-14 07:00:00 UTC)

这两种方法都采用了在夏令时转换日期间不存在或存在两次的宽松转换路径。如果你不喜欢它,那么你还有更多的工作要做。但我认为这超出了你所要求的范围。