【问题标题】:C# Server-side management of dates in UTCUTC 中日期的 C# 服务器端管理
【发布时间】:2021-12-13 11:57:50
【问题描述】:

我正在开发一个 .Net Core 3.1 REST Api。

我对接近午夜的日期和时区有疑问。
我以 UTC 格式保存数据库中的所有数据,前端调用 API 以 UTC 格式传递时间。

我目前处于 GTM+2 时区。

我必须将用户执行的“操作”分成不同的日子。

输出示例:

    {
        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

为了采取行动并将它们按天分开,我编写了这段代码 sn-p..

    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: [
                    {
                        ...
                    },
                    {
                        ...
                    }
                ]
            }
        ]
    }

由于 API 在 UTC 中工作,此代码根据 UTC 值拆分日期。
例如,最后一天输入的“2021-10-28T00:00:00.000 LOCAL”将放置在“2021-10-27 UTC”这一天之下。

我该如何解决这个问题?我错过了什么?
管理这些案例的最佳方法是什么?

理论上结果是正确的。 但是前端读取的数据不正确。

【问题讨论】:

    标签: c# asp.net-core datetime .net-core timezone


    【解决方案1】:

    看起来像一个奇怪的错误。我建议在任何地方用DateTimeOffset 替换DateTime,进行数据库迁移和更新数据库。

    如果上述方法不起作用,请告诉我。

    【讨论】:

    • DateTimeOffset 解决了这个问题。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-10
    • 1970-01-01
    • 2020-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多