2015-11-05 49 views
3

在我们的ASP.NET MVC 5应用程序中,我们拥有带有时区ID(IANA)的用户配置文件。如何从NodaTime的偏移量中获取所有IANA时区?

public class User 
{ 
    public int Id { get; set; } 
    public string TimeZoneId { get; set; } 
} 

任务是在当地时间早上6点向所有用户发送电子邮件。我们的计划是每小时向当地时间早上6点(根据服务器的UTC时间计算)的所有时区发送电子邮件。

由于我们只有时区ID才能通过,因此我希望得到相应的时区ID,例如,考虑到DST,可以获得偏移量-4:00:00 -

string[] timezoneIds; 

然后我可以查询我的数据库,像这样:

db.Users.Where(x => timezoneIds.Contains(x.TimeZoneId)); 

我的问题是,很明显,这是一个不错的主意,或是否有针对此问题的最佳做法,我不知道呢?

谢谢。

回答

3

你可以尝试以下方法:

首先创建一个字典,所有的偏移和属于该时区偏移

Instant now = SystemClock.Instance.Now; 
IDateTimeZoneProvider timeZoneProvider = DateTimeZoneProviders.Tzdb; 
Dictionary<TimeSpan, List<string>> timezonesForOffset = new Dictionary<TimeSpan, List<string>>(); 
foreach(var id in timeZoneProvider.Ids){ 
    ZonedDateTime zdt = now.InZone(timeZoneProvider[id]); 
    var timespan = zdt.Offset.ToTimeSpan(); 
    if(timezonesForOffset.ContainsKey(timespan)){ 
     timezonesForOffset[timespan].Add(id); 
    } else { 
     timezonesForOffset[timespan] = new List<string> {id, }; 
    } 
} 

你做了之后,你可以使用下面的代码片段来获取所有一定的时区

var timespan2 = new TimeSpan(1,0,0); 
var timezonesWithOffset = timezonesForOffset[timespan2]; 

var usersinTimezone = db.Users.Where(x=> timezonesWithOffset.Contains(x.TimezoneId)).ToList(); 

这将让所有用户在时区UTC + 1

内的用户为
+0

这种方法很好,但考虑属特德SQL可能相当大,取决于匹配的时区数量。另外,如果代码提前运行,那么一定要在实际执行时间内传递正确的“即时”,而不是“现在”。 –

+0

噢,我相信它可以和字典中的Offset'键一样使用,而不是它真的很重要。 ;) –

6

简单的代码了 “建设一个字典”,塞尔显示:使用LINQ的查找,DateTimeZone.GetUtcOffset,并Offset键,而不是TimeSpan值:

var now = SystemClock.Instance.Now; 
var provider = DateTimeZoneProviders.Tzdb; 
var idsByCurrentOffset = provider.Ids.ToLookup(id => provider[id].GetUtcOffset(now)); 

然后你可以使用:

var offset = Offset.FromHours(5); 
foreach (var id in idsByCurrentOffset[offset]) 
{ 
    ... 
} 

(你甚至不需要首先检查存在性,因为查找索引器在返回一个空序列时,如果在查找中不存在一个键时出现)。