C
C#14h ago
V0FBU1VM

Time conversion issue?

/// <summary>
/// Validates if the start and end times are in the future.
/// </summary>
/// <param name="date">The date of the shift (in local time).</param>
/// <param name="start">The start time of the shift (in local time).</param>
/// <param name="end">The end time of the shift (in local time).</param>
/// <returns>True if the shift is in the future; otherwise, false.</returns>
public static bool IsScheduledInFuture(DateTime date, TimeOnly start, TimeOnly end)
{
// Combine the provided date with the start and end times to create local DateTime values
var localStart = date.Date.Add(start.ToTimeSpan());
var localEnd = end > start
? date.Date.Add(end.ToTimeSpan()) // Same day
: date.Date.AddDays(1).Add(end.ToTimeSpan()); // Next day for overnight shifts

// Convert local times to UTC explicitly
var utcStart = localStart.ToUniversalTime();
var utcEnd = localEnd.ToUniversalTime();

// Get current UTC time
var now = DateTime.UtcNow;

// Ensure the shift starts and ends in the future
return utcStart > now && utcEnd > now;
}
/// <summary>
/// Validates if the start and end times are in the future.
/// </summary>
/// <param name="date">The date of the shift (in local time).</param>
/// <param name="start">The start time of the shift (in local time).</param>
/// <param name="end">The end time of the shift (in local time).</param>
/// <returns>True if the shift is in the future; otherwise, false.</returns>
public static bool IsScheduledInFuture(DateTime date, TimeOnly start, TimeOnly end)
{
// Combine the provided date with the start and end times to create local DateTime values
var localStart = date.Date.Add(start.ToTimeSpan());
var localEnd = end > start
? date.Date.Add(end.ToTimeSpan()) // Same day
: date.Date.AddDays(1).Add(end.ToTimeSpan()); // Next day for overnight shifts

// Convert local times to UTC explicitly
var utcStart = localStart.ToUniversalTime();
var utcEnd = localEnd.ToUniversalTime();

// Get current UTC time
var now = DateTime.UtcNow;

// Ensure the shift starts and ends in the future
return utcStart > now && utcEnd > now;
}
What am I missing here? The date, start and end are in local. For some reason this is returning true even though if the current start and end are in the past? I have written some tests, all of them are passing locally. When testing from the client, the behavior is not the same. The client is calling the server.
6 Replies
Jimmacle
Jimmacle14h ago
i recommend not using datetime, use datetimeoffset at least because that actually stores offset information there is probably an issue with differences in the time set on the different machines
V0FBU1VM
V0FBU1VMOP14h ago
I can try that out and see. Should I have stored the start and end as DateTimeOffset instead of TimeOnly?
/// <summary>
/// Represents a shift in the system.
/// </summary>
public sealed partial class Shift : Entity, IArchivable
{
/// <summary>
/// The time the shift starts. Defaults to <see cref="TimeOnly.MinValue" /> (00:00:00).
/// </summary>
public TimeOnly StartsAt { get; set; } = TimeOnly.MinValue;

/// <summary>
/// The time the shift ends. Defaults to <see cref="TimeOnly.MinValue" /> (00:00:00).
/// </summary>
public TimeOnly EndsAt { get; set; } = TimeOnly.MinValue;

/// <summary>
/// The duration of the break allocated during the shift.
/// Defaults to <see cref="TimeSpan.Zero" /> (0 hours, 0 minutes).
/// </summary>
public TimeSpan Break { get; set; } = TimeSpan.Zero;

/// <summary>
/// The duration of any overtime allocated during the shift.
/// Defaults to <see cref="TimeSpan.Zero" /> (0 hours, 0 minutes).
/// </summary>
public TimeSpan Overtime { get; set; } = TimeSpan.Zero;

/// <summary>
/// The date the shift occurs on. Defaults to <see cref="DateOnly.MinValue" />.
/// </summary>
public DateOnly Date { get; init; } = DateOnly.MinValue;
}
/// <summary>
/// Represents a shift in the system.
/// </summary>
public sealed partial class Shift : Entity, IArchivable
{
/// <summary>
/// The time the shift starts. Defaults to <see cref="TimeOnly.MinValue" /> (00:00:00).
/// </summary>
public TimeOnly StartsAt { get; set; } = TimeOnly.MinValue;

/// <summary>
/// The time the shift ends. Defaults to <see cref="TimeOnly.MinValue" /> (00:00:00).
/// </summary>
public TimeOnly EndsAt { get; set; } = TimeOnly.MinValue;

/// <summary>
/// The duration of the break allocated during the shift.
/// Defaults to <see cref="TimeSpan.Zero" /> (0 hours, 0 minutes).
/// </summary>
public TimeSpan Break { get; set; } = TimeSpan.Zero;

/// <summary>
/// The duration of any overtime allocated during the shift.
/// Defaults to <see cref="TimeSpan.Zero" /> (0 hours, 0 minutes).
/// </summary>
public TimeSpan Overtime { get; set; } = TimeSpan.Zero;

/// <summary>
/// The date the shift occurs on. Defaults to <see cref="DateOnly.MinValue" />.
/// </summary>
public DateOnly Date { get; init; } = DateOnly.MinValue;
}
I thought this would be enough.
Jimmacle
Jimmacle14h ago
it depends, do you need to account for time zone changes when handling them?
V0FBU1VM
V0FBU1VMOP14h ago
Not really, the problem is that sometimes I need to make sure that details are in future. The thing is that I don't want to store the start and end as utc or the date. It's leading to some issues when creating stuff or querying. During validation, I need to absolutely make sure that stuff are not in the past. Maybe I should remove date and just have start and end as DateTimeOffset. Since sometimes you can have an overnight shift.
Jimmacle
Jimmacle14h ago
unless shifts can be longer than 24 hours timeonly would probably be fine?
V0FBU1VM
V0FBU1VMOP14h ago
No, the shifts cannot be longer then 24 hours. Ok. thank you very much for the input. I will look into some more options and decide.
Want results from more Discord servers?
Add your server