У нас есть система, которая представляет недели с указанием времени UTC, начинающегося &. Дата окончания времени из часового пояса Америки/Чикаго. Недели начинаются в полночь в субботу утром центрального времени и заканчивается в 23:59:59 в пятницу вечером центрального времени, поэтому их записи UTC в базе данных являются:Перевод времени UTC в любое время в будущем, учитывая переход на летнее время в часовом поясе
Week 1 - begin: 2015-10-24 05:00:00, end 2015-10-31 04:59:59
Week 2 - begin: 2015-10-31 05:00:00, end 2015-11-07 05:59:59
Week 3 - begin: 2015-11-07 06:00:00, end 2015-11-14 05:59:59
Week 4 - begin: 2015-11-14 06:00:00, end 2015-11-21 05:59:59
Week 5 - begin: 2015-11-21 06:00:00, end 2015-11-28 05:59:59
Так из приведенных выше примеров недель, вы можете см. изменение времени от дневного света до стандартного времени между 10/31 & 11/7.
Мне нужно вернуть N недель с данной недели. Наши системы - это веб-роли C# Azure & и запускаются в облаке Azure (все вычислительные узлы - UTC). Моя логика заключается в том, чтобы начать стартовую неделю и добавить недельную работу дней к начальной дате/времени недели и запросить недели, у которых дата начала больше начальной даты начала и меньше или равна расчетной будущая дата.
var weeks = repository.Fetch(x => x.BeginDate <= nWeeksAheadUtc && x.BeginDate > week.BeginDate)l=;
Это работает, за исключением случаев, когда в результате результирующего ответа происходит переход на летнее время. Из-за изменения времени, просим в течение следующих 3 недель с 1-й недели на основе добавления 21 дня к дате начала 1-й недели, приводит только к возврату Недели 2 & 3, поскольку рассчитанное будущее значение - 2015-11-14 05:00: 00, что исключает Неделя 4.
Я решил эту проблему, используя Nodatime следующим образом:
LocalDateTime localDateTime = LocalDateTime.FromDateTime(week.BeginDate);
ZonedDateTime zonedDateTime = localDateTime.InZoneStrictly(DateTimeZoneProviders.Tzdb["UTC"]);
zonedDateTime = zonedDateTime.WithZone(DateTimeZoneProviders.Tzdb["America/Chicago"]);
DateTime centralDateTime = zonedDateTime.ToDateTimeUnspecified();
DateTime futureDateTime = centralDateTime.Add(TimeSpan.FromDays(weekCount*7));
localDateTime = LocalDateTime.FromDateTime(futureDateTime);
zonedDateTime = localDateTime.InZoneStrictly(DateTimeZoneProviders.Tzdb["America/Chicago"]);
DateTime nWeeksAheadUtc = zonedDateTime.ToDateTimeUtc();
var weeks = repository.Fetch(x => x.BeginDate <= nWeeksAheadUtc && x.BeginDate > week.BeginDate).OrderBy(x => x.RetailerWeekNumber).ToList();
в то время как функции, кажется громоздким и не очень интуитивным для разработчиков, которые будут следовать за мной в сохранении этого код. Есть ли более чистый способ сделать это через API Nodatime или (базовая дата/время C#), которую я пропускаю?
Добавление в запрашиваемом примере - я только что создал проект UnitTest для этого, и эти три класса:
Week.cs
using System;
namespace NodaTimeTest
{
public class Week
{
public int Id { get; set; }
public DateTime BeginDate { get; set; }
public DateTime EndDate { get; set; }
}
}
WeekService.cs
using NodaTime;
using System;
using System.Collections.Generic;
using System.Linq;
namespace NodaTimeTest
{
public class WeekService
{
private readonly List<Week> repository;
public WeekService()
{
this.repository = this.InitWeeks();
}
public List<Week> GetNextWeeks(int weekId, int weekCount)
{
Week week = this.repository.First(x => x.Id == weekId);
// the meat - how to do this the right way?
LocalDateTime localDateTime = LocalDateTime.FromDateTime(week.BeginDate);
ZonedDateTime zonedDateTime = localDateTime.InZoneStrictly(DateTimeZoneProviders.Tzdb["UTC"]);
zonedDateTime = zonedDateTime.WithZone(DateTimeZoneProviders.Tzdb["America/Chicago"]);
DateTime centralDateTime = zonedDateTime.ToDateTimeUnspecified();
DateTime futureDateTime = centralDateTime.Add(TimeSpan.FromDays(weekCount * 7));
localDateTime = LocalDateTime.FromDateTime(futureDateTime);
zonedDateTime = localDateTime.InZoneStrictly(DateTimeZoneProviders.Tzdb["America/Chicago"]);
DateTime nWeeksAheadUtc = zonedDateTime.ToDateTimeUtc();
var weeks = repository.Where(x => x.BeginDate <= nWeeksAheadUtc && x.BeginDate > week.BeginDate).OrderBy(x => x.Id).ToList();
return weeks;
}
private List<Week> InitWeeks()
{
// sets up our list of 10 example dates in UTC encompassing America/Chicago daylight savings time change on 11/1
// this means that all weeks are 168 hours long, except week "4", which is 169 hours long.
var weeks = new List<Week>();
DateTime beginDate = new DateTime(2015, 10, 10, 5, 0, 0, DateTimeKind.Utc);
for (int i = 1; i <= 10; i++)
{
DateTime endDate = beginDate.AddDays(7).AddSeconds(-1);
if (endDate.Date == new DateTime(2015, 11, 7, 0, 0, 0, DateTimeKind.Utc))
{
endDate = endDate.AddHours(1);
}
weeks.Add(new Week { Id = i, BeginDate = beginDate, EndDate = endDate });
beginDate = endDate.AddSeconds(1);
}
return weeks;
}
}
}
WeekServiceTest :
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;
namespace NodaTimeTest
{
[TestClass]
public class WeekServiceTest
{
private readonly WeekService weekService = new WeekService();
[TestMethod]
public void TestGetNextThreeWeeksOverDaylightTimeChange()
{
var result = this.weekService.GetNextWeeks(2, 3);
Assert.AreEqual(3, result.ElementAt(0).Id);
Assert.AreEqual(4, result.ElementAt(1).Id);
Assert.AreEqual(5, result.ElementAt(2).Id);
}
[TestMethod]
public void TestGetNextThreeWeeksWithNoDaylightTimeChange()
{
var result = this.weekService.GetNextWeeks(5, 3);
Assert.AreEqual(6, result.ElementAt(0).Id);
Assert.AreEqual(7, result.ElementAt(1).Id);
Assert.AreEqual(8, result.ElementAt(2).Id);
}
}
}
Вы уверены, что хотите сохранить UTC? По данным Национального центра ураганов «Переход на летнее время не влияет на UTC». – Kevin
+ Кевин Да, это UTC. В то время как UTC не отражает изменения времени летнего времени, время, указанное (длина «недели» в часах), потому что оно основано на временах в центральном часовом поясе, на которые влияют изменения летнего времени. Эффективно весной неделя сокращается на один час, а осенью неделя удлиняется на один час, как вы можете видеть в приведенных моих примерах данных. – IceBox13
@MattJohnson: Я действительно не уверен в том, чтобы поместить это в Code Review. Учитывая, что мы просим людей показать, что они придумали до сих пор, похоже, что если есть код «просто о работе, но на самом деле это не хорошо», который не должен требовать перехода в CodeReview. Основой этого вопроса является «Как мне достичь X?» а не «Пожалуйста, просмотрите мой код, который делает X». Но, как я уже сказал, я в двух умах ... –