Reputation: 129
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
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
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