JSON Stringify thay đổi thời gian trong ngày do UTC


98

Đối tượng ngày tháng của tôi trong JavaScript luôn được biểu thị bằng UTC +2 vì vị trí của tôi. Do đó như thế này

Mon Sep 28 10:00:00 UTC+0200 2009

Sự cố đang thực hiện JSON.stringifychuyển đổi ngày ở trên thành

2009-09-28T08:00:00Z  (notice 2 hours missing i.e. 8 instead of 10)

Những gì tôi cần là ngày và giờ được tôn vinh nhưng không phải vậy, do đó nó phải là

2009-09-28T10:00:00Z  (this is how it should be)

Về cơ bản tôi sử dụng cái này:

var jsonData = JSON.stringify(jsonObject);

Tôi đã thử chuyển tham số thay thế (tham số thứ hai trên stringify) nhưng vấn đề là giá trị đã được xử lý.

Tôi cũng đã thử sử dụng toString()toUTCString()trên đối tượng ngày tháng, nhưng chúng cũng không mang lại cho tôi những gì tôi muốn ..

Ai giúp tôi với?


17
2009-09-28T10:00:00Z không đại diện cho cùng một thời điểm trong thời gian như Mon Sep 28 10:00:00 UTC+0200 2009. Ngày Ztrong ISO 8601 có nghĩa là UTC và 10 giờ ở UTC là thời điểm khác với 10 giờ ở +0200. Sẽ là một điều nếu bạn muốn ngày được tuần tự với múi giờ phù hợp, nhưng bạn đang yêu cầu chúng tôi giúp bạn tuần tự hóa nó thành một đại diện sai rõ ràng, khách quan .
Mark Amery

1
Để thêm vào Marks bình luận, trong nhiều trường hợp nó là thực hành tốt nhất để lưu trữ datetimes của bạn như UTC thời gian, vì vậy bạn có thể hỗ trợ người sử dụng trong các múi giờ khác nhau
JoeCodeFrog

Câu trả lời:


67

Gần đây tôi đã gặp phải vấn đề tương tự. Và nó đã được giải quyết bằng cách sử dụng mã sau:

x = new Date();
let hoursDiff = x.getHours() - x.getTimezoneOffset() / 60;
let minutesDiff = (x.getHours() - x.getTimezoneOffset()) % 60;
x.setHours(hoursDiff);
x.setMinutes(minutesDiff);

có nhưng đây là nếu trang web được sử dụng trong nước của tôi, nếu nó được sử dụng ở một nước khác như Hoa Kỳ - nó sẽ không có 2 ...
mark smith

Rõ ràng, giá trị này nên được tính toán.
Anatoliy

3
cảm ơn ... Tôi thực sự đã tìm thấy một thư viện tuyệt vời ở đây, blog.stevenlevithan.com/archives/date-time-format , tất cả những gì bạn cần để làm điều này (có thể nó sẽ giúp bạn), bạn vượt qua false và nó không chuyển đổi. var something = dateFormat (myStartDate, "isoDateTime", false);
mark smith,

11
điều này không chính xác vì nó làm cho mã của bạn không an toàn với múi giờ - bạn nên sửa múi giờ khi bạn đọc ngày trở lại.
olliej 28/09/09

4
Câu trả lời này là sai. OP không nhận ra rằng "2009-09-28T08: 00: 00Z" và "Thứ Hai ngày 28 tháng 9 10:00:00 UTC + 0200 2009" chính xác là cùng một thời điểm và việc điều chỉnh chênh lệch múi giờ thực sự đang tạo ra sai thời điểm.
RobG

41

JSON sử dụng Date.prototype.toISOStringhàm không đại diện cho giờ địa phương - nó biểu thị thời gian theo UTC không được sửa đổi - nếu bạn nhìn vào kết quả ngày của mình, bạn có thể thấy bạn đang ở UTC + 2 giờ, đó là lý do tại sao chuỗi JSON thay đổi hai giờ, nhưng nếu điều này cho phép cùng một thời gian được biểu diễn chính xác trên nhiều múi giờ.


2
Không bao giờ nghĩ về điều này, nhưng bạn đã đúng. Đây là giải pháp: Tôi có thể chỉ định bất kỳ định dạng nào tôi thích bằng cách sử dụng tạo mẫu.
racs


9

Đây là một câu trả lời khác (và cá nhân tôi nghĩ nó phù hợp hơn)

var currentDate = new Date(); 
currentDate = JSON.stringify(currentDate);

// Now currentDate is in a different format... oh gosh what do we do...

currentDate = new Date(JSON.parse(currentDate));

// Now currentDate is back to its original form :)

@Rohaan cảm ơn bạn đã chỉ ra điều đó nhưng các thẻ trên câu hỏi đề cập đến JavaScript.
Tháng Tám

6

date.toJSON () in UTC-Date thành một Chuỗi được định dạng (Vì vậy, thêm phần bù với nó khi chuyển đổi nó sang định dạng JSON).

date = new Date();
new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toJSON();

6
Thông thường, bạn nên thêm giải thích về những gì mã của bạn làm. Điều này cho phép các nhà phát triển mới hơn hiểu cách mã hoạt động.
Caleb Kleveter

Bạn có thể giải thích tại sao mã trong câu trả lời nên hoạt động không?
Cristik

Điều này cũng hoạt động cho tôi, nhưng bạn có thể giải thích cách bạn đã làm điều đó?
Deven Patil

Tôi sẽ cố gắng giải thích dòng thứ hai của mã này .. date.getTime()trả về thời gian tính bằng mili giây, vì vậy chúng ta cũng nên chuyển đổi toán hạng thứ hai thành mili giây. Vì date.getTimezoneOffset()lợi nhuận bù theo phút, chúng tôi nhân nó với 60000, vì 1 phút = 60000 mili giây. Vì vậy, bằng cách trừ đi phần bù cho thời gian hiện tại, chúng ta sẽ có thời gian tính theo UTC.
Maksim Pavlov

4

bạn có thể sử dụng moment.js để định dạng theo giờ địa phương:

Date.prototype.toISOString = function () {
    return moment(this).format("YYYY-MM-DDTHH:mm:ss");
};

không ghi đè ngày lớp chung. Nó có thể dễ dàng phá vỡ ứng dụng của bạn nếu sử dụng một số mô-đun bên ngoài.
Viacheslav Dobromyslov

3

Tôi hơi muộn nhưng bạn luôn có thể ghi đè lên hàm toJson trong trường hợp Ngày sử dụng Nguyên mẫu như vậy:

Date.prototype.toJSON = function(){
    return Util.getDateTimeString(this);
};

Trong trường hợp của tôi, Util.getDateTimeString (this) trả về một chuỗi như sau: "2017-01-19T00: 00: 00Z"


2
Lưu ý rằng việc ghi đè toàn cầu trình duyệt có thể phá vỡ các thư viện của bên thứ ba mà bạn nhúng vào và là một cách chống lại lớn. Không bao giờ làm điều này trong sản xuất.
jakub.

2

Thông thường, bạn muốn ngày tháng được hiển thị cho từng người dùng theo giờ địa phương của họ-

đó là lý do tại sao chúng tôi sử dụng GMT (UTC).

Sử dụng Date.parse (jsondatestring) để lấy chuỗi giờ địa phương,

trừ khi bạn muốn giờ địa phương của mình hiển thị cho từng khách truy cập.

Trong trường hợp đó, hãy sử dụng phương pháp của Anatoly.


2

Khắc phục sự cố này bằng cách sử dụng moment.jsthư viện (phiên bản không theo múi giờ).

var newMinDate = moment(datePicker.selectedDates[0]);
var newMaxDate = moment(datePicker.selectedDates[1]);

// Define the data to ask the server for
var dataToGet = {"ArduinoDeviceIdentifier":"Temperatures",
                "StartDate":newMinDate.format('YYYY-MM-DD HH:mm'),
                "EndDate":newMaxDate.format('YYYY-MM-DD HH:mm')
};

alert(JSON.stringify(dataToGet));

Tôi đã sử dụng flatpickr.min.jsthư viện. Thời gian của đối tượng JSON kết quả được tạo khớp với giờ địa phương được cung cấp nhưng bộ chọn ngày.


2

Giải pháp độc đáo để buộc JSON.stringifybỏ qua múi giờ:

  • Javascript thuần túy (dựa trên câu trả lời Anatoliy):

// Before: JSON.stringify apply timezone offset
const date =  new Date();
let string = JSON.stringify(date);
console.log(string);

// After: JSON.stringify keeps date as-is!
Date.prototype.toJSON = function(){
    const hoursDiff = this.getHours() - this.getTimezoneOffset() / 60;
    this.setHours(hoursDiff);
    return this.toISOString();
};
string = JSON.stringify(date);
console.log(string);

Sử dụng thư viện moment.js:

const date =  new Date();
let string = JSON.stringify(date);
console.log(string);

Date.prototype.toJSON = function(){
    return moment(this).format("YYYY-MM-DDTHH:mm:ss:ms");;
};
string = JSON.stringify(date);
console.log(string);
<html>
  <header>
    <script src="https://momentjs.com/downloads/moment.min.js"></script>
    <script src="https://momentjs.com/downloads/moment-timezone-with-data-10-year-range.min.js"></script>
</header>
</html>


2

Tôi gặp phải vấn đề này một chút khi làm việc với những thứ kế thừa nơi chúng chỉ hoạt động ở bờ biển phía đông Hoa Kỳ và không lưu trữ ngày tháng theo giờ UTC, tất cả đều là EST. Tôi phải lọc ngày dựa trên thông tin người dùng nhập vào trình duyệt, vì vậy phải chuyển ngày theo giờ địa phương ở định dạng JSON.

Chỉ để nói rõ hơn về giải pháp này đã được đăng - đây là những gì tôi sử dụng:

// Could be picked by user in date picker - local JS date
date = new Date();

// Create new Date from milliseconds of user input date (date.getTime() returns milliseconds)
// Subtract milliseconds that will be offset by toJSON before calling it
new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toJSON();

Vì vậy, sự hiểu biết của tôi là điều này sẽ tiếp tục và trừ thời gian (tính bằng mili giây (do đó là 60000) từ ngày bắt đầu dựa trên độ lệch múi giờ (trả về phút) - với dự đoán là thời gian cộng thêm vàoJSON () sẽ được thêm vào.


1

Đây là một cái gì đó thực sự gọn gàng và đơn giản (ít nhất tôi tin là như vậy :)) và không yêu cầu thao tác ngày tháng để được sao chép hoặc làm quá tải bất kỳ hàm gốc nào của trình duyệt như toJSON (tham khảo: Cách JSON xâu chuỗi ngày javascript và bảo toàn múi giờ , bạn Shawson tán tỉnh)

Chuyển một hàm thay thế cho JSON.stringify để xâu chuỗi nội dung trái tim của bạn !!! Bằng cách này, bạn không phải thực hiện chênh lệch giờ và phút hoặc bất kỳ thao tác nào khác.

Tôi đã đưa vào console.logs để xem kết quả trung gian để có thể hiểu rõ điều gì đang xảy ra và cách đệ quy hoạt động. Điều đó cho thấy một điều đáng chú ý: giá trị tham số thay thế đã được chuyển đổi sang định dạng ngày ISO :). Sử dụng [phím] này để làm việc với dữ liệu gốc.

var replacer = function(key, value)
{
    var returnVal = value;
    if(this[key] instanceof Date)
    {
        console.log("replacer called with key - ", key, " value - ", value, this[key]); 

        returnVal = this[key].toString();

        /* Above line does not strictly speaking clone the date as in the cloned object 
         * it is a string in same format as the original but not a Date object. I tried 
         * multiple things but was unable to cause a Date object being created in the 
         * clone. 
         * Please Heeeeelp someone here!

        returnVal = new Date(JSON.parse(JSON.stringify(this[key])));   //OR
        returnVal = new Date(this[key]);   //OR
        returnVal = this[key];   //careful, returning original obj so may have potential side effect

*/
    }
    console.log("returning value: ", returnVal);

    /* if undefined is returned, the key is not at all added to the new object(i.e. clone), 
     * so return null. null !== undefined but both are falsy and can be used as such*/
    return this[key] === undefined ? null : returnVal;
};

ab = {prop1: "p1", prop2: [1, "str2", {p1: "p1inner", p2: undefined, p3: null, p4date: new Date()}]};
var abstr = JSON.stringify(ab, replacer);
var abcloned = JSON.parse(abstr);
console.log("ab is: ", ab);
console.log("abcloned is: ", abcloned);

/* abcloned is:
 * {
  "prop1": "p1",
  "prop2": [
    1,
    "str2",
    {
      "p1": "p1inner",
      "p2": null,
      "p3": null,
      "p4date": "Tue Jun 11 2019 18:47:50 GMT+0530 (India Standard Time)"
    }
  ]
}
Note p4date is string not Date object but format and timezone are completely preserved.
*/

1

JavaScript thường chuyển đổi múi giờ địa phương thành UTC.

date = new Date();
date.setMinutes(date.getMinutes()-date.getTimezoneOffset())
JSON.stringify(date)

0

Tất cả đều tổng hợp nếu chương trình phụ trợ máy chủ của bạn có bất khả tri về múi giờ hay không. Nếu không, thì bạn cần phải giả định rằng múi giờ của máy chủ giống với múi giờ của máy khách hoặc chuyển thông tin về múi giờ của máy khách và đưa thông tin đó vào các phép tính.

một ví dụ dựa trên phụ trợ PostgreSQL:

select '2009-09-28T08:00:00Z'::timestamp -> '2009-09-28 08:00:00' (wrong for 10am)
select '2009-09-28T08:00:00Z'::timestamptz -> '2009-09-28 10:00:00+02'
select '2009-09-28T08:00:00Z'::timestamptz::timestamp -> '2009-09-28 10:00:00'

Cái cuối cùng có lẽ là thứ bạn muốn sử dụng trong cơ sở dữ liệu, nếu bạn không sẵn sàng triển khai logic múi giờ đúng cách.


0

Thay vào đó toJSON, bạn có thể sử dụng hàm định dạng luôn cung cấp ngày và giờ chính xác +GMT

Đây là tùy chọn hiển thị mạnh mẽ nhất. Nó cần một chuỗi các mã thông báo và thay thế chúng bằng các giá trị tương ứng của chúng.


0

Tôi đã thử điều này trong góc 8:

  1. tạo Mô hình:

    export class Model { YourDate: string | Date; }
  2. trong thành phần của bạn

    model : Model;
    model.YourDate = new Date();
  3. gửi Ngày đến API của bạn để lưu

  4. Khi tải dữ liệu của bạn từ API, bạn sẽ thực hiện điều này:

    model.YourDate = new Date(model.YourDate+"Z");

bạn sẽ nhận được ngày của bạn một cách chính xác với múi giờ của bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.