C#数据库日期格式转换与查询适配问题咨询
解决方案
1. 处理用户输入的d/m/y格式日期
ASP.NET Core 默认 DateTime 绑定逻辑无法直接识别 dd/MM/yyyy 格式,需通过自定义模型绑定器实现正确解析:
自定义日期模型绑定器
public class DmyDateTimeModelBinder : IModelBinder { public Task BindModelAsync(ModelBindingContext bindingContext) { if (bindingContext == null) throw new ArgumentNullException(nameof(bindingContext)); var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); if (valueProviderResult == ValueProviderResult.None) return Task.CompletedTask; bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); var inputValue = valueProviderResult.FirstValue; if (string.IsNullOrEmpty(inputValue)) return Task.CompletedTask; // 解析dd/MM/yyyy格式日期 if (DateTime.TryParseExact(inputValue, "dd/MM/yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out var parsedDate)) { bindingContext.Result = ModelBindingResult.Success(parsedDate.Date); // 仅保留日期部分 } else { bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, "日期格式无效,请使用dd/MM/yyyy格式(如09/08/2022)"); } return Task.CompletedTask; } }
绑定API接口参数
修改接口参数,指定使用自定义绑定器:
[HttpGet("date/{date}")] [Produces("application/json")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] public async Task<ActionResult<Result>> GetPartySearchHistoriesByDate( [BindRequired] [FromRoute] [ModelBinder(BinderType = typeof(DmyDateTimeModelBinder))] DateTime date) { try { var items = await _mediator.Send(new GetPartySearchHistoriesByDateQuery() { Date = date }); return Result.Ok(new { MatchCount = items.Count, Matches = items }); } catch (Exception ex) { throw new SanctionException("获取记录时发生错误。", ex); } }
2. 修改数据库查询逻辑(匹配当天所有数据)
原SQL仅匹配精确时间,需改为查询当天0点至次日0点的范围,避免时间精度问题且能利用索引:
public async Task<List<PartySearchHistoryDto>> GetListByDateAsync(DateTime date) { IUnitOfWork unitOfWork = await _dbConnection.GetUnitOfWorkAsync(); unitOfWork.Begin(); try { var startOfDay = date.Date; var startOfNextDay = startOfDay.AddDays(1); var partySearchHistories = await unitOfWork .Connection .QueryAsync<PartySearchHistoryDto>( @"SELECT * FROM [dbo].[PartySearchHistories] WITH (NOLOCK) WHERE CreatedAt >= @startOfDay AND CreatedAt < @startOfNextDay AND IsDeleted = 0", new { startOfDay, startOfNextDay }, transaction: unitOfWork.Transaction); return partySearchHistories.ToList(); } catch (Exception) { return new List<PartySearchHistoryDto>(); } }
3. 格式化返回结果(dd/MM/yyyy HH:mm)
在ViewModel中添加格式化后的日期属性,直接返回给前端:
public class PartySearchHistoryVM { // 原有属性保留... public DateTime CreatedAt { get; set; } // 新增格式化日期属性 public string FormattedCreatedAt => CreatedAt.ToString("dd/MM/yyyy HH:mm", CultureInfo.InvariantCulture); }
若使用AutoMapper进行DTO到VM的转换,可通过映射配置实现:
CreateMap<PartySearchHistoryDto, PartySearchHistoryVM>() .ForMember(dest => dest.FormattedCreatedAt, opt => opt.MapFrom(src => src.CreatedAt.ToString("dd/MM/yyyy HH:mm", CultureInfo.InvariantCulture)));
额外提示
- 若需支持两位年份输入(如
09/08/22),可在模型绑定器中添加dd/MM/yy格式的解析逻辑。 - 模型绑定器会自动处理解析失败的情况,ASP.NET Core将返回400 Bad Request并包含错误信息。
- 若数据库
CreatedAt为datetimeoffset类型,需将输入日期转换为对应时区后再执行查询。
内容的提问来源于stack exchange,提问作者dogac
相关产品推荐
相关产品推荐

