Stéphanie Autire
Stéphanie Autire

Reputation: 129

Get time left until sunday 9:30 pm

What I want to do is basically in the question title.

This is what I've tried so far, unsuccessfully.

Note that I haven't implemented exact hour and minute yet (9:30 pm).

It actually seems to always return a value between 00:00:59 and 00:00:01 for some reason

DateTime nextSunday = DateTime.Today.AddDays(((int)DayOfWeek.Sunday - (int)DateTime.Today.DayOfWeek + 7) % 7) + new TimeSpan(21, 30, 0);
TimeSpan untilNextSunday = nextSunday - DateTime.Now;

await ReplyAsync($"It is in **{TimeSpan.FromSeconds(untilNextSunday.Seconds)}**");

Which equals to

var today = DateTime.Today;
var daysUntilSunday = ((int)DayOfWeek.Sunday - (int)today.DayOfWeek + 7) % 7;
var nextSunday = today.AddDays(daysUntilSunday);
var ts = new TimeSpan(21, 30, 0);
nextSunday = nextSunday.Date + ts;

TimeSpan untilNextSunday = nextSunday - DateTime.Now;

If possible, I'd also like to use Paris TimeZone.

Upvotes: 1

Views: 283

Answers (2)

Jon Skeet
Jon Skeet

Reputation: 1500665

Here's an example using Noda Time, including time zone handling. It doesn't attempt to handle "interesting" situations where (say) you ask for the next 1:30am, and it's already 1:45am but the clock goes back at 2am - in which case the right answer is really "45 minutes" but this code will give you a week instead.

using System;
using NodaTime;

class Test
{
    static void Main()
    {
        var duration = GetDurationToNext(
            IsoDayOfWeek.Sunday, new LocalTime(21, 30),
            DateTimeZoneProviders.Tzdb["Europe/Paris"],
            SystemClock.Instance);

        Console.WriteLine($"Duration: {duration}");
    }

    static Duration GetDurationToNext(
        IsoDayOfWeek dayOfWeek,
        LocalTime timeOfDay,
        DateTimeZone zone,
        IClock clock) // Or just take an instant
    {
        var now = clock.GetCurrentInstant();
        var localNow = now.InZone(zone).LocalDateTime;

        var localNext = localNow
            .Date.With(DateAdjusters.NextOrSame(dayOfWeek))
            .At(timeOfDay);
        // Handle "we're already on the right day-of-week, but
        // later in the day"
        if (localNext <= localNow)
        {
            localNext = localNext.PlusWeeks(1);
        }

        var zonedNext = localNext.InZoneLeniently(zone);
        var instantNext = zonedNext.ToInstant();
        return instantNext - now;
    }
}

Upvotes: 1

Enigmativity
Enigmativity

Reputation: 117064

I tend to find all of the DateTime.Today.AddDays(((int)DayOfWeek.Sunday - (int)DateTime.Today.DayOfWeek + 7) % 7) + new TimeSpan(21, 30, 0) arithmetic quite confusing. Instead I try to go with a more iterative approach that can be clearly reasoned about.

Try this:

public static DateTime GetNextDateTime(DateTime now, DayOfWeek targetDay, TimeSpan targetTime)
{
    DateTime target = now.Date.Add(targetTime);

    while (target < now || target.DayOfWeek != targetDay)
    {
        target = target.AddDays(1.0);
    }

    return target;
}

Now you can use it like this:

DateTime now = DateTime.Now;
DateTime target = GetNextDateTime(DateTime.Now, DayOfWeek.Sunday, new TimeSpan(21, 30, 0));
TimeSpan untilNextSunday = target.Subtract(now);

Upvotes: 1

Related Questions