如何使用ASP.NET向Web用户显示本地化的日期和时间信息

8
我有一个ASP.NET应用程序和服务器上的UTC时间戳。我想将时间戳以正确的时区和本地日期/时间格式显示给用户。

例如,对于位于美国纽约(UTC-0500)的用户,Jan 2, 2012 14:00:00 UTC应显示为1/2/2012 9:00 AM,对于位于英国伦敦的用户,则应显示为02/01/2012 14:00

这看似简单的任务却证明非常困难。MSDN有一篇文章标题相同,但是它讨论的是解析用户输入而不是显示服务器端数据,因此并不完全适用。

可以通过JavaScript轻松确定客户端的时区偏移量

offset = new Date().getTimezoneOffset();

但是JavaScript对日期/时间格式的支持非常差。你只能使用toLocaleString()方法,其结果是一个丑陋的长字符串,例如Monday, January 02, 2012 9:00:00 AM。没有提供更短的格式,因此在客户端上,我们被困在良好的时区信息和不良日期/时间格式功能中。
服务器上的情况恰恰相反。我们可以利用Accept-Language HTTP标头来获取用户的语言环境({{link1:可能不是最佳选择,但可能足够好}}),然后利用.NET已知语言环境的数据库,所以我们的代码类似于 CultureInfo userCulture = new CultureInfo(Request.UserLanguages [0]); 加上一些错误处理。
但是我们卡在了时区问题上。是的,可以通过JavaScript获取它,然后作为cookie或postback数据传回,但如果我们需要在应用程序的第一个页面上显示日期怎么办?有人可能会认为第一页总是登录页面,但当用户登录信息在会话之间持久化(“记住我”选项)时,情况并非如此。解决这个问题的方法可能是将时区偏移保存为用户配置文件的一部分,但它可能很容易变得陈旧(在会话之间进出夏令时)。是否有一个全面的解决方案来解决这个问题,既能表现良好,又不需要编写大量代码?我非常好奇,请给予建议。
1个回答

5
您应该以标准形式(例如ISO8601)向客户端传递时间字符串:
var timeString = '2012-01-02T16:00:00Z';

有些浏览器可以正确解析ISO8601字符串,而有些则不行,因此为了确保解析正确,请手动解析。这很简单 - 创建一个本地日期对象,然后设置UTC日期和时间:

function localDateFromUTC(s) {

  var x = s.split(/[-\s:tz]/i);
  var d = new Date();

  d.setUTCFullYear(x[0], x[1], x[2]);
  d.setUTCHours(x[3], x[4], x[5]);
  return d;
}

var s = '2012-01-02T16:00:00Z';
var d = localDateFromUTC(s);
alert(d); // Shows local date and time for the provided UTC date and time

如果您想要特定的输出,您需要手动进行格式化,例如:
function formatDate(d) {
  var days = ['Sunday','Monday','Tuesday','Wednesday',
              'Thursday','Friday','Saturday'];
  var months = ['January','February','March','April','May','June','July',
                'August','September','October','November','December'];

  return days[d.getDay()] + ', ' + d.getDate() + ' ' + 
              months[d.getMonth()] + ', ' + d.getFullYear();
} 

你可以尝试使用toLocaleString(),但是不同浏览器的结果差异很大,大多数浏览器似乎都忽略了本地设置。

如果您想要特定的输出,我喜欢像这样传递日期的想法,但是确定本地日期/时间格式的问题仍未解决。您如何知道要使用什么:'01/02/2012 2:00 PM''2012-01-02 14.00'或者可能是'02.01.2012 14:00' - Ivan Krivyakov
通常的解决方案是以明确的格式编写日期,例如“2012年2月2日”,这应该可以被任何人清楚地理解,即使他们更喜欢其他格式的日期。如果浏览器有一个适当的toLocaleString函数,你可以使用它,但它们没有。 - RobG
1
我试图逆向工程Gmail如何处理时区。它非常聪明。他们在服务器上进行日期格式化和时区转换。在客户端,他们尝试通过在2010年1月1日和6月30日之间以及6月30日和2011年1月1日之间执行二进制搜索来确定夏令时转换的日期(如果有的话)。他们将该信息编码,并将当前时区偏移量与其一起存储在字符串中,然后(看我的手!)执行 (new Image).src=encoded_string! 这样他们可以在主页面完成渲染之前将数据传递给服务器,而不需要使用cookies或postback。 - Ivan Krivyakov
那种技术是如何在没有XMLHttpRequest的情况下完成AJAX的,你可以使用任何具有src属性的元素(例如iframe,script)。但我仍然不明白它如何进行本地格式化。如果所有操作都在UTC中完成,并且只为演示目的转换为本地日期/时间,则可以忽略时区偏移和夏令时 - 日期对象会处理这些事情。 - RobG
它在服务器上进行格式化。为了使其本地化,它在设置中有“显示语言”,选项包括英语(美国),英语(英国),法语等。它会相应地更改日期格式。我认为它需要夏令时信息才能正确显示旧电子邮件(但我不确定它是否完全正确,因为它只查找2010年)。当涉及实际显示日期和时间时,Gmail根本不使用JavaScript,因此没有日期对象。 - Ivan Krivyakov
谷歌可能之所以这样做,是因为它从客户端获取日期和时间,因此必须计算出时区。在编写日期时,真正常用的只有两种格式:日/月/年(占世界人口的95%)和月/日/年(占5%)。为用户提供他们想要的选项,并将其存储为首选项。您可能想提供年/月/日,在欧洲某些地区很常见,因为可以很好地排序。 - RobG

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接