我有一个要求,我有点困惑。我开始使用NodaTime,我认为这是最好的方式。
我有两个用户,User1和User2都位于两个不同的时区。例如,他们可以在当地时区的下午2点到5点之间见面。如果User2与User1的偏移量为+2小时,则重叠仅为1小时。我希望得到的小时数重叠(User1和User2的实际时间将是奖金。)
到目前为止我所拥有的只是:
var user1TimeZone = DateTimeZoneProviders.Tzdb.GetZoneOrNull(user1timezone);
var user2TimeZone = DateTimeZoneProviders.Tzdb.GetZoneOrNull(user2timeZone);
关于我应该如何开始解决这个问题的任何想法?
谢谢,
答案 0 :(得分:2)
首先,请注意每天都可能更改:不要将时区视为固定偏移量。
其次,请注意指定的本地时间(对于每个开始/结束)可能不会发生,或者可能发生两次。弄清楚你想要处理模糊和跳过的时间。
对于任何特定日期,我只会将用户的开始/结束时间转换为Instant
(通过ZonedDateTime
),然后您就可以找到重叠。这确实假设任何重叠发生在同一天,但是......实际情况并非如此。我即将开会,其中一位与会者在新西兰 - 这是3月14日在这里,但3月15日在那里。考虑到这一点相当棘手......
以下是相对简单案例的代码:
using NodaTime;
using System;
class Test
{
static void Main()
{
// My availability: 4pm-7pm in London
var jon = new Availability(
DateTimeZoneProviders.Tzdb["Europe/London"],
new LocalTime(16, 0, 0),
new LocalTime(19, 0, 0));
// My friend Richard's availability: 12pm-4pm in New York
var richard = new Availability(
DateTimeZoneProviders.Tzdb["America/New_York"],
new LocalTime(12, 0, 0),
new LocalTime(16, 0, 0));
// Let's look through all of March 2017...
var startDate = new LocalDate(2017, 3, 1);
var endDate = new LocalDate(2017, 4, 1);
for (LocalDate date = startDate; date < endDate; date = date.PlusDays(1))
{
var overlap = GetAvailableOverlap(date, jon, richard);
Console.WriteLine($"{date:yyyy-MM-dd}: {overlap:HH:mm}");
}
}
static Duration GetAvailableOverlap(
LocalDate date,
Availability avail1,
Availability avail2)
{
// TODO: Check that the rules of InZoneLeniently are what you want.
// Be careful, as you could end up with an end before a start...
var start1 = (date + avail1.Start).InZoneLeniently(avail1.Zone);
var end1 = (date + avail1.End).InZoneLeniently(avail1.Zone);
var start2 = (date + avail2.Start).InZoneLeniently(avail2.Zone);
var end2 = (date + avail2.End).InZoneLeniently(avail2.Zone);
var latestStart = Instant.Max(start1.ToInstant(), start2.ToInstant());
var earliestEnd = Instant.Min(end1.ToInstant(), end2.ToInstant());
// Never return a negative duration... return zero of there's no overlap.
// Noda Time should have Duration.Max really...
var overlap = earliestEnd - latestStart;
return overlap < Duration.Zero ? Duration.Zero : overlap;
}
}
public sealed class Availability
{
public DateTimeZone Zone { get; }
public LocalTime Start { get; }
public LocalTime End { get; }
public Availability(DateTimeZone zone, LocalTime start, LocalTime end)
{
Zone = zone;
Start = start;
End = end;
}
}
答案 1 :(得分:1)
如果您有服务器,则必须发送UTC然后进行比较。当您在客户端获得时间时,您必须将其转换为本地时间。这意味着,当第一个用户想要安排会议时,他将他的时间发送到UTC到服务器,然后当第二个用户得到这个时间时,他将把它转换成他当地的时间。
// First user sends UTC.
DateTime firstUserTime = DateTime.UtcNow;
// Second user gets time in his time zone.
DateTime secondUserTime = firstUserTime.ToLocalTime();