C# 替换时区
我们正在尝试构建基本的事件日历功能,该功能允许用户创建事件,并在给定的月、日、年、小时、分钟以及时区指定开始时间(C# 替换时区,c#,datetime,timezone,icalendar,nodatime,C#,Datetime,Timezone,Icalendar,Nodatime,我们正在尝试构建基本的事件日历功能,该功能允许用户创建事件,并在给定的月、日、年、小时、分钟以及时区指定开始时间(System.TimeZoneInfo.Id)。CMS系统根据服务器的位置生成结果system.DateTime,比如TimeZoneInfo.Id山地标准时间。CMS不提供带有日期选择器组件的选项来指定时区。但是,我们可以控制SQL日期时间精度,默认设置为7 DateTime格式为yyyymmddthhmmszas,用于填充.ics/ical中的开始/结束时间。使用这种格式,201
System.TimeZoneInfo.Id
)。CMS系统根据服务器的位置生成结果system.DateTime
,比如TimeZoneInfo.Id
山地标准时间。CMS不提供带有日期选择器组件的选项来指定时区。但是,我们可以控制SQL日期时间精度,默认设置为7
DateTime
格式为yyyymmddthhmmsz
as,用于填充.ics/ical中的开始/结束时间。使用这种格式,2018年5月25日7:00PM(20180508T192840Z
)总是看起来像服务器的山区标准时间(MST),而不是2018年5月25日选定东部标准时间(EST)的7:00PM
如何使用日期时间
,日期时间偏移量
,时区信息
,节点时间
,甚至字符串
函数来格式化为yyyymmddthhmmsz
,来“替换”生成的日期时间
的时区
以下是:
TimeZoneInfo destinationTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var converted = TimeZoneInfo.ConvertTime(dateTime1, destinationTimeZone);
或:
创建一个新的DateTime
,将小时数从CST调整为EST,但该小时数不起作用,因为目标是使DateTime
具有原始小时值,但具有TimeZoneInfo.Id
东部标准时间
DateTime
构造函数似乎没有指定TimeZoneInfo
的构造函数,只有DateTimeKind
如何使用一些甚至是从
DateTime.Now
创建的DateTime
来实现这一点呢?DateTime
类型不知道时区,它所知道的关于区域的一切都是DateTimeKind
,可以是本地Utc
或未指定的。字符串表示中包含的区域信息将基于种类
值和服务器时区
您应该为您的场景使用DateTimeOffset
,它将日期时间和时区信息存储在一个值中:
var dateTime = DateTime.Now; /*your date time here*/
var destinationTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var zonedDateTime = new DateTimeOffset(DateTime.SpecifyKind(dateTime, DateTimeKind.Unspecified), destinationTimeZone.BaseUtcOffset);
var dateTimeStr = zonedDateTime.ToString("o"/*your format goes here*/);
有几件事:
- 您的格式说明符在末尾包含一个
Z
。Net的字符串格式将其视为字符文字,因为它不是有效的。请注意,格式化标记区分大小写。作为一个文本,它只是复制到输出,就像T
一样。因此,您生成的这个字符串总是会被任何解析它的东西解释为UTC,因为在ISO 8601标准中,Z
就是这个意思。这是你所面临问题的根本原因
如果您希望它反映一个不明确的本地时间(因为时区可能在.ics中的其他地方?),那么请完全省略Z
。但是,如果您打算包含时区偏移量,则可以使用K
说明符来指定DateTime
值,或者可以将zzz
说明符与DateTimeOffset
值结合使用,具体取决于您的具体需要
- 正如其他人所指出的,
DateTime
不支持时区,但也请注意,DateTimeOffset
也不支持时区,因为它只跟踪UTC的偏移量,而不跟踪特定时区。例如,它可以跟踪-07:00
,但不能告诉您它在山区时间。这就是野田佳彦时间有其zoneDateTime
类型的原因。Net本身没有任何这样的内置类型
- 在代码中,而不是在调用
TimeZoneInfo.ConvertTime
时,将考虑dateTime1
变量的.Kind
。如果是DateTimeKind.Utc
,则结果将是确定的。但是如果它是DateTimeKind.Unspecified
,或者DateTimeKind.Local
,那么它将被视为本地计算机的时区,在您的情况下,这就是服务器时区
- 请注意,无论服务器的时区设置为什么,以行为相同的方式编写代码要好得多。这通常意味着避免使用
DateTimeKind.Local
,例如DateTime.Now
、TimeZoneInfo.Local
等。相反,使用DateTime.UtcNow
获取当前DateTime
。或者,您可以使用DateTimeOffset.Now
或DateTimeOffset.UtcNow
,或者在Noda Time的IClock
实现上使用其中一种方法
归根结底,虽然有几种可能的解决方案可以解决您的问题,但将当前时间生成为特定时区中的字符串的最简单方法是:
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
DateTime utcNow = DateTime.UtcNow;
DateTime converted = TimeZoneInfo.ConvertTime(utcNow, destinationTimeZone);
string s = converted.ToString("yyyyMMddTHHmmss");
或者您可能想要:
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
DateTimeOffset utcNow = DateTimeOffset.UtcNow;
DateTimeOffset converted = TimeZoneInfo.ConvertTime(utcNow, destinationTimeZone);
string s = converted.ToString("yyyyMMddTHHmmsszzz").Replace(":","");
请注意,最后通过Replace
删除了:
——这是因为在ISO 8601基本格式中,偏移量应该类似于-0500
,而不是-05:00
。不幸的是,没有格式说明符可以直接得到它。(只有ISO 8601扩展格式使用冒号)。对于此应用程序,服务器时间实际上应该设置为GMT。DateTime
类型不知道时区,它知道的所有关于区域的信息都是DateTimeKind
,可以是Local
、Utc
或Unspecified
。因此,我不太确定在不更改ticks值的情况下替换DateTime
的时区意味着什么。你能进一步解释一下吗?对于包含区域信息的日期,应使用DateTimeOffset
。它有一个带有TimeSpan
的构造函数,因此您可以提供时区偏移。是否要将所选日期时间转换为sele
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
DateTimeOffset utcNow = DateTimeOffset.UtcNow;
DateTimeOffset converted = TimeZoneInfo.ConvertTime(utcNow, destinationTimeZone);
string s = converted.ToString("yyyyMMddTHHmmsszzz").Replace(":","");