草庐IT

c# - 指定日期时间的时区而不更改值

coder 2024-06-02 原文

我想知道如何在不实际更改值的情况下更改 DateTime 对象的时区。这是背景...

我在 AppHarbor 上托管了一个 ASP.NET MVC 站点,并且服务器的时间设置为 UTC。当我从我的站点提交包含日期时间值的表单时,比如 2013 年 9 月 17 日凌晨 4:00,它会以该值发送到服务器。但是,当我这样做时:

public ActionResult Save(Entity entity)
{
    entity.Date = entity.Date.ToUniversalTime();
    EntityService.Save(entity);
}

...它错误地将其保留为同一时间(凌晨 4 点),因为服务器已经在 UTC 时间。所以在转换为 UTC 并保存到数据库后,数据库值为 2013-09-17 04:00:00.000,实际上它应该是 2013-09-17 08:00:00.000,因为浏览器是在 EST 上。我希望在提交表单并将值传递给 Controller ​​操作后,它会将 DateTime 的时区设置为浏览器的 (EST) 而不是服务器主机的 (UTC),但这并没有发生。

无论如何,现在我被困在一个包含正确日期/时间值但错误时区的 DateTime 对象上,所以我无法正确地将它转换为 UTC。我存储每个用户的时区,所以如果有一种方法可以在不实际更改值的情况下为 DateTime 对象设置时区(我不能执行 TimeZoneInfo.ConvertTime 因为它会更改值)那么我可以有正确的日期/时间值和正确的时区,然后我可以安全地执行 date.ToUniversalTime。话虽如此,我只看到了如何更改 DateTime 的 KIND 而不是 TimeZone,而没有更改其实际值。

有任何想法吗?

最佳答案

实际上,它正在做你要求它做的事情。从服务器的角度来看,您向它传递了一个“未指定的”DateTime .换句话说,只是年、月日等,没有任何上下文。如果你看 .Kind属性,你会看到它确实是 DateTimeKind.Unspecified .

当您拨打 .ToUniversalTime()在未指定类型的 DateTime 上, .NET 将假定运行代码的计算机的本地时区上下文。您可以阅读有关此内容的更多信息 in the documentation here .由于您的服务器设置为 UTC,因此无论输入类型如何,所有三种类型都会产生相同的结果。基本上,这是一个无操作。

现在,您说您希望时间反射(reflect)用户的时区。不幸的是,这是服务器没有的信息。没有携带时区详细信息的神奇 HTTP header 。

不过,有一些方法可以实现这种效果,并且您有一些选择。

JavaScript 方法

这可能是最简单的选择,但它确实需要 JavaScript。

  • 获取用户输入的本地日期和时间并将其解析为 JavaScript Date类(class)。
  • 为了更容易解析,您可以考虑使用 moment相反,来自 moment.js图书馆。
  • Date 获取 UTC 日期和时间或 moment ,并将其传递给您的服务器。
  • 这在 JavaScript 中相对容易,所以我会为您提供详细信息。
  • 您可以传递多种格式,但首选方式是作为 ISO8601 时间戳。示例:2013-09-17T08:00:00.000Z
  • 不要忘记 Z在末尾。这表明时间是 UTC。
  • 由于它是作为 UTC 传递给您的,因此您可以直接存储它而无需任何转换。
  • 检索它时,您再次将 UTC 传递给浏览器,将其加载到 Date 中。或 moment使用 JavaScript,然后发出本地日期和时间。
  • 我强烈建议您尝试 moment.js如果你采取这种方法。它可以在没有它的情况下完成,但这可能会更加复杂且容易出错。

  • 使用 Windows 时区的 .NET 方法

    如果您不打算调用 JavaScript,则需要向用户询问他们的时区。这在更大的应用程序中可以很好地工作,例如在用户的个人资料页面上。
  • 使用 TimeZoneInfo.GetSystemTimeZones 建立一个下拉列表。
  • 每个TimeZoneInfo列表中的项目,使用 .Id值,以及 .DisplayName为文本。
  • 然后当你想转换时间时可以使用这个值。
    TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById(yourUsersTimeZone);
    DateTime utc = TimeZoneInfo.ConvertTimeToUtc(theInputDatetime, tz);
    
  • 这将适用于 Windows 时区,这是 Microsoft 创建的,并且有一些缺点。您可以在 the timezone tag wiki 中了解他们的一些不足之处。 .

  • .NET 方法使用 IANA 时区

    如果要使用更标准的 IANA 时区,例如 America/New_YorkEurope/London ,那么你可以使用像 Noda Time 这样的库.它提供了比内置框架更好的处理日期和时间的 API。有一点学习曲线,但如果你正在做任何复杂的事情,那么付出努力是值得的。举个例子:
    DateTimeZone tz = DateTimeZoneProviders.Tzdb["America/New_York"];
    var pattern = LocalDateTimePattern.CreateWithInvariantCulture("yyyy-MM-dd HH:mm:ss");
    LocalDateTime dt = pattern.Parse("2013-09-17 04:00:00").Value;
    ZonedDateTime zdt = tz.AtLeniently(dt);
    Instant utc = zdt.ToInstant();
    

    关于夏令时

    无论您采用这三种方法中的哪一种,您都必须处理夏令时造成的问题。这些示例中的每一个都显示了一种“宽松”的方法,如果您指定的本地时间不明确或无效,则会遵循某些规则,因此您仍然可以获得一些有效的时间。当我拨打 AtLeniently 时,您可以使用 Noda Time 方法直接看到这一点。 .但它也发生在其他人身上——这只是隐含的。在 JavaScript 中,规则可能因浏览器而异,因此不要期望结果一致。

    根据您收集的数据类型,您可能会认为做出这种假设是完全可以接受的。但在许多情况下,假设是不合适的。在这种情况下,您可能需要提醒用户输入时间无效,或者询问他们的意思是两个不明确的时间中的哪一个。

    在 .Net 中,您可以使用 TimeZoneInfo.IsInvalidTime 来检查这一点。和 TimeZoneInfo.IsAmbiguousTime .

    有关夏令时工作原理的示例,see here .在“spring-forward”转换中,转换期间的时间是无效的。在“回退”转换中,转换期间的时间是不明确的——也就是说,它可能发生在转换之前或之后。

    关于c# - 指定日期时间的时区而不更改值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18840081/

    有关c# - 指定日期时间的时区而不更改值的更多相关文章

    1. ruby-on-rails - Ruby on Rails 迁移,将表更改为 MyISAM - 2

      如何正确创建Rails迁移,以便将表更改为MySQL中的MyISAM?目前是InnoDB。运行原始执行语句会更改表,但它不会更新db/schema.rb,因此当在测试环境中重新创建表时,它会返回到InnoDB并且我的全文搜索失败。我如何着手更改/添加迁移,以便将现有表修改为MyISAM并更新schema.rb,以便我的数据库和相应的测试数据库得到相应更新? 最佳答案 我没有找到执行此操作的好方法。您可以像有人建议的那样更改您的schema.rb,然后运行:rakedb:schema:load,但是,这将覆盖您的数据。我的做法是(假设

    2. ruby - 如何指定 Rack 处理程序 - 2

      Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

    3. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

      我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

    4. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

      我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

    5. ruby - Capistrano 3 在任务中更改 ssh_options - 2

      我尝试使用不同的ssh_options在同一阶段运行capistranov.3任务。我的production.rb说:set:stage,:productionset:user,'deploy'set:ssh_options,{user:'deploy'}通过此配置,capistrano与用户deploy连接,这对于其余的任务是正确的。但是我需要将它连接到服务器中配置良好的an_other_user以完成一项特定任务。然后我的食谱说:...taskswithoriginaluser...task:my_task_with_an_other_userdoset:user,'an_othe

    6. ruby-on-rails - 在 ruby​​ .gemspec 文件中,如何指定依赖项的多个版本? - 2

      我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这

    7. ruby-on-rails - date_field_tag,如何设置默认日期? [ rails 上的 ruby ] - 2

      我想设置一个默认日期,例如实际日期,我该如何设置?还有如何在组合框中设置默认值顺便问一下,date_field_tag和date_field之间有什么区别? 最佳答案 试试这个:将默认日期作为第二个参数传递。youcorrectlysetthedefaultvalueofcomboboxasshowninyourquestion. 关于ruby-on-rails-date_field_tag,如何设置默认日期?[rails上的ruby],我们在StackOverflow上找到一个类似的问

    8. ruby - 如果指定键的值在数组中相同,如何合并哈希 - 2

      我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat

    9. ruby-on-rails - Ruby 检查日期时间是否为 iso8601 并保存 - 2

      我需要检查DateTime是否采用有效的ISO8601格式。喜欢:#iso8601?我检查了ruby​​是否有特定方法,但没有找到。目前我正在使用date.iso8601==date来检查这个。有什么好的方法吗?编辑解释我的环境,并改变问题的范围。因此,我的项目将使用jsapiFullCalendar,这就是我需要iso8601字符串格式的原因。我想知道更好或正确的方法是什么,以正确的格式将日期保存在数据库中,或者让ActiveRecord完成它们的工作并在我需要时间信息时对其进行操作。 最佳答案 我不太明白你的问题。我假设您想检查

    10. ruby - 检查日期是否在过去 7 天内 - 2

      我的日期格式如下:"%d-%m-%Y"(例如,今天的日期为07-09-2015),我想看看是不是在过去的七天内。谁能推荐一种方法? 最佳答案 你可以这样做:require"date"Date.today-7 关于ruby-检查日期是否在过去7天内,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/32438063/

    随机推荐