Parsing tanggal tanpa javascript zona waktu

147

Saya ingin menguraikan tanggal tanpa zona waktu dalam JavaScript. Saya telah mencoba:

new Date(Date.parse("2005-07-08T00:00:00+0000"));

Pengembalian Jum 08 Jul 2005 02:00:00 GMT + 0200 (Waktu Siang Eropa Tengah)

new Date(Date.parse("2005-07-08 00:00:00 GMT+0000"));

Menghasilkan hasil yang sama

new Date(Date.parse("2005-07-08 00:00:00 GMT-0000"));

Menghasilkan hasil yang sama

Saya ingin menguraikan waktu:

  1. Tanpa zona waktu.

  2. Tanpa memanggil konstruktor Date.UTC atau Tanggal baru (tahun, bulan, hari).

  3. Sederhananya lewat string ke konstruktor Tanggal (tanpa pendekatan prototipe).

  4. Saya harus Dateobjek produk , tidak String.

Athlan
sumber
3
Anda bisa menghilangkan Date.parsebtw dan langsung meneruskan string ke Datekonstruktor.
Bergi
1
Saya tidak yakin mengapa Anda membutuhkan ini, tetapi saya cukup yakin Date selalu memiliki zona waktu lokal pengguna. Jika Anda ingin JavaScript Anda bekerja dengan zona waktu selain daripada Anda harus menggunakan objek pembungkus untuk Date, mungkin ini akan bekerja untuk Anda: github.com/mde/timezone-js
HMR
1
Sayangnya, saya harus menyalin Dateobjek untuk mendapatkan objek yang benar untuk membandingkan tanggal di MongoDB:new Date(dateStart.getFullYear(), dateStart.getMonth(), dateStart.getDate())
Athlan
Jika Anda ingin menguraikan tanggal tanpa waktu, Anda perlu menentukan zona waktu yang ingin Anda asumsikan, karena "2005-07-08" memiliki arti yang berbeda di zona waktu yang berbeda. Pada Mei 2020, dokumentasi MDN menyarankan agar fitur parsing Date buit-in tidak ada karena perbedaan dalam implementasi. Namun, menggunakan Date.parse ("2005-07-08") mungkin akan mengembalikan waktu 00:00 UTC. date-fns parse di sisi lain, akan kembali pukul 00:00 waktu setempat ketika mengurai string tanggal yang sama
Andy

Jawaban:

106

Tanggal diuraikan dengan benar, hanya toString yang mengubahnya menjadi zona waktu lokal Anda:

let s = "2005-07-08T11:22:33+0000";
let d = new Date(Date.parse(s));

// this logs for me 
// "Fri Jul 08 2005 13:22:33 GMT+0200 (Central European Summer Time)" 
// and something else for you

console.log(d.toString()) 

// this logs
// Fri, 08 Jul 2005 11:22:33 GMT
// for everyone

console.log(d.toUTCString())

Objek Date Javascript adalah cap waktu - mereka hanya mengandung sejumlah milidetik sejak zaman. Tidak ada info zona waktu di objek Tanggal. Tanggal kalender mana (hari, menit, detik) yang diwakili oleh stempel waktu ini adalah masalah interpretasi (salah satu to...Stringmetode).

Contoh di atas menunjukkan bahwa tanggal sedang diurai dengan benar - yaitu, sebenarnya berisi jumlah milidetik yang sesuai dengan "2005-07-08T11: 22: 33" dalam GMT.

georg
sumber
4
Sayangnya saya harus menghasilkan objek Date, bukan String.
Athlan
@Athlan: menambahkan beberapa penjelasan.
georg
1
Saya sudah memeriksanya. Saya telah melewati tanggal parsing ke dalam permintaan MongoDB new Date(Date.parse("2005-07-08T11:22:33+0000")), dan tanggal disalin melalui konstruktor: new Date(dateStart.getFullYear(), dateStart.getMonth(), dateStart.getDate()). Kedua solusi, hasil berbeda, kedua benar! Balasan Anda bermanfaat, hanya disebutkan di hunlock.com/blogs/Javascript_Dates-The_Complete_Reference . Naik.
Athlan
Bekerja dengan sempurna untuk saya - .toUTCString () adalah tiket yang memberi saya waktu yang tepat kembali dari string yang diberikan asli. yaitu Tanggal baru ("2016-08-22T19: 45: 00.0000000"). toUTCString ()
Michael Giovanni Pumo
38
Akar semua kejahatan dalam tanggal dan waktu JavaScript terkandung dalam kalimat pertama Anda ... Hanya toString yang mengkonversikannya ke zona waktu lokal Anda ... Di mana tanggung jawab tunggal dalam hal ini? Metode toString seharusnya hanya meringkas hasilnya dan tidak mengubahnya. Jika saya ingin tanggal dikonversi saya harus memiliki metode lain untuk melakukan itu.
jangkar
109

Saya memiliki masalah yang sama. Saya mendapatkan tanggal sebagai String, misalnya: '2016-08-25T00: 00: 00', tetapi saya perlu memiliki objek Date dengan waktu yang benar. Untuk mengonversi String menjadi objek, saya menggunakan getTimezoneOffset:

var date = new Date('2016-08-25T00:00:00')
var userTimezoneOffset = date.getTimezoneOffset() * 60000;
new Date(date.getTime() - userTimezoneOffset);

getTimezoneOffset()akan mengembalikan nilai negatif atau positif eter. Ini harus dikurangkan untuk bekerja di setiap lokasi di dunia.

wawka
sumber
6
Saya memiliki masalah yang sama dan menemukan ini membantu. Namun, saya menemukan bahwa ini tidak menangani offset zona waktu karena waktu musim panas. Contoh: Saya di PST jadi offset saya saat ini (pada bulan Maret) dari GMT adalah -8: 00, tetapi pada bulan Mei akan menjadi -7: 00. Solusi saya adalah menghitungvar userTimezoneOffset = date.getTimezoneOffset()*60000;
mmh02
3
Kecuali saya benar-benar idiot, ini sebenarnya mengembalikan waktu yang salah. getTimezoneOffset()mengembalikan jumlah menit ke arah berlawanan yang Anda pikirkan - zona waktu saya adalah UTC-4 sekarang tetapi getTimezoneOffset()mengembalikan 240 yang positif. Oleh karena itu userTimezoneOffsetharus dikurangi date.getTime(), bukan ditambahkan.
vaindil
1
Saya akan setuju dengan @vaindil Anda harus mengurangi. solusi wakwa hanya bekerja ketika Anda berada di sisi yang benar dari Greenwich. Wakwa harus memperbaikinya.
Janne Harju
1
Ah! berbicara terlalu cepat. Ini tidak berfungsi untuk sebagian besar zona waktu. Saya dapat mengonfirmasi bahwa ia mengembalikan tanggal yang salah ketika mengimbangi waktu AEST & CEST dengan waktu GMT.
saran3h
1
@vaindil sekarang hasilnya sama dengan yang new Date('2016-08-25T00:00:00Z')saya pikir intinya adalah untuk memanipulasi new Date('2016-08-25T00:00:00Z')sehingga waktu lokal ditampilkan dengan waktu 0:00 tetapi kode ini tidak terjawabZ
barbsan
14

Saya mengalami masalah yang sama dan kemudian teringat sesuatu yang aneh tentang proyek warisan yang sedang saya kerjakan dan bagaimana mereka menangani masalah ini. Saya tidak memahaminya pada saat itu dan tidak terlalu peduli sampai saya mengalami masalah sendiri

var date = '2014-01-02T00:00:00.000Z'
date = date.substring(0,10).split('-')
date = date[1] + '-' + date[2] + '-' + date[0]

new Date(date) #Thu Jan 02 2014 00:00:00 GMT-0600

Untuk alasan apa pun yang melewatkan tanggal sebagai '01 -02-2014 'menetapkan zona waktu ke nol dan mengabaikan zona waktu pengguna. Ini mungkin kebetulan di kelas Date tetapi ada beberapa waktu lalu dan ada hari ini. Dan tampaknya berfungsi lintas-browser. Cobalah sendiri.

Kode ini diimplementasikan dalam proyek global di mana zona waktu sangat berarti tetapi orang yang melihat tanggal tersebut tidak peduli kapan tepatnya itu diperkenalkan.

Iwnnay
sumber
Saya pikir ini disengaja karena "Z" menunjuk UTC yang kemudian dikonversi oleh JS, tetapi tanpa zona waktu, ia tidak dapat mengubahnya sehingga pada dasarnya mengasumsikan zona waktu pengguna. Akan sangat senang mendapatkan konfirmasi atau penjelasan yang lebih baik.
dlsso
7
Perilaku miring adalah karena tanda hubung. Chrome, Firefox, dan IE11 semuanya menafsirkan 2014/5/31dan 2014/05/31sebagai Sabtu, 31 Mei 2014 00:00:00 GMT-0600 (Waktu Siang Gunung) `(MDT menjadi zona waktu saya saat ini). Dengan tanda hubung ... semua browser mengartikan 2014-05-31sebagai Jum 30 Mei 2014 18:00:00 GMT-0600 (Waktu Siang Gunung). Anehnya, dengan 2014-5-31, Chrome kembali pada hari Sabtu, Firefox kembali pada hari Jumat, dan IE11 mengatakan tanggal tersebut tidak valid. Sepertinya date.replace('-','/')bisa melakukan trik.
atheaos
6

The Dateobyek itu sendiri akan berisi zona waktu pula, dan hasil yang dikembalikan adalah efek dari mengubahnya menjadi string dengan cara default. Yaitu Anda tidak dapat membuat objek tanggal tanpa zona waktu. Tapi yang bisa Anda lakukan adalah meniru perilaku Dateobjek dengan membuat objek Anda sendiri. Namun, ini lebih baik diserahkan ke perpustakaan seperti moment.js .

mishik
sumber
2
Sayangnya saya harus menghasilkan objek Date, bukan String.
Athlan
3

solusi sederhana

const handler1 = {
  construct(target, args) {
    let newDate = new target(...args);
    var tzDifference = newDate.getTimezoneOffset();
    return new target(newDate.getTime() + tzDifference * 60 * 1000);
  }
};

Date = new Proxy(Date, handler1);
alexey
sumber
3

Tanggal dalam javascript hanya menjaganya agar tetap sederhana. sehingga data tanggal-waktu disimpan dalam UTC unix epoch (milidetik atau ms).

Jika Anda ingin memiliki waktu "tetap" yang tidak berubah di zona waktu apa pun di bumi, Anda dapat menyesuaikan waktu di UTC agar sesuai dengan zona waktu lokal Anda saat ini dan menyimpannya. Dan ketika mengambilnya kembali, di zona waktu lokal mana pun Anda berada, itu akan menunjukkan waktu UTC yang disesuaikan berdasarkan orang yang menyimpannya dan menambahkan offset zona waktu lokal untuk mendapatkan waktu "tetap".

Untuk menyimpan tanggal (dalam ms)

toUTC(datetime) {
  const myDate = (typeof datetime === 'number')
    ? new Date(datetime)
    : datetime;

  if (!myDate || (typeof myDate.getTime !== 'function')) {
    return 0;
  }

  const getUTC = myDate.getTime();
  const offset = myDate.getTimezoneOffset() * 60000; // It's in minutes so convert to ms
  return getUTC - offset; // UTC - OFFSET
}

Untuk mengambil / menampilkan tanggal (dalam ms)

fromUTC(datetime) {
  const myDate = (typeof datetime === 'number')
    ? new Date(datetime)
    : datetime;

  if (!myDate || (typeof myDate.getTime !== 'function')) {
    return 0;
  }

  const getUTC = myDate.getTime();
  const offset = myDate.getTimezoneOffset() * 60000; // It's in minutes so convert to ms
  return getUTC + offset; // UTC + OFFSET
}

Maka kamu bisa:

const saveTime = new Date(toUTC(Date.parse("2005-07-08T00:00:00+0000")));
// SEND TO DB....

// FROM DB...
const showTime = new Date(fromUTC(saveTime));
DRBendanillo
sumber
2

Anda dapat menggunakan kode ini

var stringDate = "2005-07-08T00:00:00+0000";
var dTimezone = new Date();
var offset = dTimezone.getTimezoneOffset() / 60;
var date = new Date(Date.parse(stringDate));
date.setHours(date.getHours() + offset);
deype0
sumber
1
Saya tidak percaya ini memperhitungkan penghematan siang hari
Daniel Thompson
2

Karena ini benar-benar masalah pemformatan saat menampilkan tanggal (mis. Tampilan dalam waktu lokal), saya ingin menggunakan objek Intl.ateTimeFormat (ish) yang baru untuk melakukan pemformatan karena lebih eksplisit dan memberikan lebih banyak opsi keluaran:

const dateOptions = { timeZone: 'UTC', month: 'long', day: 'numeric', year: 'numeric' };

const dateFormatter = new Intl.DateTimeFormat('en-US', dateOptions);
const dateAsFormattedString = dateFormatter.format(new Date('2019-06-01T00:00:00.000+00:00'));

console.log(dateAsFormattedString) // "June 1, 2019"

Seperti yang ditunjukkan, dengan mengatur zona waktu ke 'UTC' maka tidak akan melakukan konversi lokal. Sebagai bonus, ini juga memungkinkan Anda untuk membuat lebih banyak output yang dipoles. Anda dapat membaca lebih lanjut tentang objek Intl.DateTimeFormat dari Mozilla - Intl.DateTimeFormat .

Edit:

Fungsionalitas yang sama dapat dicapai tanpa membuat Intl.DateTimeFormatobjek baru . Cukup berikan opsi lokal dan tanggal langsung ketoLocaleDateString() fungsi.

const dateOptions = { timeZone: 'UTC', month: 'long', day: 'numeric', year: 'numeric' };
const myDate = new Date('2019-06-01T00:00:00.000+00:00');
today.toLocaleDateString('en-US', dateOptions); // "June 1, 2019"
John Galt
sumber
1

Hanya catatan umum. cara untuk membuatnya fleksibel.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date

Kita dapat menggunakan getMinutes (), tetapi hanya mengembalikan satu nomor selama 9 menit pertama.

let epoch = new Date() // Or any unix timestamp

let za = new Date(epoch),
    zaR = za.getUTCFullYear(),
    zaMth = za.getUTCMonth(),
    zaDs = za.getUTCDate(),
    zaTm = za.toTimeString().substr(0,5);

console.log(zaR +"-" + zaMth + "-" + zaDs, zaTm)

Date.prototype.getDate()
    Returns the day of the month (1-31) for the specified date according to local time.
Date.prototype.getDay()
    Returns the day of the week (0-6) for the specified date according to local time.
Date.prototype.getFullYear()
    Returns the year (4 digits for 4-digit years) of the specified date according to local time.
Date.prototype.getHours()
    Returns the hour (0-23) in the specified date according to local time.
Date.prototype.getMilliseconds()
    Returns the milliseconds (0-999) in the specified date according to local time.
Date.prototype.getMinutes()
    Returns the minutes (0-59) in the specified date according to local time.
Date.prototype.getMonth()
    Returns the month (0-11) in the specified date according to local time.
Date.prototype.getSeconds()
    Returns the seconds (0-59) in the specified date according to local time.
Date.prototype.getTime()
    Returns the numeric value of the specified date as the number of milliseconds since January 1, 1970, 00:00:00 UTC (negative for prior times).
Date.prototype.getTimezoneOffset()
    Returns the time-zone offset in minutes for the current locale.
Date.prototype.getUTCDate()
    Returns the day (date) of the month (1-31) in the specified date according to universal time.
Date.prototype.getUTCDay()
    Returns the day of the week (0-6) in the specified date according to universal time.
Date.prototype.getUTCFullYear()
    Returns the year (4 digits for 4-digit years) in the specified date according to universal time.
Date.prototype.getUTCHours()
    Returns the hours (0-23) in the specified date according to universal time.
Date.prototype.getUTCMilliseconds()
    Returns the milliseconds (0-999) in the specified date according to universal time.
Date.prototype.getUTCMinutes()
    Returns the minutes (0-59) in the specified date according to universal time.
Date.prototype.getUTCMonth()
    Returns the month (0-11) in the specified date according to universal time.
Date.prototype.getUTCSeconds()
    Returns the seconds (0-59) in the specified date according to universal time.
Date.prototype.getYear()
    Returns the year (usually 2-3 digits) in the specified date according to local time. Use getFullYear() instead. 
NVRM
sumber
-1

(new Date().toString()).replace(/ \w+-\d+ \(.*\)$/,"")

Ini akan menghasilkan: Sel 10 Jul 2018 19:07:11

(new Date("2005-07-08T11:22:33+0000").toString()).replace(/ \w+-\d+ \(.*\)$/,"")

Ini akan menghasilkan: Jumat 08 Juli 2005 04:22:33

Catatan: Waktu yang dikembalikan akan tergantung pada zona waktu lokal Anda

xxnations
sumber
-1

Ini adalah solusi yang saya buat untuk masalah ini yang bekerja untuk saya.


perpustakaan digunakan: momentjs dengan kelas Tanggal javascript polos.

Langkah 1. Konversi String date to object moment (PS: moment mempertahankan tanggal dan waktu asli selama toDate()metode tidak dipanggil):

const dateMoment = moment("2005-07-08T11:22:33+0000");

Langkah 2. Ekstrak hoursdan minutesnilai dari objek momen yang dibuat sebelumnya:

  const hours = dateMoment.hours();
  const mins = dateMoment.minutes();

Langkah 3. Konversi momen ke Tanggal (PS: ini akan mengubah tanggal asli berdasarkan zona waktu browser / mesin Anda, tetapi jangan khawatir dan baca langkah 4.):

  const dateObj = dateMoment.toDate();

Langkah 4. Secara manual mengatur jam dan menit diekstraksi dalam Langkah 2.

  dateObj.setHours(hours);
  dateObj.setMinutes(mins);

Langkah 5. dateObj sekarang akan menampilkan Tanggal asli tanpa perbedaan zona waktu. Bahkan perubahan waktu Siang hari tidak akan berpengaruh pada objek tanggal karena kami secara manual mengatur jam dan menit asli.

Semoga ini membantu.

saran3h
sumber
-7

Ada beberapa masalah inheren dengan penguraian tanggal yang sayangnya tidak ditangani dengan baik secara default.

Tanggal yang dapat dibaca manusia memiliki zona waktu tersirat di dalamnya
Ada banyak format tanggal yang banyak digunakan di seluruh web yang ambigu.

Untuk menyelesaikan masalah ini dengan mudah dan bersih, dibutuhkan fungsi seperti ini:

>parse(whateverDateTimeString,expectedDatePattern,timezone)
"unix time in milliseconds"

Saya telah mencari ini, tetapi tidak menemukan yang seperti itu!

Jadi saya membuat: https://github.com/zsoltszabo/timestamp-grabber

Nikmati!

pengguna2667976
sumber