ASP MVC Web API + EF中带有时区的DateTime

时间:2015-04-26 10:46:15

标签: c# entity-framework datetime asp.net-web-api timezone

我正在使用ASP MVC Web API + EF,而我的客户正在获取没有时区信息的DateTime。我试图在WebApiConfig中设置设置但没有成功:

config.Formatters.JsonFormatter.SerializerSettings.DateTimeZoneHandling 
= DateTimeZoneHandling.Local;

唯一的方法是为我工作:使用DateTimeKind.Local创建DateTime的新实例:

    public IEnumerable<ClientDto> Execute()
    {
        var clients = this.DbContext.Clients.Select(
            m => new ClientDto
        {
            Id = m.Id,
            NotificationSendingTime = m.NotificationSendingTime,
            . . .
        }).ToList();

        clients.ForEach(m => m.NotificationSendingTime = 
            m.NotificationSendingTime.HasValue 
            ? new DateTime(m.NotificationSendingTime.Value.Ticks, DateTimeKind.Local) 
            : m.NotificationSendingTime);

        return clients;
    }

但在这种情况下,我必须使用.ToList()并为每个项目设置新的DateTime和时区。

如何设置WebApi或EF以自动添加有关时区的信息?感谢。

更新

我似乎找到了解决方案。 我的HTML:

<!-- Timepicker -->
<input id="notificationSendingTime"
       name="notificationSendingTime"
       type="text"
       class="form-control"
       data-ng-model="notificationSendingTime"
       bs-timepicker
       data-time-format="HH:mm"
       data-time-type="date"
       data-length="1" data-minute-step="30"
       data-arrow-behavior="picker" />

<!-- Timezone -->
<button type="button" class="btn btn-default full-width time-zone" ng-model="formData.TimeZoneId"
        data-html="1" data-animation="" placeholder="Time Zone..."
        ng-options="timeZone.Id as timeZone.FriendlyName for timeZone in timeZones" bs-select>
    Action <span class="caret"></span>
</button>

我的客户端:

public class ClientDto
{
    public int Id { get; set; }
    public DateTime? NotificationSendingTime { get; set; }

    public DateTimeOffset? NotificationSendingTimeOffset
    {
        get
        {
            if (!this.NotificationSendingTime.HasValue)
            {
                return null;
            }

            var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(string.IsNullOrWhiteSpace(this.TimeZoneId) ? "Greenwich Standard Time" : this.TimeZoneId);
            var offset = TimeZoneInfo.ConvertTimeFromUtc(this.NotificationSendingTime.Value, timeZoneInfo);
            return offset;
        }
    }
    public string TimeZoneId { get; set; }
}

在服务器端更新客户端:

if (command.CommandArg.NotificationSendingTime.HasValue)
{
    var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(string.IsNullOrWhiteSpace(command.CommandArg.TimeZoneId) ? "Greenwich Standard Time" : command.CommandArg.TimeZoneId);
    var utc = TimeZoneInfo.ConvertTimeToUtc(command.CommandArg.NotificationSendingTime.Value, timeZoneInfo);
    command.CommandArg.NotificationSendingTime = utc.Date + new TimeSpan(utc.Hour, 0, 0);
}

client.NotificationSendingTime = command.CommandArg.NotificationSendingTime;
client.TimeZoneId = command.CommandArg.TimeZoneId;

this.DbContext.SaveChanges();

在获取数据后的angularJS控制器中:

$scope.notificationSendingTime = $scope.formData.NotificationSendingTimeOffset;

在提交数据之前在我的angularJS控制器中:

    $scope.formData.NotificationSendingTime 
= $filter('date')($scope.notificationSendingTime, 'HH:mm');

timepicker适用于所有浏览器!感谢。

1 个答案:

答案 0 :(得分:0)

如果您将时区信息存储在单独的列中,我认为制作EF转换内容并不简单。我建议将此功能放在模型中。对于这个简单的例子,DTO看起来像个好人:

[DataContract]
public class Client
{
    [DataMember]
    public DateTime Created { get; set; }

    [DataMember]
    public string CreatedTimeZoneId { get; set; }
}

public class ClientDto
{
    private readonly Client _client;

    public ClientDto(Client client)
    {
        _client = client;
    }

    public DateTimeOffset Created
    {
        get
        {
            //TODO: Should be moved in separate helper method.
            var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(_client.CreatedTimeZoneId);
            return new DateTimeOffset(_client.Created, timeZoneInfo.BaseUtcOffset);
        }
    }
}

通过使用DateTimeOffset类型,您可以免于担心时区处理。 JSON.NET适用于这种类型:

// Simulate DB call
var clients = new List<Client>
{
    new Client
    {
        Created = new DateTime(2015, 4, 27, 11, 48, 22, DateTimeKind.Unspecified),
        CreatedTimeZoneId = "FLE Standard Time"
    }
};

var clientDtos = clients.Select(client => new ClientDto(client));
var json = JsonConvert.SerializeObject(clientDtos);

生成的JSON将是:

[{"Created":"2015-04-27T11:48:22+02:00"}]