无论客户端系统的时区如何,获取客户端本地时间的最佳方法是什么?我正在创建一个应用程序,我首先需要获取客户访问地点的确切时间和日期。即使检测客户端系统的 IP 地址也有缺点,或者检测客户端系统的时区有时可能会有风险。那么,有没有什么方法可以真正可靠且不易出错,因为向客户显示错误的时间和日期是一件非常尴尬的事情。
15 回答
如今,您只需一行代码即可获得用户的正确时区:
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
然后,您可以使用moment-timezone来解析时区,例如:
const currentTime = moment().tz(timezone).format();
尝试
let s= new Date().toLocaleString();
console.log(s);
如果您想知道客户端相对于 GMT/UTC 的时区,请访问:
var d = new Date();
var tz = d.toString().split("GMT")[1].split(" (")[0]; // timezone, i.e. -0700
如果您想要时区的实际名称,可以试试这个:
var d = new Date();
var tz = d.toString().split("GMT")[1]; // timezone, i.e. -0700 (Pacific Daylight Time)
更新 1
根据您的第一条评论,您还可以使用d.getTimezoneOffset()
从 UTC 获取以分钟为单位的偏移量。虽然有几个问题。
- 返回的分钟数的符号 (+/-) 可能与您的预期相反。如果您比 UTC晚8 小时,它将返回
480
not-480
。有关更多文档,请参阅MDN或MSDN。 - 它实际上并没有返回客户端报告的时区,就像我给出的第二个示例一样。只是当前与 UTC 的分钟偏移量。所以它会根据夏令时而改变。
更新 2
虽然字符串拆分示例有效,但阅读起来可能会令人困惑。这是一个应该更容易理解并且可能更快的正则表达式版本(虽然这两种方法都非常快)。
如果您想知道客户端相对于 GMT/UTC 的时区,请访问:
var gmtRe = /GMT([\-\+]?\d{4})/; // Look for GMT, + or - (optionally), and 4 characters of digits (\d)
var d = new Date().toString();
var tz = gmtRe.exec(d)[1]; // timezone, i.e. -0700
如果您想要时区的实际名称,请尝试以下操作:
var tzRe = /\(([\w\s]+)\)/; // Look for "(", any words (\w) or spaces (\s), and ")"
var d = new Date().toString();
var tz = tzRe.exec(d)[1]; // timezone, i.e. "Pacific Daylight Time"
为了在纯 Javascript 中获取本地时间,请使用这个内置函数
// return new Date().toLocaleTimeString();
见下面的例子
function getLocaltime(){
return new Date().toLocaleTimeString();
}
console.log(getLocaltime());
只需要解决这个问题,所以我想我会留下我的答案。不需要 jQuery 我曾经更新元素,因为我已经缓存了对象。
我首先编写了一个 php 函数来将所需的日期/时间返回到我的 HTML 模板
/**
* Gets the current location time based on timezone
* @return string
*/
function get_the_local_time($timezone) {
//$timezone ='Europe/London';
$date = new DateTime('now', new DateTimeZone($timezone));
return array(
'local-machine-time' => $date->format('Y-m-d\TH:i:s+0000'),
'local-time' => $date->format('h:i a')
);
}
然后在我的 HTML 模板中使用它来显示初始时间,并在数据属性中呈现 javascript 所需的日期格式。
<span class="box--location__time" data-time="<?php echo $time['local-machine-time']; ?>">
<?php echo $time['local-time']; ?>
</span>
然后我在我的日期对象上使用 getUTCHours 来返回时间,而与用户时区无关
getUTCHours() 方法根据世界时返回指定日期和时间的小时(从 0 到 23)。
var initClocks = function() {
var $clocks = $('.box--location__time');
function formatTime(hours, minutes) {
if (hours === 0) {
hours = 12;
}
if (hours < 10) {
hours = "0" + hours;
}
if (minutes < 10) {
minutes = "0" + minutes;
}
return {
hours: hours,
minutes: minutes
}
}
function displayTime(time, $clockDiv) {
var currentTime = new Date(time);
var hours = currentTime.getUTCHours();
var minutes = currentTime.getUTCMinutes();
var seconds = currentTime.getUTCSeconds();
var initSeconds = seconds;
var displayTime = formatTime(hours, minutes);
$clockDiv.html(displayTime.hours + ":" + displayTime.minutes + ":" + seconds);
setInterval(function() {
if (initSeconds > 60) {
initSeconds = 1;
} else {
initSeconds++;
}
currentTime.setSeconds(initSeconds);
hours = currentTime.getUTCHours();
minutes = currentTime.getUTCMinutes();
seconds = currentTime.getUTCSeconds();
displayTime = formatTime(hours, minutes);
$clockDiv.html(displayTime.hours + ":" + displayTime.minutes + ":" + seconds);
}, 1000);
}
$clocks.each(function() {
displayTime($(this).data('time'), $(this));
});
};
然后我使用 setSeconds 方法根据页面加载后的秒数更新日期对象(简单的间隔函数),并更新 HTML
直接这样:
new Date((new Date().setHours(new Date().getHours() - (new Date().getTimezoneOffset() / 60)))).toISOString()
此实用程序功能中的更多详细信息
function getLocaLTime() { // new Date().getTimezoneOffset() : getTimezoneOffset in minutes //for GMT + 1 it is (-60) //for GMT + 2 it is (-120) //.. let time_zone_offset_in_hours = new Date().getTimezoneOffset() / 60; //get current datetime hour let current_hour = new Date().getHours(); //adjust current date hour let local_datetime_in_milliseconds = new Date().setHours(current_hour - time_zone_offset_in_hours); //format date in milliseconds to ISO String let local_datetime = new Date(local_datetime_in_milliseconds).toISOString(); return local_datetime; }
我发现这个功能在我所有的项目中都非常有用。你也可以使用它。
getStartTime(){
let date = new Date();
var tz = date.toString().split("GMT")[1].split(" (")[0];
tz = tz.substring(1,5);
let hOffset = parseInt(tz[0]+tz[1]);
let mOffset = parseInt(tz[2]+tz[3]);
let offset = date.getTimezoneOffset() * 60 * 1000;
let localTime = date.getTime();
let utcTime = localTime + offset;
let austratia_brisbane = utcTime + (3600000 * hOffset) + (60000 * mOffset);
let customDate = new Date(austratia_brisbane);
let data = {
day: customDate.getDate(),
month: customDate.getMonth() + 1,
year: customDate.getFullYear(),
hour: customDate.getHours(),
min: customDate.getMinutes(),
second: customDate.getSeconds(),
raw: customDate,
stringDate: customDate.toString()
}
return data;
}
这将根据您的时区为您提供时间。
谢谢。
这是使用 fetch 和https://worldtimeapi.org/api在 2020 年 9 月运行良好的版本
fetch("https://worldtimeapi.org/api/ip")
.then(response => response.json())
.then(data => console.log(data.dst,data.datetime));
我发现显示城市或位置当地时间的最可靠方法是利用时区 API,例如Google Time Zone API。它返回正确的时区,更重要的是,任何位置的夏令时偏移量,据我所知,仅使用 JavaScript 的 Date() 对象是无法完成的。这里有一个关于使用 API 获取和显示本地时间的很好的教程:
var loc = '35.731252, 139.730291' // Tokyo expressed as lat,lng tuple
var targetDate = new Date() // Current date/time of user computer
var timestamp = targetDate.getTime() / 1000 + targetDate.getTimezoneOffset() * 60 // Current UTC date/time expressed as seconds since midnight, January 1, 1970 UTC
var apikey = 'YOUR_TIMEZONE_API_KEY_HERE'
var apicall = 'https://maps.googleapis.com/maps/api/timezone/json?location=' + loc + '×tamp=' + timestamp + '&key=' + apikey
var xhr = new XMLHttpRequest() // create new XMLHttpRequest2 object
xhr.open('GET', apicall) // open GET request
xhr.onload = function() {
if (xhr.status === 200) { // if Ajax request successful
var output = JSON.parse(xhr.responseText) // convert returned JSON string to JSON object
console.log(output.status) // log API return status for debugging purposes
if (output.status == 'OK') { // if API reports everything was returned successfully
var offsets = output.dstOffset * 1000 + output.rawOffset * 1000 // get DST and time zone offsets in milliseconds
var localdate = new Date(timestamp * 1000 + offsets) // Date object containing current time of Tokyo (timestamp + dstOffset + rawOffset)
console.log(localdate.toLocaleString()) // Display current Tokyo date and time
}
} else {
alert('Request failed. Returned status of ' + xhr.status)
}
}
xhr.send() // send request
我需要在本地时间向服务器报告客户端发生的事情。(在这个特定的商业案例中,UTC 没有提供任何价值)。我需要使用 toIsoString() 来使格式与 .Net MVC 兼容,但是 toIsoString() 这总是将其转换为 UTC 时间(正在发送到服务器)。
受“amit saini”答案的启发,我现在使用这个
function toIsoStringInLocalTime(date) {
return new Date((date.getTime() + (-date.getTimezoneOffset() * 60000))).toISOString()
}
我的代码是
function display_c(){
var refresh=1000; // Refresh rate in milli seconds
mytime=setTimeout('display_ct()',refresh)
}
function display_ct() {
var strcount
var x = new Date()
document.getElementById('ct').innerHTML = x;
tt=display_c();
}
<body onload=display_ct();>
<span id='ct' ></span>
</body>
您还可以创建自己的 nodeJS 端点,使用 heroku 之类的东西发布它,然后访问它
require("http").createServer(function (q,r) {
r.setHeader("accees-control-allow-origin","*")
r.end(Date.now())
}).listen(process.env.PORT || 80)
然后在JS上访问它
fetch ("http://someGerokuApp")
.then(r=>r.text)
. then (r=>console.log(r))
这仍然与托管节点应用程序的任何计算机相关,但也许您可以通过某种方式获取位置并根据当前时区提供适合其他时区的不同端点(例如,如果服务器恰好在加利福尼亚,那么对于纽约时区只需将1000*60*60*3
毫秒添加到 Date.now() 以添加 3 小时)
为简单起见,如果可以从服务器获取位置并将其作为响应标头发送,则只需在客户端对不同时区进行计算
实际上,使用 heroku,它们允许您指定应该在https://devcenter.heroku.com/articles/regions#specifying-a-region上部署的区域,您可以将其用作参考。
编辑刚刚意识到时区在日期字符串本身中,可以将整个内容作为标题支付给客户端读取
require("http").createServer(function (q,r) {
var d= new Date()
r.setHeader("accees-control-allow-origin","*")
r.setHeader("zman", d.toString())
r.end(d.getTime())
}).listen(process.env.PORT || 80)
试试这种方式
function timenow(){
var now= new Date(),
ampm= 'am',
h= now.getHours(),
m= now.getMinutes(),
s= now.getSeconds();
if(h>= 12){
if(h>12) h -= 12;
ampm= 'pm';
}
if(m<10) m= '0'+m;
if(s<10) s= '0'+s;
return now.toLocaleDateString()+ ' ' + h + ':' + m + ':' + s + ' ' + ampm;
}
toLocaleDateString()
是更改日期时间格式的功能,例如toLocaleDateString("en-us")
new Date(Date.now() + (-1*new Date().getTimezoneOffset()*60000)).toISOString()