简体   繁体   English

使用NodaTime比较两个不同的时区时跨

[英]Comparing two different timezone timespans using NodaTime

I have a requirement which I'm getting a little confused about. 我有一个要求,对此有些困惑。 I started using NodaTime which I think is the best way to go. 我开始使用NodaTime,我认为这是最好的方法。

I have two users, User1 and User2 both in two different timezones. 我在两个不同的时区中都有两个用户,User1和User2。 They are available to meet between 2pm and 5pm for example, in their local timezones. 例如,他们可以在当地时区的下午2点至下午5点之间见面。 If User2 has an offset of +2 hours from User1, then the overlap is just 1 hour. 如果User2与User1的偏移量为+2小时,则重叠时间仅为1小时。 What I want to get the number of hours overlap (the actual time for User1 and User2 would be a bonus.) 我想要得到的小时数重叠(User1和User2的实际时间将是一个奖励。)

All I have got so far is: 到目前为止,我得到的是:

var user1TimeZone = DateTimeZoneProviders.Tzdb.GetZoneOrNull(user1timezone);
var user2TimeZone = DateTimeZoneProviders.Tzdb.GetZoneOrNull(user2timeZone);

Any thoughts on how I should even start tackling this problem? 关于我什至应该开始解决这个问题的任何想法?

Thanks, 谢谢,

Firstly, be aware that it could change each day: don't treat a time zone as a fixed offset. 首先,请注意它可能每天都在变化:不要将时区视为固定的偏移量。

Secondly, be aware that the local time specified (for each of start/end) may not even happen, or may happen twice. 其次,请注意,指定的本地时间(针对每个开始/结束)可能甚至不会发生,或者可能会发生两次。 Work out how you want to handle ambiguous and skipped times. 找出您要如何处理含糊不清的时间。

For any particular day, I would just convert they users' start/end times to Instant (via ZonedDateTime ) and then you can find the overlap. 对于任何特定的日子,我只要将其用户的开始/结束时间转换为Instant (通过ZonedDateTime )即可,然后您可以找到重叠部分。 This does assume that any overlap happens on the same day, however... that isn't the case in reality. 这确实假设任何重叠都发生在同一天,但是...实际上并非如此。 I'm having a meeting soon where one of the attendees is in New Zealand - it's March 14th here, but March 15th there. 我即将开会,其中一位与会者在新西兰-3月14日在这里,但3月15日在新西兰。 Accounting for that is rather trickier... 考虑到这一点比较棘手...

Here's code for the relatively simple case though: 这是相对简单的情况的代码:

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

If you have a server where you do that, you have to send UTC and then compare it. 如果您在服务器上执行此操作,则必须发送UTC,然后进行比较。 When you get the time on the client side you have to convert it into local. 当您有时间在客户端时,您必须将其转换为本地。 It means, that when first user wants to arrange a meeting, he sends his time into UTC to server, then when second user gets this time, he will convert it into his local time. 这意味着,当第一个用户想要安排会议时,他将自己的时间发送到UTC到服务器,然后,当第二个用户获得该时间时,他会将其转换为他的本地时间。

// First user sends UTC.
DateTime firstUserTime = DateTime.UtcNow;

// Second user gets time in his time zone.
DateTime secondUserTime = firstUserTime.ToLocalTime();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM