Skip to content

Commit

Permalink
Working on getting dates/times to work consistently regardless of mac…
Browse files Browse the repository at this point in the history
…hine timezone (in docker or in visualstudio)
  • Loading branch information
ardalis committed Mar 30, 2021
1 parent 8af807d commit 9db5520
Show file tree
Hide file tree
Showing 30 changed files with 443 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class CreateAppointmentRequest : BaseRequest
public int AppointmentTypeId { get; set; }
public int ClientId { get; set; }
public int RoomId { get; set; }
public DateTime DateOfAppointment { get; set; }
public DateTimeOffset DateOfAppointment { get; set; }
public int SelectedDoctor { get; set; }
public string Details { get; set; }
}
Expand Down
4 changes: 2 additions & 2 deletions FrontDesk/src/FrontDesk.Api/Endpoints/Appointment/Create.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ public override async Task<ActionResult<CreateAppointmentResponse>> HandleAsync(
var schedule = await _scheduleReadRepository.GetBySpecAsync(spec);

var appointmentType = await _appointmentTypeRepository.GetByIdAsync(request.AppointmentTypeId);
var appointmentStart = request.DateOfAppointment.ToLocalTime();
var timeRange = new DateTimeRange(appointmentStart, TimeSpan.FromMinutes(appointmentType.Duration));
var appointmentStart = request.DateOfAppointment;
var timeRange = new DateTimeOffsetRange(appointmentStart, TimeSpan.FromMinutes(appointmentType.Duration));

var newAppointment = new Appointment(request.AppointmentTypeId, request.ScheduleId, request.ClientId, request.SelectedDoctor, request.PatientId, request.RoomId, timeRange, request.Details);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public override async Task<ActionResult<UpdateAppointmentResponse>> HandleAsync(
var apptToUpdate = schedule.Appointments.FirstOrDefault(a => a.Id == request.Id);
apptToUpdate.UpdateAppointmentType(apptType);
apptToUpdate.UpdateRoom(request.RoomId);
apptToUpdate.UpdateStartTime(request.Start.ToLocalTime());
apptToUpdate.UpdateStartTime(request.Start);
apptToUpdate.UpdateTitle(request.Title);
apptToUpdate.UpdateDoctor(request.DoctorId);

Expand Down
8 changes: 4 additions & 4 deletions FrontDesk/src/FrontDesk.Api/FrontDesk.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.10.9" />
<PackageReference Include="MediatR" Version="9.0.0" />
<PackageReference Include="PluralsightDdd.SharedKernel" Version="1.1.4" />
<PackageReference Include="PluralsightDdd.SharedKernel" Version="1.2.2" />
<PackageReference Include="RabbitMQ.Client" Version="6.2.1" />
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.3" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.1.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.1.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.1.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.1.1" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.1.1" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.4" />
</ItemGroup>

Expand Down
6 changes: 5 additions & 1 deletion FrontDesk/src/FrontDesk.Api/OfficeSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ namespace FrontDesk.Api
public class OfficeSettings : IApplicationSettings
{
public int ClinicId { get { return 1; } }
public DateTime TestDate { get { return new DateTime(2030, 9, 23); } }
public DateTimeOffset TestDate { get
{
return new DateTimeOffset(2030, 9, 23, 0, 0, 0, new TimeSpan(-4, 0, 0));
}
}
}
}
1 change: 1 addition & 0 deletions FrontDesk/src/FrontDesk.Blazor/wwwroot/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@
],
workWeekEnd: 6,
timezone: "America/Detroit",
//timezone: "Etc/UTC",
dataSource: viewModel.schedulerData,
dataBound: onDataBound,
eventTemplate: kendo.template($("#event-template").html()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class CreateConfirmationEmailMessage : IApplicationEvent
public string PatientName { get; set; }
public string DoctorName { get; set; }
public string AppointmentType { get; set; }
public DateTime AppointmentStartDateTime { get; set; }
public DateTimeOffset AppointmentStartDateTime { get; set; }

public string EventType => nameof(CreateConfirmationEmailMessage);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,10 @@ public AppointmentScheduledEvent(Appointment appointment) : this()
public AppointmentScheduledEvent()
{
this.Id = Guid.NewGuid();
DateTimeEventOccurred = DateTime.Now;
}

public Guid Id { get; private set; }

public DateTime DateTimeEventOccurred { get; private set; }

public Appointment AppointmentScheduled { get; private set; }
}
}
4 changes: 2 additions & 2 deletions FrontDesk/src/FrontDesk.Core/FrontDesk.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
<PackageReference Include="Ardalis.GuardClauses" Version="3.1.0" />
<PackageReference Include="Ardalis.Result" Version="3.1.1" />
<PackageReference Include="MediatR" Version="9.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="PluralsightDdd.SharedKernel" Version="1.1.4" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="PluralsightDdd.SharedKernel" Version="1.2.2" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
using System;
using System;

namespace FrontDesk.Core.Interfaces
{
public interface IApplicationSettings
{
int ClinicId { get; }
DateTime TestDate { get; }
DateTimeOffset TestDate { get; }
}
}
}
13 changes: 6 additions & 7 deletions FrontDesk/src/FrontDesk.Core/ScheduleAggregate/Appointment.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.ComponentModel.DataAnnotations.Schema;
using Ardalis.GuardClauses;
using FrontDesk.Core.Events;
using PluralsightDdd.SharedKernel;
Expand All @@ -15,9 +14,9 @@ public class Appointment : BaseEntity<Guid>
public int DoctorId { get; private set; }
public int AppointmentTypeId { get; private set; }

public DateTimeRange TimeRange { get; private set; }
public DateTimeOffsetRange TimeRange { get; private set; }
public string Title { get; private set; }
public DateTime? DateTimeConfirmed { get; set; }
public DateTimeOffset? DateTimeConfirmed { get; set; }
public bool IsPotentiallyConflicting { get; set; }

// EF https://github.com/dotnet/efcore/issues/12078#issuecomment-498379223
Expand All @@ -27,7 +26,7 @@ public Appointment(int appointmentTypeId,
int doctorId,
int patientId,
int roomId,
DateTimeRange timeRange, // EF Core 5 cannot provide this type
DateTimeOffsetRange timeRange, // EF Core 5 cannot provide this type
string title,
DateTime? dateTimeConfirmed = null)
{
Expand Down Expand Up @@ -71,11 +70,11 @@ public void UpdateDoctor(int newDoctorId)
Events.Add(appointmentUpdatedEvent);
}

public void UpdateStartTime(DateTime newStartTime)
public void UpdateStartTime(DateTimeOffset newStartTime)
{
if (newStartTime == TimeRange.Start) return;

TimeRange = new DateTimeRange(newStartTime, TimeSpan.FromMinutes(TimeRange.DurationInMinutes()));
TimeRange = new DateTimeOffsetRange(newStartTime, TimeSpan.FromMinutes(TimeRange.DurationInMinutes()));

var appointmentUpdatedEvent = new AppointmentUpdatedEvent(this);
Events.Add(appointmentUpdatedEvent);
Expand Down Expand Up @@ -103,7 +102,7 @@ public void UpdateAppointmentType(AppointmentType appointmentType)
Events.Add(appointmentUpdatedEvent);
}

public void Confirm(DateTime dateConfirmed)
public void Confirm(DateTimeOffset dateConfirmed)
{
if (DateTimeConfirmed.HasValue) return; // no need to reconfirm

Expand Down
4 changes: 2 additions & 2 deletions FrontDesk/src/FrontDesk.Core/ScheduleAggregate/Schedule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace FrontDesk.Core.Aggregates
public class Schedule : BaseEntity<Guid>, IAggregateRoot
{
public Schedule(Guid id,
DateTimeRange dateRange,
DateTimeOffsetRange dateRange,
int clinicId,
IEnumerable<Appointment> appointments)
{
Expand All @@ -33,7 +33,7 @@ public Schedule(Guid id,

// not persisted
[NotMapped]
public virtual DateTimeRange DateRange { get; private set; }
public virtual DateTimeOffsetRange DateRange { get; private set; }
private readonly List<Appointment> _appointments = new List<Appointment>();
public IEnumerable<Appointment> Appointments => _appointments.AsReadOnly();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ namespace FrontDesk.Core.Specifications
{
public class ScheduleForClinicAndDateWithAppointmentsSpec : Specification<Schedule>, ISingleResultSpecification
{
public ScheduleForClinicAndDateWithAppointmentsSpec(int clinicId, DateTime date)
public ScheduleForClinicAndDateWithAppointmentsSpec(int clinicId, DateTimeOffset date)
{
Query
.Include(nameof(Schedule.Appointments))
.Where(schedule =>
schedule.ClinicId == clinicId &&
schedule.Appointments != null &&
schedule.Appointments.Any(appointment => ((DateTime?)appointment.TimeRange.Start).Value.Date == ((DateTime?)date).Value.Date));
schedule.Appointments.Any(appointment => appointment.TimeRange.Start.Date == date.Date));
}
}
}
33 changes: 33 additions & 0 deletions FrontDesk/src/FrontDesk.Infrastructure/Data/AppDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using FrontDesk.Core.Aggregates;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using PluralsightDdd.SharedKernel;

namespace FrontDesk.Infrastructure.Data
Expand All @@ -32,6 +33,38 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
//StoreDatesInUtc(modelBuilder);
}

private void StoreDatesInUtc(ModelBuilder builder)
{
var dateTimeConverter = new ValueConverter<DateTime, DateTime>(
v => v.ToUniversalTime(),
v => DateTime.SpecifyKind(v, DateTimeKind.Utc));

var nullableDateTimeConverter = new ValueConverter<DateTime?, DateTime?>(
v => v.HasValue ? v.Value.ToUniversalTime() : v,
v => v.HasValue ? DateTime.SpecifyKind(v.Value, DateTimeKind.Utc) : v);

foreach (var entityType in builder.Model.GetEntityTypes())
{
if (entityType.IsKeyless)
{
continue;
}

foreach (var property in entityType.GetProperties())
{
if (property.ClrType == typeof(DateTime))
{
property.SetValueConverter(dateTimeConverter);
}
else if (property.ClrType == typeof(DateTime?))
{
property.SetValueConverter(nullableDateTimeConverter);
}
}
}
}

public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
Expand Down
18 changes: 9 additions & 9 deletions FrontDesk/src/FrontDesk.Infrastructure/Data/AppDbContextSeed.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class AppDbContextSeed
private Doctor DrWho => new Doctor(2, "Dr. Who");
private Doctor DrMcDreamy => new Doctor(3, "Dr. McDreamy");
private readonly Guid _scheduleId = Guid.Parse("f9369039-9d11-4442-9738-ed65d8a8ad52");
private DateTime _testDate = DateTime.Now;
private DateTimeOffset _testDate = DateTime.UtcNow.Date;
public const string MALE_SEX = "Male";
public const string FEMALE_SEX = "Female";
private readonly AppDbContext _context;
Expand All @@ -37,9 +37,9 @@ public AppDbContextSeed(AppDbContext context,
_logger = logger;
}

public async Task SeedAsync(DateTime testDate, int? retry = 0)
public async Task SeedAsync(DateTimeOffset testDate, int? retry = 0)
{
_logger.LogInformation($"Seeding data.");
_logger.LogInformation($"Seeding data - testDate: {testDate}");
_logger.LogInformation($"DbContext Type: {_context.Database.ProviderName}");

_testDate = testDate;
Expand Down Expand Up @@ -143,7 +143,7 @@ private List<RoomDto> GetDefaultRooms()

private Schedule CreateSchedule()
{
return new Schedule(_scheduleId, new DateTimeRange(_testDate, _testDate), 1, null);
return new Schedule(_scheduleId, new DateTimeOffsetRange(_testDate, _testDate), 1, null);
}

private async Task<List<AppointmentType>> CreateAppointmentTypes()
Expand Down Expand Up @@ -272,7 +272,7 @@ private IEnumerable<Appointment> CreateAppointments(Guid scheduleId)
DrSmith.Id,
_darwin.Id,
room1,
new DateTimeRange(_testDate.AddHours(10), TimeSpan.FromMinutes(30)),
new DateTimeOffsetRange(_testDate.AddHours(10), TimeSpan.FromMinutes(30)),
"(WE) Darwin - Steve Smith"),
new Appointment(
wellnessVisit,
Expand All @@ -281,7 +281,7 @@ private IEnumerable<Appointment> CreateAppointments(Guid scheduleId)
DrSmith.Id,
_steve.Patients[1].Id,
room1,
new DateTimeRange(_testDate.AddHours(10).AddMinutes(30), TimeSpan.FromMinutes(30)),
new DateTimeOffsetRange(_testDate.AddHours(10).AddMinutes(30), TimeSpan.FromMinutes(30)),
"(WE) Arya - Steve Smith"),
new Appointment(
wellnessVisit,
Expand All @@ -290,7 +290,7 @@ private IEnumerable<Appointment> CreateAppointments(Guid scheduleId)
DrSmith.Id,
_steve.Patients[2].Id,
room1,
new DateTimeRange(_testDate.AddHours(11), TimeSpan.FromMinutes(30)),
new DateTimeOffsetRange(_testDate.AddHours(11), TimeSpan.FromMinutes(30)),
"(WE) Rosie - Steve Smith"),
new Appointment(
diagnosticVisit,
Expand All @@ -299,7 +299,7 @@ private IEnumerable<Appointment> CreateAppointments(Guid scheduleId)
DrWho.Id,
_sampson.Id,
room2,
new DateTimeRange(_testDate.AddHours(11), TimeSpan.FromMinutes(60)),
new DateTimeOffsetRange(_testDate.AddHours(11), TimeSpan.FromMinutes(60)),
"(DE) Sampson - Julie Lerman")
};

Expand All @@ -325,7 +325,7 @@ private Appointment CreateAppointment(Guid scheduleId, string clientName, string
{
var client = _context.Clients.First(c => c.FullName == clientName);
var patient = _context.Patients.First(p => p.Name == patientName);
var appt = new Appointment(diagnosticVisit, scheduleId, client.Id, patient.PreferredDoctorId.Value, patient.Id, roomId, new DateTimeRange(_testDate.AddHours(hour), TimeSpan.FromMinutes(60)), $"(DE) {patientName} - {clientName}");
var appt = new Appointment(diagnosticVisit, scheduleId, client.Id, patient.PreferredDoctorId.Value, patient.Id, roomId, new DateTimeOffsetRange(_testDate.AddHours(hour), TimeSpan.FromMinutes(60)), $"(DE) {patientName} - {clientName}");
return appt;
}
catch (Exception ex)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ public void Configure(EntityTypeBuilder<Appointment> builder)
builder.ToTable("Appointments").HasKey(x => x.Id);
builder.OwnsOne(p => p.TimeRange, p =>
{
p.Property(pp => pp.Start).HasColumnName("TimeRange_Start");
p.Property(pp => pp.End).HasColumnName("TimeRange_End");
p.Property(pp => pp.Start)
//.HasColumnType("datetimeoffset")
.HasColumnName("TimeRange_Start");
p.Property(pp => pp.End)
//.HasColumnType("datetimeoffset")
.HasColumnName("TimeRange_End");
});
builder.Property(p => p.Title)
.HasMaxLength(ColumnConstants.DEFAULT_NAME_LENGTH);
Expand Down
Loading

0 comments on commit 9db5520

Please sign in to comment.