The following will work in .NET 6 or newer:
// Get the current time, in the specified time zone.
var tz = TimeZoneInfo.FindSystemTimeZoneById("America/Chicago");
var now = TimeZoneInfo.ConvertTime(DateTime.UtcNow, tz);
// Get the target as a DateTime, using tomorrow's date, and the desired time.
var tomorrow = DateOnly.FromDateTime(now).AddDays(1);
var time = new TimeOnly(7, 0);
var dt = tomorrow.ToDateTime(time);
// You can now get a DateTimeOffset in the desired time zone.
var dto = new DateTimeOffset(dt, tz.GetUtcOffset(dt));
If you're using older .NET, then you can use this instead:
// Get the current time, in the specified time zone.
var tz = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
var now = TimeZoneInfo.ConvertTime(DateTime.UtcNow, tz);
// Get the target as a DateTime, using tomorrow's date, and the desired time.
var tomorrow = now.Date.AddDays(1);
var dt = tomorrow.AddHours(7);
// You can now get a DateTimeOffset in the desired time zone.
var dto = new DateTimeOffset(dt, tz.GetUtcOffset(dt));
(The second example will work in newer .NET also, but the first is more correct and idiomatic for modern .NET.)
Important:
With either implementation, this will use the default behavior of TimeZoneInfo.GetUtcOffset(DateTime), which in the case of invalid or ambiguous input, returns the standard time offset, not the daylight time offset. If you are possibly using a time of day that is near a DST transition, then you may wish to consider taking control over that default behavior. You can do this using an extension method such as the following (which I've posted on many other answers now, and also proposed as a built-in API.):
public static DateTimeOffset ToDateTimeOffset(this DateTime dt, TimeZoneInfo tz)
{
if (dt.Kind != DateTimeKind.Unspecified)
{
// Handle UTC or Local kinds (regular and hidden 4th kind)
DateTimeOffset dto = new DateTimeOffset(dt.ToUniversalTime(), TimeSpan.Zero);
return TimeZoneInfo.ConvertTime(dto, tz);
}
if (tz.IsAmbiguousTime(dt))
{
// Prefer the daylight offset, because it comes first sequentially (1:30 ET becomes 1:30 EDT)
TimeSpan[] offsets = tz.GetAmbiguousTimeOffsets(dt);
TimeSpan offset = offsets[0] > offsets[1] ? offsets[0] : offsets[1];
return new DateTimeOffset(dt, offset);
}
if (tz.IsInvalidTime(dt))
{
// Advance by the gap, and return with the daylight offset (2:30 ET becomes 3:30 EDT)
TimeSpan[] offsets = { tz.GetUtcOffset(dt.AddDays(-1)), tz.GetUtcOffset(dt.AddDays(1)) };
TimeSpan gap = offsets[1] - offsets[0];
return new DateTimeOffset(dt.Add(gap), offsets[1]);
}
// Simple case
return new DateTimeOffset(dt, tz.GetUtcOffset(dt));
}
Put that in a static class somewhere, then you can adjust the last line of the original code I gave at the top of this answer to the following:
var dto = dt.ToDateTimeOffset(tz);
DateTimeKind.Localand your system is not actually in central standard time, theDateTimeOffsetconstructor will throw an exception. UsingDateTimeKind.Unspecifiedseems to work better.