Skip to content

Commit

Permalink
Format DateTime strings as correct ISO8601 (#296)
Browse files Browse the repository at this point in the history
Fixes #295 

Turns out that the default string formatting of DateTime objects doesn't
conform to ISO8601, so even when the object is saved as UTC; the app
does not recognize it as UTC.
  • Loading branch information
duckth authored Nov 17, 2024
1 parent 6b947f4 commit af9c81e
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ private async Task AnonymizeUserAsync(User user)
user.Name = string.Empty;
user.Password = string.Empty;
user.Salt = string.Empty;
user.DateUpdated = DateTime.Now;
user.DateUpdated = DateTime.UtcNow;
user.PrivacyActivated = true;
user.UserState = UserState.Deleted;
await _context.SaveChangesAsync();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public async Task<IEnumerable<IssueVoucherResponse>> CreateVouchers(IssueVoucher
.Select(code => new Voucher
{
Code = code,
DateCreated = DateTime.Now,
DateCreated = DateTime.UtcNow,
Product = product,
Description = request.Description,
Requester = request.Requester
Expand Down
22 changes: 22 additions & 0 deletions coffeecard/CoffeeCard.Library/Utils/DateTimeConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace CoffeeCard.Library.Utils
{
public class DateTimeConverter : JsonConverter<DateTime>
{
private const string DateFormatIso8601 = "yyyy-MM-ddTHH:mm:ss.fffZ";

public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return DateTime.Parse(reader.GetString()!, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
}

public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToUniversalTime().ToString(DateFormatIso8601, CultureInfo.InvariantCulture));
}
}
}
60 changes: 60 additions & 0 deletions coffeecard/CoffeeCard.Tests.Unit/Utils/DateTimeConverterTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System;
using System.Text.Json;
using CoffeeCard.Library.Utils;
using Xunit;

namespace CoffeeCard.Tests.Unit.Utils
{
public class DateTimeConverterTests
{
private readonly JsonSerializerOptions _options;

public DateTimeConverterTests()
{
_options = new JsonSerializerOptions();
_options.Converters.Add(new DateTimeConverter());
}

[Fact]
public void Serialize_ShouldFormatDateTimeCorrectly()
{
// Arrange
var dateTime = new DateTime(2022, 1, 9, 21, 3, 52, millisecond: 123, DateTimeKind.Utc);
var expectedJson = "\"2022-01-09T21:03:52.123Z\"";

// Act
var json = JsonSerializer.Serialize(dateTime, _options);

// Assert
Assert.Equal(expectedJson, json);
}

[Fact]
public void Deserialize_ShouldParseDateTimeCorrectly()
{
// Arrange
var json = "\"2022-01-09T21:03:52Z\"";
var expectedDateTime = new DateTime(2022, 1, 9, 21, 3, 52, DateTimeKind.Utc);

// Act
var dateTime = JsonSerializer.Deserialize<DateTime>(json, _options);

// Assert
Assert.Equal(expectedDateTime, dateTime);
}

[Fact]
public void Serialize_Deserialize_RoundTrip_ShouldMatchOriginalDateTime()
{
// Arrange
var originalDateTime = new DateTime(2022, 1, 9, 21, 3, 52, DateTimeKind.Utc);

// Act
var json = JsonSerializer.Serialize(originalDateTime, _options);
var deserializedDateTime = JsonSerializer.Deserialize<DateTime>(json, _options);

// Assert
Assert.Equal(originalDateTime, deserializedDateTime);
}
}
}
1 change: 1 addition & 0 deletions coffeecard/CoffeeCard.WebApi/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ public void ConfigureServices(IServiceCollection services)
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.Never;
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
options.JsonSerializerOptions.Converters.Add(new DateTimeConverter());
});

services.AddCors(options => options.AddDefaultPolicy(builder =>
Expand Down

0 comments on commit af9c81e

Please sign in to comment.