关于javascript:以用户的语言环境格式和时间偏移显示日期/时间

Display date/time in user's locale format and time offset

我希望服务器总是以HTML格式提供UTC格式的日期,并让客户机站点上的javascript将其转换为用户的本地时区。

如果我能以用户的区域设置日期格式输出,我会得到额外的奖励。


从UTC日期开始,最简单的方法似乎是创建一个新的Date对象,并使用setUTC…方法将其设置为所需的日期/时间。

然后各种toLocale…String方法将提供本地化输出。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// This would come from the server.
// Also, this whole block could probably be made into an mktime function.
// All very bare here for quick grasping.
d = new Date();
d.setUTCFullYear(2004);
d.setUTCMonth(1);
d.setUTCDate(29);
d.setUTCHours(2);
d.setUTCMinutes(45);
d.setUTCSeconds(26);

console.log(d);                        // -> Sat Feb 28 2004 23:45:26 GMT-0300 (BRT)
console.log(d.toLocaleString());       // -> Sat Feb 28 23:45:26 2004
console.log(d.toLocaleDateString());   // -> 02/28/2004
console.log(d.toLocaleTimeString());   // -> 23:45:26

一些参考文献:

  • 托卡拉弦
  • ToLocaledateString
  • Tolocaletimestring
  • GetTimeZoneOffset


对于新项目,只需使用moment.js

这个问题很古老,所以moment.js当时不存在,但是对于新项目,它可以简化很多这样的任务。

最好按如下方式分析来自UTC的日期字符串(在服务器上创建一个与ISO-8601兼容的字符串,以便在所有浏览器中获得一致的结果):

1
var m = moment("2013-02-08T09:30:26Z");

现在只需在应用程序中使用m,moment.js默认为本地时区进行显示操作。有很多方法可以格式化日期和时间值或提取其中的一部分。

您甚至可以在用户区域设置中设置矩对象的格式,如下所示:

1
m.format('LLL') // Returns"February 8 2013 8:30 AM" on en-us

要将moment.js对象转换为不同的时区(即既不是本地的也不是UTC),您需要moment.js时区扩展。这个页面还有一些例子,使用起来非常简单。


您可以使用new Date().getTimezoneOffset()/60作为时区。还有一个使用用户区域设置显示日期的toLocaleString()方法。

以下是整个列表:使用日期


一旦构建了日期对象,下面是转换的一个片段:

函数接受一个UTC格式的日期对象和格式字符串。您将需要一个Date.strftime原型。

1
2
3
4
5
6
7
8
function UTCToLocalTimeString(d, format) {
    if (timeOffsetInHours == null) {
        timeOffsetInHours = (new Date().getTimezoneOffset()/60) * (-1);
    }
    d.setHours(d.getHours() + timeOffsetInHours);

    return d.strftime(format);
}


以下是我在过去项目中使用的内容:

1
2
3
4
5
6
7
8
var myDate = new Date();
var tzo = (myDate.getTimezoneOffset()/60)*(-1);
//get server date value here, the parseInvariant is from MS Ajax, you would need to do something similar on your own
myDate = new Date.parseInvariant('<%=DataCurrentDate%>', 'yyyyMMdd hh:mm:ss');
myDate.setHours(myDate.getHours() + tzo);
//here you would have to get a handle to your span / div to set.  again, I'm using MS Ajax's $get
var dateSpn = $get('dataDate');
dateSpn.innerHTML = myDate.localeFormat('F');


在JS中,除了转换上面提到的每个属性之外,没有简单的跨平台的方法来格式化本地日期时间。

这里有一个快速的黑客,我用来获取本地的YYYY-MM-DD。注意这是一个黑客,因为最终日期将不再有正确的时区(所以你必须忽略时区)。如果我还需要其他东西,我使用moment.js。

1
2
3
4
var d = new Date();    
d = new Date(d.getTime() - d.getTimezoneOffset() * 60000)
var yyyymmdd = t.toISOString().slice(0,0);
// 2017-05-09T08:24:26.581Z (but this is not UTC)

d.getTimeZoneOffset()以分钟为单位返回时区偏移量,d.getTime()以毫秒为单位,因此x 60000。


我混合了迄今为止的答案并添加到其中,因为我必须阅读所有答案并额外调查一段时间,才能以用户的本地时区格式显示数据库中的日期-时间字符串。

datetime字符串来自python/django数据库,格式为:2016-12-05t15:12:24.215z

在javascript中可靠地检测浏览器语言在所有浏览器中似乎都不起作用(请参阅javascript以检测浏览器语言首选项),因此我从服务器获取浏览器语言。

python/django:将请求浏览器语言作为上下文参数发送:

1
2
language = request.META.get('HTTP_ACCEPT_LANGUAGE')
return render(request, 'cssexy/index.html', {"language": language })

HTML:将其写入隐藏输入:

1
<input type="hidden" id="browserlanguage" value={{ language }}/>

javascript:获取隐藏输入的值,例如en-gb、en-us;q=0.8、en;q=0.6/,然后仅通过replace和正则表达式获取列表中的第一种语言

1
2
const browserlanguage = document.getElementById("browserlanguage").value;
var defaultlang = browserlanguage.replace(/(\w{2}\-\w{2}),.*/,"$1");

javascript:转换为日期时间并格式化:

1
2
var options = { hour:"2-digit", minute:"2-digit" };
var dt = (new Date(str)).toLocaleDateString(defaultlang, options);

请参阅:https://developer.mozilla.org/en/docs/web/javascript/reference/global_objects/date/toLocaledateString

结果是(浏览器语言为en-GB):05/12/2016,14:58


使用PHP代码中的日期,我使用了类似的方法。

1
2
3
4
5
6
function getLocalDate(php_date) {
  var dt = new Date(php_date);
  var minutes = dt.getTimezoneOffset();
  dt = new Date(dt.getTime() + minutes*60000);
  return dt;
}

我们可以这样称呼它

1
var localdateObj = getLocalDate('2015-09-25T02:57:46');


.getTimezoneOffset()方法以分钟为单位报告时区偏移量,从gmt/utc时区算起"向西",得出的偏移量值与人们通常习惯的值相反。(例如,纽约时间报告为+240分钟或+4小时)

要获得以小时为单位的正常时区偏移量,需要使用:

1
var timeOffsetInHours = -(new Date()).getTimezoneOffset()/60

重要细节:请注意,夏令时是计算结果的因素,所以这个方法给出的实际上是时间偏移量,而不是实际的地理时区偏移量。


我遇到的最佳解决方案是创建[time display="llll"datetime="utc time"/]标记,并使用javascript(jquery)相对于用户的时间来解析和显示它。

网址:http://moment js.com/moment.js

会很好地显示时间。


您可以使用以下报告时区与格林尼治标准时间(以分钟为单位)的偏移量:

1
new Date().getTimezoneOffset();

注:-此函数返回一个负数。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// new Date(year, monthIndex [, day [, hours [, minutes [, seconds [, milliseconds]]]]])
var serverDate = new Date(2018, 5, 30, 19, 13, 15); // just any date that comes from server
var serverDateStr = serverDate.toLocaleString("en-US", {
  year: 'numeric',
  month: 'numeric',
  day: 'numeric',
  hour: 'numeric',
  minute: 'numeric',
  second: 'numeric'
})
var userDate = new Date(serverDateStr +" UTC");
var locale = window.navigator.userLanguage || window.navigator.language;

var clientDateStr = userDate.toLocaleString(locale, {
  year: 'numeric',
  month: 'numeric',
  day: 'numeric'
});

var clientDateTimeStr = userDate.toLocaleString(locale, {
  year: 'numeric',
  month: 'numeric',
  day: 'numeric',
  hour: 'numeric',
  minute: 'numeric',
  second: 'numeric'
});

console.log("Server UTC date:" + serverDateStr);
console.log("User's local date:" + clientDateStr);
console.log("User's local date&time:" + clientDateTimeStr);


getTimeZoneOffset()和toLocaleString适合于基本的日期工作,但是如果需要实时区域支持,请查看MDE的timeZone.js。

在这个问题的答案中,还有几个选项要讨论


要将日期转换为本地日期,请使用toLocaledateString()方法。

1
var date = (new Date(str)).toLocaleDateString(defaultlang, options);

要将时间转换为本地时间,请使用toLocaletimeString()方法。

1
var time = (new Date(str)).toLocaleTimeString(defaultlang, options);

不知道如何进行区域设置,但javascript是客户端技术。

1
usersLocalTime = new Date();

将包含客户的时间和日期(由他们的浏览器报告,并通过扩展他们所在的计算机)。将服务器的时间包括在响应中,并进行一些简单的数学运算来猜测时间偏移量,这应该是很简单的事情。