20

我有一个场景,我有一个时区偏移量(以分钟为单位)并且需要确定它的时区。我知道所有数据都不可用(例如,可能有多个时区偏移为 -240 分钟),但“最佳猜测”是可以接受的。

我的第一关是这样的:

foreach (var info in TimeZoneInfo.GetSystemTimeZones())
{
    if (info.BaseUtcOffset.TotalMinutes == timezoneOffset)
    {
         // do something here if this is a valid timezone
    }
}

这种方法很有效,但我需要考虑夏令时,这让我有些失望。我添加了这个可怕的黑客:

foreach (var info in TimeZoneInfo.GetSystemTimeZones())
{
    var extra = info.IsDaylightSavingTime(DateTime.Now) ? 60 : 0;
    if (info.BaseUtcOffset.TotalMinutes + extra == timezoneOffset)
    {
         // do something here if this is a valid timezone
    }
}

这“足够好”,因为我可以在夏令时无效时向用户显示正确的时间,并且在 DST 期间正确率约为 70%。仍然......这对我的眼球来说是一些糟糕的代码。

有一个更好的方法吗?更优雅会更好,更准确会更好。

更新

从技术上讲,我可以访问 Javascript 可以获得的有关日期的任何信息。我有一个页面,在该页面上放置了一个名为“offset”的隐藏字段。我有一个使用 DateTime().getTimezoneOffset() 填充偏移字段的 JQuery 函数。虽然我在 DateTime 对象上看不到任何有用的东西,但也许这会为想法开辟其他途径。

4

2 回答 2

21

简短的回答:你不能。

夏令时使它成为不可能。例如,仅从 UTC 偏移量无法确定夏季亚利桑那州和加利福尼亚州之间或冬季亚利桑那州和新墨西哥州之间的差异(因为亚利桑那州不遵守 DST)。

还有一个问题是不同国家什么时候遵守夏令时。例如,美国 DST 比欧洲开始得早,结束得晚。

可以进行精确的猜测(即 +/- 一个小时),但如果您使用它向用户显示时间,您将不可避免地向其中一些人显示错误的时间。


更新:从评论看来,您的主要目标是在用户的本地时区显示时间戳。如果这是您想要做的,您应该将时间作为 UTC 时间戳发送,然后使用 Javascript 在用户的浏览器上重写它。如果他们没有启用 Javascript,他们仍然会看到可用的 UTC 时间戳。这是我在这个问题中提出的一个函数,我在这个 Greasemonkey 脚本中使用了它。您可能需要对其进行调整以满足您的需要。

//@param timestamp An ISO-8601 timestamp in the form YYYY-MM-DDTHH:MM:SS±HH:MM
//Note: Some other valid ISO-8601 timestamps are not accepted by this function
function parseISO8601(timestamp)
{
  var regex = new RegExp("^([\\d]{4})-([\\d]{2})-([\\d]{2})T([\\d]{2}):([\\d]{2}):([\\d]{2})([\\+\\-])([\\d]{2}):([\\d]{2})$");
  var matches = regex.exec(timestamp);
  if(matches != null)
  {
    var offset = parseInt(matches[8], 10) * 60 + parseInt(matches[9], 10);
    if(matches[7] == "-")
      offset = -offset;

    return new Date(
      Date.UTC(
        parseInt(matches[1], 10),
        parseInt(matches[2], 10) - 1,
        parseInt(matches[3], 10),
        parseInt(matches[4], 10),
        parseInt(matches[5], 10),
        parseInt(matches[6], 10)
      ) - offset*60*1000
    );
  }
  return null;
}

这是我在博客上使用的一个函数,用于在用户的本地时区显示已解析的时间戳。同样,您可以将其调整为您想要的格式。

var weekDays = new Array("Sunday", "Monday", "Tuesday", "Wednesday",
        "Thursday", "Friday", "Saturday");
var months = new Array("January", "February", "March", "April", "May", "June",
        "July", "August", "September", "October", "November", "December");

function toLocalTime(date)
{
  var hour = date.getHours();
  var ampm = (hour < 12 ? "am" : "pm");
  hour = (hour + 11)%12 + 1;

  var minutes = date.getMinutes();
  if(minutes < 10)
    minutes = "0" + minutes;

  return weekDays[date.getDay()] + ", "
       + months[date.getMonth()] + " "
       + date.getDate()          + ", "
       + date.getFullYear()      + " at "
       + hour                    + ":"
       + minutes                 + " "
       + ampm;
}
于 2009-08-13T21:37:26.047 回答
5

仅知道与 UTC 的偏移量,由于 DST,您无法判断您所在的时区。您可以考虑查看部分时间以尝试猜测 DST 在当时是否生效,但政治考虑使这几乎是不可能的,因为不同的司法管辖区会改变 DST 的定义。

于 2009-08-13T21:41:53.803 回答