use*_*797 6 c# timezone datetime
在我的项目中,我需要计算重复事件的日期.一开始我只有一个开始日期/时间以及该事件必须重复的信息:
Every Day
Every Week
Every 2 Weeks
Every 3 Weeks
Every Month
Every 2 Months
...
Run Code Online (Sandbox Code Playgroud)
这样做的正确方法是什么?它应该可以正常使用不同的时区和日节省时间设置.我想我应该在本地DateTime中添加几天/几周/月,然后将其转换为UTC.但我不确定这一点.如果我添加几天会发生什么,这将是我们需要向前调整我们的时钟一小时的时间.在这种情况下,此时间不存在.
下面是我写的代码,但我不确定它在每种情况下都能正常工作:
private static List<DateTime> FindOccurrences(DateTime localStart, Repeat repeat, int occurrences)
{
var result = new List<DateTime> { localStart };
switch (repeat)
{
case Repeat.Daily:
for (int i = 1; i <= occurrences; i++)
result.Add(localStart.AddDays(i));
break;
case Repeat.Every2Weeks:
for (int i = 1; i <= occurrences; i++)
result.Add(localStart.AddDays((7 * 2) * i));
break;
...
}
return result;
}
public List<Event> CreateRepeating(string timeZone, Repeat repeat, int repeatEnds, DateTime localStart, int eventDuration)
{
var events = new List<Event>();
var occurrences = FindOccurrences(localStart, repeat, repeatEnds);
foreach (var occurrence in occurrences)
{
var item = new Event();
item.Start = occurrence.ToUtcTime(timeZone);
item.End = occurrence.ToUtcTime(timeZone).AddMinutes(eventDuration);
events.Add(item);
}
return events;
}
Run Code Online (Sandbox Code Playgroud)
PS:所有日期都以UTC格式存储在数据库中.
Mat*_*int 11
安排或计算未来事件的日期,尤其是重复发生的事件,是一个非常复杂的主题.我已经写了几次,虽然从其他语言的角度来看(见:1,2,3,4).
我担心这个主题过于宽泛,无法为您提供准确的代码.详细信息将特定于您的应用程序.但这里有一些提示.
一般来说:
仅将UTC用于发生单个事件实例的预计时刻.
以当地时间存储实际活动.同时存储时区ID.
不要不存储时区偏移.应该单独查找每次出现的情况.
将事件即将发生的事件计划为UTC,以便您知道何时基于事件(或对您的场景有意义的任何事情)执行操作.
决定夏令时,当一个事件发生在弹跳间隙或后退重叠时要做什么.您的需求可能会有所不同,但一个共同的策略是跳过春天的差距,并选择秋季的第一次出现.如果你不确定我的意思,请参阅dst标签wiki.
仔细考虑如何处理月末附近的日期.并非所有月份都有相同的天数,日历数学很难. dt.AddMonths(1).AddMonths(1)
不一定是一样的dt.AddMonths(2)
.
随时掌握时区数据更新.没人能预测未来,世界各国政府都喜欢改变一切!
您需要保留计划的原始本地时间值,以便可以重新设置事件的UTC值.您应该定期执行此操作,或者应用时区更新时(如果您手动跟踪它们). 时区标签wiki包含有关不同时区数据库及其更新方式的详细信息.
小心避免使用本地时区.你应该没有来电DateTime.Now
,ToLocalTime
或ToUniversalTime
.请记住,本地时区基于运行代码的计算机,不应影响代码的行为.阅读The Case Against DateTime.Now中的更多内容.
如果您正在完成所有这些工作,那么您应该查看一个预先解决的解决方案,例如Quartz.NET.它是免费的,开源的,功能强大的,涵盖了许多您可能没有想过的边缘情况.
部分答案.我宁愿将实现更改为
public enum TimePeriod {
None = 0,
Day = 1,
// Just week, no "two weeks, three weeks etc."
Week = 2,
Month = 3
}
public static class Occurrencies {
// May be you want to convert it to method extension: "this DateTime from"
public static IEnumerable<DateTime> FindInterval(DateTime from,
TimePeriod period,
int count) {
while (true) {
switch (period) {
case TimePeriod.Day:
from = from.AddDays(count);
break;
case TimePeriod.Week:
from = from.AddDays(7 * count);
break;
case TimePeriod.Month:
from = from.AddMonths(count);
break;
}
yield return from;
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用:
// Get 5 2-week intervals
List<DateTime> intervals2Weeks = Occurrencies
.FindInterval(DateTime.Now, TimePeriod.Week, 2)
.Take(5)
.ToList();
// Get 11 3-month intervals
List<DateTime> intervals3Months = Occurrencies
.FindInterval(DateTime.Now, TimePeriod.Month, 3)
.Take(11)
.ToList();
Run Code Online (Sandbox Code Playgroud)