2014-10-14 4 views
6

내 프로젝트에서 반복 이벤트에 대한 날짜를 계산해야합니다. 처음에는 시작일/시간과이 이벤트가 반복되어야하는 정보가 있습니다.C#에서 되풀이 날짜를 계산하는 올바른 방법

Every Day 
Every Week 
Every 2 Weeks 
Every 3 Weeks 
Every Month 
Every 2 Months 
... 

어떻게해야할까요? 다른 시간대 및 요일 저장 설정으로 올바르게 작동해야합니다. 나는 단지 일/주/월을 로컬 DateTime에 추가 한 다음 UTC로 변환해야한다고 생각합니다. 하지만 이것에 대해서는 잘 모르겠습니다. 며칠을 추가하면 시계가 1 시간 앞으로 조정되어야 할 때가됩니다. 이 경우에는이 시간이 존재하지 않습니다. 다음은

은 내가 쓴 코드입니다,하지만 난이 모든 경우에 제대로 작동하는지 확실하지 않다 :

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

PS : 모든 날짜가 데이터베이스에서 UTC 형식으로 저장됩니다.

+2

[NodaTime] (http://code.google.com/p/noda-time/) - 날짜 및 시간대 고유의 많은 문제점을 고려했습니다. – StuartLC

답변

5

부분 대답.

// 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(); 
8

일정 또는 미래의 사건, 특히 반복되는 이벤트의 날짜를 계산, 매우 복잡한 주제이다 : 나는 오히려

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

사용에 구현을 변경할 것입니다. 다른 언어의 관점에서 볼 때 몇 번이나이 내용을 썼습니다 (1, 2, 3, 4 참조).

정확한 코드를 제공하기에는 너무 광범위합니다. 세부 사항은 응용 프로그램에 매우 특정한 것입니다. 그러나 여기에 몇 가지 팁이 있습니다. 일반적으로

:

  • 사용 UTC 이벤트 만의 단일 인스턴스가 발생하는 시간에 투영 된 순간.

  • 실제 이벤트는 로컬 시간에 저장하십시오. 시간대 ID도 저장하십시오.

  • do 오프셋을 저장하지 않음. 그것은 각 사건마다 개별적으로 찾아야합니다.

  • 이벤트 발생 예정일을 UTC로 프로젝트하여 이벤트를 기반으로 어떤 조치를 취해야하는지 (또는 시나리오에 적합한 지) 알 수 있습니다.

  • 일광 절약 시간제, 즉 어커런스가 스프링 앞으로 감추거나 폴백 되려고 할 때 수행 할 작업을 결정하십시오. 요구 사항은 다를 수 있지만 일반적인 전략은 으로 건너 뛰어 봄 간격 인이며, 가을에는 첫 번째로 발생을 선택하십시오. 무슨 뜻인지 확실하지 않으면 the dst tag wiki을 참조하십시오.

  • 월말에 가까운 날짜를 처리하는 방법에 대해 신중히 생각하십시오. 모든 달의 일수가 같지 않으며 캘린더 수학이 어렵지 않습니다. dt.AddMonths(1).AddMonths(1)은 반드시 dt.AddMonths(2)과 같을 필요는 없습니다.

  • 표준 시간대 데이터 업데이트를 유지하십시오. 아무도 미래를 예언 할 수 없으며 세계 정부는 일을 바꾸고 싶어합니다!

  • 발생의 UTC 값을 다시 투영 할 수 있도록 일정의 원래 현지 시간 값을 유지해야합니다. 정기적으로 또는 시간대 업데이트를 적용 할 때마다 (수동으로 추적하는 경우)이 작업을 수행해야합니다. The timezone tag wiki에는 다른 표준 시간대 데이터베이스 및 업데이트 방법에 대한 세부 정보가 있습니다.

  • Noda TimeIANA/TZDB 시간대를 사용하는 것을 고려하십시오. 이러한 유형의 작업은 Microsoft에서 제공하는 기본 제공 유형 및 표준 시간대보다 훨씬 적합합니다.

  • 현지 시간대를 사용하지 않도록주의하십시오. DateTime.Now, ToLocalTime 또는 ToUniversalTime에 대한 전화가 없어야합니다. 현지 표준 시간대는 코드가 실행중인 컴퓨터를 기반으로하며 코드 동작에 영향을 미치지 않아야합니다. The Case Against DateTime.Now에서 자세히 읽으십시오.

  • 예약 된 작업을 시작하기 위해이 모든 작업을 수행하는 경우 Quartz.NET과 같은 사전 미리 준비된 솔루션을 살펴 봐야합니다. 그것은 자유롭고, 오픈 소스이며, 기능성이 뛰어나며 생각하지 못한 많은 경우를 망라합니다.

관련 문제