แยกวิเคราะห์วันที่โดยไม่มีเขตเวลาจาวาสคริปต์


147

ฉันต้องการแยกวันที่โดยไม่มีเขตเวลาใน JavaScript ฉันเหนื่อย:

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

ส่งคืนวันศุกร์ 7 ก.ค. 2548 02:00:00 GMT + 0200 (เวลามาตรฐานยุโรปกลาง)

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

ส่งคืนผลลัพธ์เดียวกัน

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

ส่งคืนผลลัพธ์เดียวกัน

ฉันต้องการแยกเวลา:

  1. ไม่มีโซนเวลา

  2. โดยไม่ต้องเรียก constructor Date.UTC หรือ Date ใหม่ (ปี, เดือน, วัน)

  3. เพียงแค่ส่งสตริงเข้าไปในตัวสร้าง Date (โดยไม่ต้องเข้าใกล้ต้นแบบ)

  4. ฉันมีกับผลิตภัณฑ์วัตถุไม่ได้DateString


3
คุณสามารถละเว้นDate.parsebtw และส่งสตริงไปยังDateconstructor โดยตรง
Bergi

1
ฉันไม่แน่ใจว่าทำไมคุณต้องการสิ่งนี้ แต่ฉันค่อนข้างแน่ใจว่า Date มีเขตเวลาท้องถิ่นของผู้ใช้เสมอ หากคุณต้องการให้ JavaScript ของคุณทำงานร่วมกับเขตเวลาอื่น ๆ นอกเหนือจากที่คุณจะต้องใช้วัตถุห่อหุ้มสำหรับวันที่อาจจะใช้งานได้กับคุณ: github.com/mde/timezone-js
HMR

1
น่าเสียดายที่ฉันต้องคัดลอกDateวัตถุเพื่อให้ได้วัตถุที่ถูกต้องเพื่อเปรียบเทียบวันที่ใน MongoDB:new Date(dateStart.getFullYear(), dateStart.getMonth(), dateStart.getDate())
Athlan

หากคุณต้องการแยกวันที่โดยไม่มีเวลาคุณต้องระบุเขตเวลาที่คุณต้องการสมมติเพราะ "2005-07-08" หมายถึงสิ่งต่าง ๆ ในเขตเวลาที่แตกต่างกัน ตั้งแต่เดือนพฤษภาคม 2563 เอกสาร MDN ให้คำแนะนำกับการแยกวิเคราะห์วันที่ในลักษณะการทำงานของ buit-in เนื่องจากความแตกต่างในการใช้งาน อย่างไรก็ตามการใช้ Date.parse ("2005-07-08") อาจส่งคืนเวลา 00:00 UTC วันที่ -fns แยกวิเคราะห์ในทางกลับกันจะกลับ 00:00 ตามเวลาท้องถิ่นเมื่อแยกสตริงวันที่เดียวกัน
Andy

คำตอบ:


106

แยกวันที่อย่างถูกต้องเป็นเพียง toString ที่แปลงเป็นเขตเวลาท้องถิ่นของคุณ:

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())

วัตถุวันที่จาวาสคริปต์เป็นเวลา - พวกเขามีเพียงจำนวนมิลลิวินาทีนับตั้งแต่ยุค ไม่มีข้อมูลเขตเวลาในวัตถุ Date วันที่ของปฏิทินใด (วัน, นาที, วินาที) แสดงเวลานี้เป็นเรื่องของการตีความ (หนึ่งในto...Stringวิธีการ)

ตัวอย่างข้างต้นแสดงให้เห็นว่าวันที่จะถูกแยกวิเคราะห์อย่างถูกต้อง - นั่นคือมันมีจำนวนมิลลิวินาทีที่สอดคล้องกับ "2005-07-08T11: 22: 33" ใน GMT


4
น่าเสียดายที่ฉันต้องสร้างวัตถุวันที่ไม่ใช่สตริง
Athlan

@Athlan: เพิ่มคำอธิบายบางอย่าง
georg

1
ฉันตรวจสอบแล้ว ฉันได้ผ่านวันแจงลงในแบบสอบถาม MongoDB และวันที่ผ่านคัดลอกคอนสตรัค:new Date(Date.parse("2005-07-08T11:22:33+0000")) new Date(dateStart.getFullYear(), dateStart.getMonth(), dateStart.getDate())ทั้งวิธีแก้ไขปัญหาผลลัพธ์ที่แตกต่างถูกต้องสองข้อ! คำตอบของคุณเป็นประโยชน์ที่กล่าวถึงเพียงในhunlock.com/blogs/Javascript_Dates-The_Complete_Reference ขึ้น
Athlan

ทำงานอย่างสมบูรณ์แบบสำหรับฉัน - .toUTCString () คือตั๋วที่ให้เวลาฉันถูกต้องย้อนกลับจากสตริงเดิมที่ให้ไว้ ie new Date ("2016-08-22T19: 45: 00.0000000"). toUTCString ()
Michael Giovanni Pumo

38
รากของความชั่วร้ายทั้งหมดในวันที่และเวลาของ JavaScript นั้นบรรจุอยู่ในประโยคแรกของคุณ ... มันเป็นเพียงการแปลงที่แปลงมันเป็นเขตเวลาท้องถิ่นของคุณ ... ความรับผิดชอบเดียวในเรื่องนี้คืออะไร? เมธอด toString ควรทำให้ผลลัพธ์เป็นสตริงและไม่ควรแปลง ถ้าฉันต้องการแปลงวันที่ฉันควรมีวิธีอื่นในการทำเช่นนั้น
สมอ

109

ฉันมีปัญหาเดียวกัน ฉันได้รับวันที่ในรูปแบบสตริงตัวอย่างเช่น: '2016-08-25T00: 00: 00' แต่ฉันต้องการวัตถุวันที่ด้วยเวลาที่ถูกต้อง ในการแปลง String เป็นวัตถุฉันใช้ getTimezoneOffset

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

getTimezoneOffset()จะส่งกลับค่าอีเทอร์เชิงลบหรือบวก ต้องลบออกเพื่อให้สามารถทำงานได้ในทุกที่ในโลก


6
ฉันมีปัญหาเดียวกันและพบว่าสิ่งนี้มีประโยชน์ อย่างไรก็ตามฉันพบว่านี่ไม่ได้จัดการการชดเชยเวลาในเขตเวลาเนื่องจากการปรับเวลาตามฤดูกาล ตัวอย่าง: ฉันอยู่ใน PST ดังนั้นออฟเซ็ตปัจจุบันของฉัน (ในเดือนมีนาคม) จาก GMT คือ -8: 00 แต่ในเดือนพฤษภาคมจะเป็น -7: 00 ทางออกของฉันคือการคำนวณvar userTimezoneOffset = date.getTimezoneOffset()*60000;
mmh02

3
นอกเสียจากว่าฉันจะเป็นคนงี่เง่าที่สมบูรณ์นี่จะส่งคืนเวลาที่ผิด getTimezoneOffset()คืนค่าจำนวนนาทีในทิศทางตรงกันข้ามที่คุณคิด - เขตเวลาของฉันคือ UTC-4 ในขณะนี้ แต่getTimezoneOffset()คืนค่าเป็นบวก 240 ดังนั้นuserTimezoneOffsetควรลบออกdate.getTime()ไม่ใช่เพิ่มเข้าไป
vaindil

1
ฉันจะเห็นด้วยกับ @vaindil คุณควรระงับ วิธีการแก้ปัญหาของ wakwa จะทำงานได้ก็ต่อเมื่อคุณอยู่ในกรีนวิช Wakwas ควรแก้ไขให้ถูกต้อง
Janne Harju

1
อา! พูดเร็วเกินไป มันใช้งานไม่ได้กับเขตเวลาส่วนใหญ่ ฉันสามารถยืนยันได้ว่ามันคืนวันที่ผิดเมื่อทำการชดเชยเวลา AEST & CEST ด้วยเวลา GMT
saran3h

1
@vaindil ตอนนี้ผลเป็นเช่นเดียวกับnew Date('2016-08-25T00:00:00Z')ที่ผมคิดว่าจุดนี้คือการจัดการnew Date('2016-08-25T00:00:00Z')เพื่อให้เวลาท้องถิ่นจะแสดงเวลา 00:00 แต่รหัสนี้พลาดZ
barbsan

14

ฉันพบปัญหาเดียวกันจากนั้นก็จดจำบางสิ่งที่แปลกใหม่เกี่ยวกับโครงการมรดกที่ฉันกำลังทำอยู่และวิธีที่พวกเขาจัดการกับปัญหานี้ ฉันไม่เข้าใจในตอนนั้นและไม่สนใจจริงๆจนกระทั่งฉันพบปัญหา

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

ด้วยเหตุผลใดก็ตามที่ผ่านวันที่ใน '01-02-2557 'ให้ตั้งค่าเขตเวลาเป็นศูนย์และไม่สนใจเขตเวลาของผู้ใช้ นี่อาจเป็นความบังเอิญในคลาส Date แต่มันมีอยู่เมื่อไม่นานมานี้และมีอยู่ในปัจจุบัน และดูเหมือนว่าจะทำงานข้ามเบราว์เซอร์ ลองด้วยตัวคุณเอง

รหัสนี้ถูกนำไปใช้ในโครงการระดับโลกที่เขตเวลามีความสำคัญมาก แต่ผู้ที่ดูวันที่ไม่สนใจเวลาที่แน่นอนที่แนะนำ


ฉันคิดว่ามันมีเจตนาเพราะ "Z" กำหนด UTC ซึ่ง JS แปลงแล้ว แต่ไม่มีเขตเวลาจึงไม่สามารถแปลงได้ดังนั้นจึงถือว่าเขตเวลาของผู้ใช้เป็นหลัก ชอบที่จะได้รับการยืนยันหรือคำอธิบายที่ดีกว่า
dlsso

7
พฤติกรรมที่เฉื่อยชาเกิดจากเครื่องหมายขีดกลาง Chrome, Firefox และ IE11 ตีความ2014/5/31และ2014/05/31เป็นวันที่ 31 พฤษภาคม 2014 00:00:00 GMT-0600 (เวลาตามฤดูกาลของภูเขา) `(MDT เป็นเขตเวลาปัจจุบันของฉัน) ด้วยขีดกลาง ... เบราว์เซอร์ทั้งหมดตีความ2014-05-31ว่าเป็นวันศุกร์ที่ 30 พฤษภาคม 2014 18:00:00 GMT-0600 (เวลาตามฤดูกาลของภูเขา) อย่างผิดปกติกับ2014-5-31Chrome คืนวันเสาร์ Firefox คืนวันศุกร์และ IE11 บอกว่าวันที่ไม่ถูกต้อง ดูเหมือนว่าdate.replace('-','/')อาจจะทำเคล็ดลับ
atheaos

6

Dateวัตถุตัวเองจะมีเขตเวลาอยู่แล้วและผลกลับเป็นผลของการแปลงไปสตริงในทางเริ่มต้นที่ นั่นคือคุณไม่สามารถสร้างวัตถุวันที่โดยไม่มีเขตเวลา แต่สิ่งที่คุณทำได้คือเลียนแบบพฤติกรรมของDateวัตถุด้วยการสร้างวัตถุของคุณเอง นี้คืออย่างไรดีกว่าที่จะส่งมอบให้กับห้องสมุดเช่นmoment.js


2
น่าเสียดายที่ฉันต้องสร้างวัตถุวันที่ไม่ใช่สตริง
Athlan

3

ทางออกที่ง่าย

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);

3

วันที่ใน javascript เป็นเพียงการทำให้ภายในง่าย ดังนั้นข้อมูลวันที่และเวลาจะถูกเก็บไว้ใน UTC unix epoch (มิลลิวินาทีหรือมิลลิวินาที)

หากคุณต้องการมีเวลา "คงที่" ที่ไม่เปลี่ยนแปลงในเขตเวลาใดก็ตามที่คุณอยู่ในโลกคุณสามารถปรับเวลาใน UTC เพื่อให้ตรงกับเขตเวลาท้องถิ่นปัจจุบันของคุณและบันทึก และเมื่อทำการเรียกคืนไม่ว่าคุณจะอยู่ในเขตเวลาใดในท้องถิ่นของคุณก็จะแสดงเวลา UTC ที่ปรับตามผู้ที่บันทึกไว้และการเพิ่มเขตเวลาท้องถิ่นเพื่อชดเชยเวลา "คงที่"

เพื่อบันทึกวันที่ (เป็น 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
}

เพื่อเรียกคืน / แสดงวันที่ (เป็น 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
}

จากนั้นคุณสามารถ:

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

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

2

คุณสามารถใช้รหัสนี้

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);

1
ฉันไม่เชื่อว่าสิ่งนี้คำนึงถึงการประหยัดเวลากลางวัน
Daniel Thompson

2

เนื่องจากเป็นปัญหาการจัดรูปแบบจริง ๆ เมื่อแสดงวันที่ (เช่นแสดงในเวลาท้องถิ่น) ฉันชอบที่จะใช้วัตถุใหม่ (ish) Intl.DateTimeFormatเพื่อดำเนินการจัดรูปแบบเนื่องจากมีความชัดเจนมากขึ้นและมีตัวเลือกเอาต์พุตมากขึ้น:

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"

ดังที่แสดงโดยการตั้งค่าเขตเวลาเป็น 'UTC' จะไม่ทำการแปลงในเครื่อง โบนัสยังช่วยให้คุณสร้างผลลัพธ์ที่สวยงามยิ่งขึ้น คุณสามารถอ่านเพิ่มเติมเกี่ยวกับIntl.DateTimeFormatวัตถุจากMozilla - Intl.DateTimeFormat

แก้ไข:

สามารถใช้ฟังก์ชันเดียวกันนี้ได้โดยไม่ต้องสร้างIntl.DateTimeFormatวัตถุใหม่ เพียงผ่านตัวเลือกสถานที่และวันที่ลงในtoLocaleDateString()ฟังก์ชันโดยตรง

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"

1

แค่บันทึกทั่วไป วิธีที่จะทำให้มันยืดหยุ่น

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

เราสามารถใช้ getMinutes () ได้ แต่จะคืนค่าเพียงหนึ่งหมายเลขในช่วง 9 นาทีแรก

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. 

-1

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

จะมีผลลัพธ์: อังคาร 10 ก.ค. 2018 19:07:11

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

สิ่งนี้จะมีผลลัพธ์: ศุกร์กรกฎาคม 08 2005 04:22:33

หมายเหตุ: เวลาที่ส่งคืนจะขึ้นอยู่กับเขตเวลาท้องถิ่นของคุณ


-1

นี่เป็นวิธีแก้ปัญหาที่ฉันคิดขึ้นสำหรับปัญหานี้ซึ่งใช้ได้กับฉัน


ไลบรารี่ที่ใช้: momentjs พร้อมคลาสวันที่จาวาสคริปต์ธรรมดา

ขั้นตอนที่ 1 แปลงวันที่ของสตริงเป็นวัตถุช่วงเวลา (PS: ช่วงเวลาจะเก็บวันที่และเวลาดั้งเดิมไว้ตราบเท่าที่toDate()ไม่ได้เรียกใช้เมธอด):

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

ขั้นตอนที่ 2 แยกhoursและminutesค่าจากวัตถุโมเมนต์ที่สร้างไว้ก่อนหน้านี้:

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

ขั้นตอนที่ 3 แปลงช่วงเวลาเป็นวันที่ (PS: สิ่งนี้จะเปลี่ยนวันที่ดั้งเดิมตามเขตเวลาของเบราว์เซอร์ / เครื่องของคุณ แต่ไม่ต้องกังวลและอ่านขั้นตอนที่ 4):

  const dateObj = dateMoment.toDate();

ขั้นตอน 4. ตั้งค่าชั่วโมงและนาทีที่แยกด้วยตนเองในขั้นตอนที่ 2

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

ขั้นตอนที่ 5 dateObjจะแสดงวันที่ดั้งเดิมโดยไม่มีความแตกต่างของเขตเวลา แม้การเปลี่ยนแปลงเวลาตามฤดูกาลจะไม่มีผลกับวัตถุวันที่เนื่องจากเราตั้งค่าชั่วโมงและนาทีดั้งเดิมด้วยตนเอง

หวังว่านี่จะช่วยได้


-7

มีปัญหาบางอย่างเกี่ยวกับการแยกวิเคราะห์วันที่ซึ่งไม่ได้รับการแก้ไขเป็นอย่างดี

- วันที่มนุษย์สามารถอ่านได้มีเขตเวลาโดยนัยในนั้น
- มีหลายรูปแบบวันที่ใช้กันอย่างแพร่หลายในเว็บที่คลุมเครือ

เพื่อแก้ปัญหาเหล่านี้ง่ายและสะอาดต้องมีฟังก์ชั่นเช่นนี้:

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

ฉันค้นหาสิ่งนี้แล้ว แต่ไม่พบสิ่งใดเลย!

ดังนั้นฉันจึงสร้าง: https://github.com/zsoltszabo/timestamp-grabber

สนุก!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.