我们正在尝试构建基本的事件日历功能,该功能允许用户创建事件并指定给定月、日、年、小时和分钟以及时区(System.TimeZoneInfo.Id)的开始时间。CMS系统根据我们服务器的位置生成结果System.DateTime,比方说TimeZoneInfo.Id 山区标准时间。CMS不提供日期选择器组件指定时区的选项。但是,我们可以控制set的精度,默认情况下设置为7。
为了在. .ics/ical中填充开始/结束时间,DateTime被格式化为yyyyMMddTHHmmssZ。使用这种格式,2018年5月25日7:00 in (20180508T192840Z)总是看起来像服务器的山地标准时间(MST),而不是2018年5月25日7:00 in在选定的东部标准时间(EST)。
我如何用DateTime、DateTimeOffset、TimeZoneInfo、NodaTime甚至string函数“替换”生成的不更改年份/月/日/小时/分钟的时区,以将其格式化为yyyyMMddTHHmmssZ
以下内容如下:
TimeZoneInfo destinationTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var converted = TimeZoneInfo.ConvertTime(dateTime1, destinationTimeZone);或者:
LocalDateTime fromLocal = LocalDateTime.FromDateTime(dateTime1);
DateTimeZone fromZone = DateTimeZoneProviders.Tzdb["America/Denver"];
ZonedDateTime fromZoned = fromLocal.InZoneLeniently(fromZone);
DateTimeZone toZone = DateTimeZoneProviders.Tzdb["America/Chicago"];
ZonedDateTime toZoned = fromZoned.WithZone(toZone);
LocalDateTime toLocal = toZoned.LocalDateTime;
var result = toLocal.ToDateTimeUnspecified();创建一个新的DateTime,将时间从CST调整到EST,这将无法工作,因为目标是拥有一个具有原始小时值的DateTime,但是使用TimeZoneInfo.Id 东方标准时间。
DateTime构造函数似乎没有指定TimeZoneInfo的构造器,只有DateTimeKind。
如何用一些甚至像从DateTime创建的DateTime.Now这样的方法来实现这一点?
发布于 2018-05-10 20:39:25
有几件事:
Z。not的字符串格式将其视为字符文字,因为它不是有效的日期时间格式说明符。注意,格式化标记区分大小写。作为文字,它只是被复制到输出--就像T一样。因此,您生成的这个字符串总是被解析它的任何东西解释为UTC,因为这就是Z在ISO8601标准中的意思。这是你所面临的问题的根本原因。
如果您想让它反映一个模糊的本地时间(因为时区可能在您的.ics中的其他地方?),那么完全忽略Z。但是,如果您打算包含时区偏移量,则可以使用K说明符来表示DateTime值,或者使用zzz说明符与DateTimeOffset值结合使用--这取决于您的特定需求。DateTime不知道时区,但也注意到DateTimeOffset也不知道,因为它只跟踪来自UTC的偏移量,而不是特定的时区。例如,它可以跟踪-07:00,但它不能告诉您它在山区时间。这就是野田时代( Noda )拥有ZonedDateTime类型的原因。.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的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 --这是因为在ISO8601的基本格式中,偏移应该类似于-0500而不是-05:00。不幸的是,没有格式说明符可以直接得到它。(只有ISO 8601扩展格式使用冒号)。
发布于 2018-05-10 18:04:00
DateTime类型不知道时区,它所知道的关于区域的一切都是DateTimeKind,它可以是Local、Utc或Unspecified。字符串表示中包含的区域信息将基于Kind值和服务器时区。
您应该在您的场景中使用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*/);https://stackoverflow.com/questions/50277481
复制相似问题