You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过TimeZoneInfo在指定时区创建办公时间DateTime?

问题

问:如何为欧洲/维也纳时区创建09:00的DateTime?

注意:我找到的大多数解决方案都是转换已有的DateTime对象,但我想直接在已知时区中创建该时区的DateTime。
它既不是DateTimeKind.Utc,也不是DateTimeKind.Local,而是属于指定时区的DateTime。

难题

难题:DateTime的构造函数不支持TimeZoneInfo参数?能否实现简单的扩展方法?


基础数据:

1. string From = "09:00" //属于当地时间,考虑夏令时/冬令时
2. string Till = "17:00" //属于当地时间,考虑夏令时/冬令时
3. string TimeZoneResolved = "Europe/Vienna"

已获取的对象:

TimeZoneInfo timeZoneInfo = TZConvert.GetTimeZoneInfo(TimeZoneResolved);
TimeSpan workHoursStart = TimeSpan.Parse(From);
TimeSpan workHoursEnd = TimeSpan.Parse(Till);

期望实现:

//重构指定时区当天的上午9点时间
var now = DateTime.UtcNow;
var startTime = new DateTime(now.Year, now.Month, now.Day, workHoursStart.Hour, workHoursStart.Minute, 0, 0, timeZoneInfo);

-> 此写法无效,因为构造函数不接受TimeZoneInfo参数,它需要的是DateTimeKind类型。

或许可以通过扩展方法实现,比如:

var now = DateTime.UtcNow;
var officeHoursStart = new DateTime().BasedOnTz(timeZoneInfo, now.Year, now.Month, now.Day, workHoursStart.Hour, workHoursStart.Minute, 0, 0);
var officeHoursStartUtc = officeHoursStart.ToUtc();

解决方案

首先明确:.NET里的DateTime本身不直接绑定时区信息,它的DateTimeKind只能标记为Utc、Local或Unspecified。如果要保留时区关联,推荐用DateTimeOffset,或者通过TimeZoneInfo的方法构造带时区感知的时间。

方法1:直接构造并转换为DateTimeOffset

先构造目标时区的本地时间,再通过TimeZoneInfo转换为带偏移的DateTimeOffset,完整保留时区相关信息:

var nowUtc = DateTime.UtcNow;
// 将UTC时间转换为目标时区的日期,确保是目标时区的"当天"
var targetZoneDate = TimeZoneInfo.ConvertTimeFromUtc(nowUtc, timeZoneInfo).Date;
// 拼接目标时区的09:00本地时间
var localStartTime = targetZoneDate.Add(workHoursStart);
// 生成带时区偏移的DateTimeOffset
var startTimeWithZone = new DateTimeOffset(localStartTime, timeZoneInfo.GetUtcOffset(localStartTime));
// 转为UTC时间
var startTimeUtc = startTimeWithZone.UtcDateTime;

方法2:实现你想要的扩展方法

如果需要简化调用,可以自定义扩展方法:

public static class DateTimeExtensions
{
    public static DateTimeOffset BasedOnTz(this DateTime _, TimeZoneInfo timeZone, int year, int month, int day, int hour, int minute, int second, int millisecond)
    {
        var localDateTime = new DateTime(year, month, day, hour, minute, second, millisecond);
        // 验证时间在目标时区是否有效(处理夏令时切换可能出现的无效时间)
        if (!TimeZoneInfo.IsInvalidTime(localDateTime))
        {
            var offset = timeZone.GetUtcOffset(localDateTime);
            return new DateTimeOffset(localDateTime, offset);
        }
        // 无效时间的处理逻辑可根据业务调整
        throw new InvalidTimeException($"时间 {localDateTime} 在时区 {timeZone.Id} 中无效");
    }

    public static DateTime ToUtc(this DateTimeOffset dateTimeOffset)
    {
        return dateTimeOffset.UtcDateTime;
    }
}

调用方式和你期望的一致:

var now = DateTime.UtcNow;
var officeHoursStart = new DateTime().BasedOnTz(timeZoneInfo, now.Year, now.Month, now.Day, workHoursStart.Hour, workHoursStart.Minute, 0, 0);
var officeHoursStartUtc = officeHoursStart.ToUtc();

注意事项

  • 夏令时/冬令时会被自动处理:TimeZoneInfo.GetUtcOffset会根据传入的本地时间自动计算对应UTC偏移量。
  • 无效时间处理:部分时区夏令时切换时会出现"跳过的时间"(比如欧洲部分时区3月最后一个周日的2:00-3:00),此时构造的本地时间无效,需要添加验证避免报错。

内容的提问来源于stack exchange,提问作者CodingYourLife

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 10:55:24