UTC 日期的 C# 服务器端管理
C# Server-side management of dates in UTC
我正在开发 .Net Core 3.1 REST Api。
我对接近午夜的日期和时区有疑问。
我以 UTC 格式将所有数据保存在数据库中,前端调用 API 以 UTC 格式传递时间。
我目前在GTM+2时区。
我必须将用户执行的 'actions' 分成不同的日子。
输出示例:
{
days: [
{
day: '2021-10-28',
actions: [
{
id: 123456,
actionType: 1,
startDate: '2021-10-28T12:04:12Z',
endDate: '2021-10-28T13:04:39Z'
},
{
...
}
],
actualHours: 1,
expectedHours: 4
},
{
day: '2021-10-29',
actions: [
{
id: 123467,
actionType: 1,
startDate: '2021-10-29T12:00:45Z',
endDate: '2021-10-29T14:00:40Z'
},
{
...
}
],
actualHours: 2,
expectedHours: 4
}
]
}
当我们的时间接近午夜时会出现问题,因为在数据库中,这一天将保存为用户输入的前一天。
添加一整天操作的用户示例。
前端:
- 开始日期:2021-10-28T00:00:00.000
- 结束日期:2021-10-28T23:59:59.999
Json 请求:
{
actionType: 1,
startDate: '2021-10-27T22:00:00.000Z',
endDate: '2021-10-28T21:59:59.999Z'
}
在数据库中,日期将保存为:
- 开始日期:2021-10-27T22:00:00.000Z
- 结束日期:2021-10-28T21:59:59.999Z
为了采取行动并将它们按天分开我写了这个代码片段..
public async Task<IList<DailyActionItem>> GetAsync(string userId, DateTime startDate, DateTime? endDate)
{
// Other code here..
// Get actions by dates
var tActions = await _actionsQuery.GetPeriodAsync(userId, startDate, endDate).ConfigureAwait(false);
// Create a list of days
var days = new List<DailyActionItem>();
// Cycling the range of dates and also adding the missing days
var ed = endDate.HasValue ? endDate.Value.Date : DateTime.UtcNow.Date;
for (var sd = startDate.Date; sd <= ed; sd = sd.AddDays(1))
{
var daily = new DailyActionItem
{
Day = sd.Date,
Actions = new List<ActionItem>()
};
// Other code here..
var actions = tActions
.Where(t => (t.StartDate <= sd.AddDays(1).AddTicks(-1) && t.StartDate >= sd) ||
(t.StartDate <= sd.AddDays(1).AddTicks(-1) && t.EndDate.HasValue && t.EndDate >= sd))
.OrderBy(c => c.StartDate);
// Add actions nella risposta e calcolo i valori attuali
if (actions?.Any() == true)
{
foreach (var action in actions)
{
daily.Actions.Add(new ActionItem
{
Id = action.Id,
ActionType = action.ActionType,
StartDate = action.StartDate,
EndDate = action.EndDate,
Comment = action.Comment
});
}
// Other code here..
}
// Important: calculations made on the day
daily.ActualHours = tActions.Sum(...);
daily.ExpectedHours = contract.ExpectedHours;
// Other code here..
days.Add(daily);
}
return days;
}
调试示例(单日 - 2021-10-28 从 00:00 本地到 23:59 本地):
- 开始日期:2021-10-27T22:00:00.000Z
- 结束日期:2021-10-28T21:59:59.999Z
在foreach中:
第一轮 -> sd = 2021-10-27T00:00:00.000Z
最后一轮 -> sd = 2021-10-28T00:00:00.000Z
输出:
{
days: [
{
day: '2021-10-27',
actions: [
{
id: 123987,
actionType: 1,
startDate: '2021-10-27T22:00:00.000Z',
endDate: '2021-10-28T21:59:59.999Z'
}
],
actualHours: 24, // full day, wrong place!
expectedHours: 4
},
{
day: '2021-10-28',
actions: [
{
...
},
{
...
}
]
}
]
}
由于 APIs 在 UTC 中工作,此代码根据 UTC 中的值拆分日期。
例如,输入“2021-10-28T00:00:00.000 LOCAL”的最后一天将置于“2021-10-27 UTC”这一天之下。
我该如何解决这个问题?我错过了什么?
管理这些案例的最佳方法是什么?
理论上结果是正确的。
但是前端读取数据不正确
看起来像一个奇怪的错误。我建议在任何地方将 DateTime
替换为 DateTimeOffset
,进行数据库迁移并更新数据库。
如果上述方法不起作用,请告诉我。
我正在开发 .Net Core 3.1 REST Api。
我对接近午夜的日期和时区有疑问。
我以 UTC 格式将所有数据保存在数据库中,前端调用 API 以 UTC 格式传递时间。
我目前在GTM+2时区。
我必须将用户执行的 'actions' 分成不同的日子。
输出示例:
{
days: [
{
day: '2021-10-28',
actions: [
{
id: 123456,
actionType: 1,
startDate: '2021-10-28T12:04:12Z',
endDate: '2021-10-28T13:04:39Z'
},
{
...
}
],
actualHours: 1,
expectedHours: 4
},
{
day: '2021-10-29',
actions: [
{
id: 123467,
actionType: 1,
startDate: '2021-10-29T12:00:45Z',
endDate: '2021-10-29T14:00:40Z'
},
{
...
}
],
actualHours: 2,
expectedHours: 4
}
]
}
当我们的时间接近午夜时会出现问题,因为在数据库中,这一天将保存为用户输入的前一天。
添加一整天操作的用户示例。
前端:
- 开始日期:2021-10-28T00:00:00.000
- 结束日期:2021-10-28T23:59:59.999
Json 请求:
{
actionType: 1,
startDate: '2021-10-27T22:00:00.000Z',
endDate: '2021-10-28T21:59:59.999Z'
}
在数据库中,日期将保存为:
- 开始日期:2021-10-27T22:00:00.000Z
- 结束日期:2021-10-28T21:59:59.999Z
为了采取行动并将它们按天分开我写了这个代码片段..
public async Task<IList<DailyActionItem>> GetAsync(string userId, DateTime startDate, DateTime? endDate)
{
// Other code here..
// Get actions by dates
var tActions = await _actionsQuery.GetPeriodAsync(userId, startDate, endDate).ConfigureAwait(false);
// Create a list of days
var days = new List<DailyActionItem>();
// Cycling the range of dates and also adding the missing days
var ed = endDate.HasValue ? endDate.Value.Date : DateTime.UtcNow.Date;
for (var sd = startDate.Date; sd <= ed; sd = sd.AddDays(1))
{
var daily = new DailyActionItem
{
Day = sd.Date,
Actions = new List<ActionItem>()
};
// Other code here..
var actions = tActions
.Where(t => (t.StartDate <= sd.AddDays(1).AddTicks(-1) && t.StartDate >= sd) ||
(t.StartDate <= sd.AddDays(1).AddTicks(-1) && t.EndDate.HasValue && t.EndDate >= sd))
.OrderBy(c => c.StartDate);
// Add actions nella risposta e calcolo i valori attuali
if (actions?.Any() == true)
{
foreach (var action in actions)
{
daily.Actions.Add(new ActionItem
{
Id = action.Id,
ActionType = action.ActionType,
StartDate = action.StartDate,
EndDate = action.EndDate,
Comment = action.Comment
});
}
// Other code here..
}
// Important: calculations made on the day
daily.ActualHours = tActions.Sum(...);
daily.ExpectedHours = contract.ExpectedHours;
// Other code here..
days.Add(daily);
}
return days;
}
调试示例(单日 - 2021-10-28 从 00:00 本地到 23:59 本地):
- 开始日期:2021-10-27T22:00:00.000Z
- 结束日期:2021-10-28T21:59:59.999Z
在foreach中:
第一轮 -> sd = 2021-10-27T00:00:00.000Z
最后一轮 -> sd = 2021-10-28T00:00:00.000Z
输出:
{
days: [
{
day: '2021-10-27',
actions: [
{
id: 123987,
actionType: 1,
startDate: '2021-10-27T22:00:00.000Z',
endDate: '2021-10-28T21:59:59.999Z'
}
],
actualHours: 24, // full day, wrong place!
expectedHours: 4
},
{
day: '2021-10-28',
actions: [
{
...
},
{
...
}
]
}
]
}
由于 APIs 在 UTC 中工作,此代码根据 UTC 中的值拆分日期。
例如,输入“2021-10-28T00:00:00.000 LOCAL”的最后一天将置于“2021-10-27 UTC”这一天之下。
我该如何解决这个问题?我错过了什么?
管理这些案例的最佳方法是什么?
理论上结果是正确的。 但是前端读取数据不正确
看起来像一个奇怪的错误。我建议在任何地方将 DateTime
替换为 DateTimeOffset
,进行数据库迁移并更新数据库。
如果上述方法不起作用,请告诉我。