2010-05-05 40 views
80

Trong ứng dụng JS, tôi nhận được dấu thời gian (eq. 1270544790922) từ máy chủ (Ajax).Cách bỏ qua múi giờ của người dùng và lực Ngày() sử dụng múi giờ cụ thể

Căn cứ vào dấu thời gian mà tôi tạo ra Date đối tượng sử dụng:

var _date = new Date(); 
_date.setTime(1270544790922); 

Bây giờ, _date giải mã dấu thời gian theo múi giờ dùng locale hiện hành. Tôi không muốn điều đó.

Tôi muốn _ date chuyển đổi dấu thời gian này thành thời gian hiện tại ở thành phố Helsinki ở châu Âu (bỏ qua múi giờ hiện tại của người dùng).

Tôi có thể làm như thế nào?

+0

Tôi biết rằng chênh lệch múi giờ ở Helsinki là +2 vào mùa đông và +3 trong DST. Nhưng ai biết khi nào là DST? Chỉ có một số cơ chế cục bộ không có sẵn trong JS – warpech

+0

Có thể, nhưng không sử dụng các phương thức gốc của Javascript, vì javascript không có phương pháp để xác định lịch sử chuyển đổi múi giờ của múi giờ khác so với múi giờ hiện tại của hệ thống của người dùng (và nó là theo cách trình duyệt phụ thuộc ít nhất là khi chúng ta đến ngày 80). Nhưng theo cách này, có thể: http://stackoverflow.com/a/12814213/1691517 và tôi nghĩ rằng câu trả lời của tôi cho bạn kết quả chính xác. –

+0

http://www.w3schools.com/jsref/jsref_setutcmilliseconds.asp – radpin

Trả lời

56

Giá trị cơ bản của đối tượng ngày thực tế là trong UTC. Để chứng minh điều này, hãy lưu ý rằng nếu bạn nhập new Date(0), bạn sẽ thấy một cái gì đó như: Wed Dec 31 1969 16:00:00 GMT-0800 (PST). 0 được coi là 0 trong GMT, nhưng phương pháp .toString() hiển thị giờ địa phương.

Ghi chú lớn, UTC là viết tắt của Universal mã thời gian. Hiện tại thời điểm hiện tại ở 2 địa điểm khác nhau là cùng một UTC, nhưng đầu ra có thể được định dạng khác nhau.

Những gì chúng ta cần ở đây là một số định dạng

var _date = new Date(1270544790922); 
// outputs > "Tue Apr 06 2010 02:06:30 GMT-0700 (PDT)", for me 
_date.toLocaleString('fi-FI', { timeZone: 'Europe/Helsinki' }); 
// outputs > "6.4.2010 klo 12.06.30" 
_date.toLocaleString('en-US', { timeZone: 'Europe/Helsinki' }); 
// outputs > "4/6/2010, 12:06:30 PM" 

này hoạt động nhưng .... bạn có thể không thực sự sử dụng bất kỳ phương pháp ngày khác vì mục đích của bạn vì chúng mô tả múi giờ của người dùng. Những gì bạn muốn là một đối tượng ngày có liên quan đến múi giờ Helsinki. Tùy chọn của bạn tại thời điểm này là sử dụng một số thư viện của bên thứ ba (tôi khuyên bạn nên sử dụng), hoặc hack-up đối tượng ngày để bạn có thể sử dụng hầu hết các phương thức của nó.

Lựa chọn 1 - một bên thứ 3 như lúc-múi giờ

moment(1270544790922).tz('Europe/Helsinki').format('YYYY-MM-DD HH:mm:ss') 
// outputs > 2010-04-06 12:06:30 
moment(1270544790922).tz('Europe/Helsinki').hour() 
// outputs > 12 

này trông rất thanh lịch hơn so với những gì chúng tôi sắp làm gì tiếp theo.

Lựa chọn 2 - Hack lên đối tượng ngày

var currentHelsinkiHoursOffset = 2; // sometimes it is 3 
var date = new Date(1270544790922); 
var helsenkiOffset = currentHelsinkiHoursOffset*60*60000; 
var userOffset = _date.getTimezoneOffset()*60000; // [min*60000 = ms] 
var helsenkiTime = new Date(date.getTime()+ helsenkiOffset + userOffset); 
// Outputs > Tue Apr 06 2010 12:06:30 GMT-0700 (PDT) 

Nó vẫn nghĩ đó là GMT-0700 (PDT), nhưng nếu bạn không nhìn chằm chằm quá khó bạn có thể nhầm lẫn rằng đối với một ngày đối tượng đó là hữu ích cho các mục đích của bạn.

Tôi thuận tiện bỏ qua một phần. Bạn cần có khả năng xác định currentHelsinkiOffset. Nếu bạn có thể sử dụng date.getTimezoneOffset() ở phía máy chủ hoặc chỉ sử dụng một số câu lệnh if để mô tả thời điểm thay đổi múi giờ sẽ xảy ra, điều đó sẽ giải quyết được sự cố của bạn.

Kết luận - Tôi nghĩ đặc biệt cho mục đích này bạn nên sử dụng thư viện ngày như moment-timezone.

+0

cũng ... một tác vụ tương tự có thể được thực hiện, đơn giản bằng cách sử dụng phần bù gmt từ một vị trí. Bạn không cần javascript ở tất cả trong trường hợp đó. – Parris

+0

xin lỗi nhưng không, ý tôi là đối diện chính xác :) Tôi đã chỉnh sửa câu hỏi, có thể bây giờ là rõ ràng hơn – warpech

+0

Ok Tôi đã thay đổi giải pháp của mình. Tôi nghĩ rằng đây là những gì bạn đang tìm kiếm. – Parris

15

Để giải thích cho mili giây và múi giờ của người dùng, sử dụng như sau:

var _userOffset = _date.getTimezoneOffset()*60*1000; // user's offset time 
var _centralOffset = 6*60*60*1000; // 6 for central time - use whatever you need 
_date = new Date(_date.getTime() - _userOffset + _centralOffset); // redefine variable 
+0

Để thay thế bằng cách sử dụng một bù đắp cố định cho trung tâm, tôi đã sử dụng khái niệm tạo ngày bằng cách sử dụng CST với thời gian cố định là 00:00, sau đó getUTCHHours của ngày đó. – grantwparks

+0

+1 Điều này làm việc cho tôi. Bạn không chắc chắn câu trả lời có thể hoạt động như thế nào mà không cần xử lý trong mili giây. –

+2

@ Bạn không nên thêm timezoneOffset để nhận gmt và sau đó trừ bù trung tâm? – coder

13

Tôi có một nghi ngờ, rằng Answer không cho kết quả chính xác.Trong câu hỏi, người hỏi muốn chuyển đổi dấu thời gian từ máy chủ sang thời điểm hiện tại trong Hellsinki, bỏ qua múi giờ hiện tại của người dùng.

Thực tế là múi giờ của người dùng có thể là thứ bao giờ nên chúng tôi không thể tin tưởng vào nó.

Nếu có. timestamp là 1270544790922 và chúng tôi có một chức năng:

var _date = new Date(); 
_date.setTime(1270544790922); 
var _helsenkiOffset = 2*60*60;//maybe 3 
var _userOffset = _date.getTimezoneOffset()*60*60; 
var _helsenkiTime = new Date(_date.getTime()+_helsenkiOffset+_userOffset); 

Khi một New Yorker truy cập vào trang, alert (_helsenkiTime) in:

Tue Apr 06 2010 05:21:02 GMT-0400 (EDT) 

Và khi một Finlander truy cập vào trang, alert (_helsenkiTime) in :

Tue Apr 06 2010 11:55:50 GMT+0300 (EEST) 

Vì vậy, các chức năng là đúng chỉ khi người truy cập trang có múi giờ mục tiêu (Châu Âu/Helsinki) trong máy tính của mình, nhưng thất bại trong gần như mọi bộ phận khác trên thế giới. Và vì dấu thời gian máy chủ thường là dấu thời gian UNIX, theo định nghĩa trong UTC, số giây kể từ thời kỳ Unix (ngày 1 tháng 1 năm 1970 00:00:00 GMT), chúng tôi không thể xác định DST hoặc không phải DST từ dấu thời gian.

Vì vậy, giải pháp là DISREGARD múi giờ hiện tại của người dùng và thực hiện một số cách để tính toán bù trừ UTC cho dù ngày có nằm trong DST hay không. Javascript không có phương pháp gốc để xác định lịch sử chuyển đổi DST của múi giờ khác so với múi giờ hiện tại của người dùng. Chúng ta có thể đạt được điều này đơn giản nhất bằng cách sử dụng kịch bản phía máy chủ, bởi vì chúng ta có thể dễ dàng truy cập vào cơ sở dữ liệu múi giờ của máy chủ với toàn bộ lịch sử chuyển đổi của tất cả các múi giờ. Nếu bạn không có quyền truy cập vào cơ sở dữ liệu múi giờ của máy chủ (hoặc bất kỳ máy chủ nào khác) VÀ dấu thời gian ở UTC, bạn có thể nhận được chức năng tương tự bằng cách mã hóa cứng các quy tắc DST trong Javascript.

Để trang trải ngày trong những năm 1998-2099 ở châu Âu/Helsinki bạn có thể sử dụng chức năng sau (jsfiddled):

function timestampToHellsinki(server_timestamp) { 
    function pad(num) { 
     num = num.toString(); 
     if (num.length == 1) return "0" + num; 
     return num; 
    } 

    var _date = new Date(); 
    _date.setTime(server_timestamp); 

    var _year = _date.getUTCFullYear(); 

    // Return false, if DST rules have been different than nowadays: 
    if (_year<=1998 && _year>2099) return false; 

    // Calculate DST start day, it is the last sunday of March 
    var start_day = (31 - ((((5 * _year)/4) + 4) % 7)); 
    var SUMMER_start = new Date(Date.UTC(_year, 2, start_day, 1, 0, 0)); 

    // Calculate DST end day, it is the last sunday of October 
    var end_day = (31 - ((((5 * _year)/4) + 1) % 7)) 
    var SUMMER_end = new Date(Date.UTC(_year, 9, end_day, 1, 0, 0)); 

    // Check if the time is between SUMMER_start and SUMMER_end 
    // If the time is in summer, the offset is 2 hours 
    // else offset is 3 hours 
    var hellsinkiOffset = 2 * 60 * 60 * 1000; 
    if (_date > SUMMER_start && _date < SUMMER_end) hellsinkiOffset = 
    3 * 60 * 60 * 1000; 

    // Add server timestamp to midnight January 1, 1970 
    // Add Hellsinki offset to that 
    _date.setTime(server_timestamp + hellsinkiOffset); 
    var hellsinkiTime = pad(_date.getUTCDate()) + "." + 
    pad(_date.getUTCMonth()) + "." + _date.getUTCFullYear() + 
    " " + pad(_date.getUTCHours()) + ":" + 
    pad(_date.getUTCMinutes()) + ":" + pad(_date.getUTCSeconds()); 

    return hellsinkiTime; 
} 

Ví dụ về sử dụng:

var server_timestamp = 1270544790922; 
document.getElementById("time").innerHTML = "The timestamp " + 
server_timestamp + " is in Hellsinki " + 
timestampToHellsinki(server_timestamp); 

server_timestamp = 1349841923 * 1000; 
document.getElementById("time").innerHTML += "<br><br>The timestamp " + 
server_timestamp + " is in Hellsinki " + timestampToHellsinki(server_timestamp); 

var now = new Date(); 
server_timestamp = now.getTime(); 
document.getElementById("time").innerHTML += "<br><br>The timestamp is now " + 
server_timestamp + " and the current local time in Hellsinki is " + 
timestampToHellsinki(server_timestamp);​ 

Và in này như sau không phân biệt múi giờ của người dùng:

The timestamp 1270544790922 is in Hellsinki 06.03.2010 12:06:30 

The timestamp 1349841923000 is in Hellsinki 10.09.2012 07:05:23 

The timestamp is now 1349853751034 and the current local time in Hellsinki is 10.09.2012 10:22:31 

Tất nhiên nếu bạn có thể quay lại ti mestamp trong một hình thức bù đắp (DST hoặc không phải DST) đã được thêm vào dấu thời gian trên máy chủ, bạn không cần phải tính toán nó clientside và bạn có thể đơn giản hóa các chức năng rất nhiều. NHƯNG nhớ KHÔNG sử dụng timezoneOffset(), bởi vì sau đó bạn phải đối phó với múi giờ của người dùng và đây không phải là hành vi mong muốn.

+2

nb. Helsinki chỉ có một 'l'. Sai lầm này thực sự làm giảm đi câu trả lời này. –

+0

@ BenMcIntyre Đó là một trò đùa nhỏ. Hoặc được cho là như vậy. :) –

0

Bạn có thể sử dụng setUTCMilliseconds()

var _date = new Date(); 
_date.setUTCMilliseconds(1270544790922); 
+0

Câu trả lời này là sai. setUTCMgiây phép thêm số mili giây được chỉ định cho Ngày. – Tibor

+0

@Tibor: Từ MozDev: Phương thức 'setUTCMilliseconds()' đặt mili giây cho một ngày được chỉ định theo thời gian quốc tế. [...] Nếu một tham số bạn chỉ định nằm ngoài phạm vi dự kiến, 'setUTCMilliseconds()' cố gắng cập nhật thông tin ngày tháng trong đối tượng Date tương ứng. Nói cách khác, bạn tạo một đối tượng 'Date' có dấu thời gian Unix đã cho, tại UTC. – jimasun

+0

Từ w3schools: Phương thức setUTCMilliseconds() đặt mili giây (từ 0 đến 999), theo thời gian quốc tế. Hãy thử câu trả lời ở trên và xem cho chính mình. – Tibor

10

Chỉ cần một cách tiếp cận

function parseTimestamp(timestampStr) { 
 
    return new Date(new Date(timestampStr).getTime() + (new Date().getTimezoneOffset() * 60 * 1000)); 
 
}; 
 

 
//Sun Jan 01 2017 12:00:00 
 
var timestamp = 1483272000000; 
 
date = parseTimestamp(timestamp); 
 
document.write(date);

Cheers!

1

Giả sử bạn nhận được dấu thời gian trong thời gian Helsinki, tôi sẽ tạo đối tượng ngày được đặt thành nửa đêm ngày 1 tháng 1 năm 1970 UTC (để bỏ qua cài đặt múi giờ địa phương của trình duyệt). Sau đó, chỉ cần thêm số mili giây cần thiết vào nó.

var _date \t = new Date(Date.UTC(1970, 0, 1, 0, 0, 0, 0)); 
 
_date.setUTCMilliseconds(1270544790922); 
 

 
alert(_date); //date shown shifted corresponding to local time settings 
 
alert(_date.getUTCFullYear()); //the UTC year value 
 
alert(_date.getUTCMonth());  //the UTC month value 
 
alert(_date.getUTCDate());  //the UTC day of month value 
 
alert(_date.getUTCHours());  //the UTC hour value 
 
alert(_date.getUTCMinutes());  //the UTC minutes value

Xem ra sau, để luôn tự hỏi giá trị tính theo giờ UTC từ đối tượng ngày. Bằng cách này, người dùng sẽ thấy các giá trị ngày giống nhau bất kể cài đặt cục bộ. Nếu không, giá trị ngày sẽ được dịch chuyển tương ứng với cài đặt giờ địa phương.

Các vấn đề liên quan