آیا شیء تاریخ جاوااسکریپت همیشه یک روز جابجا است؟


در برنامه جاوااسکریپت من، تاریخ به فرمتی مانند این ذخیره شده است:

2011-09-24

حال وقتی من تلاش میکنم از مقدار فوق برای ایجاد یک شیء تاریخ جدید استفاده کنم (تا بتوانم تاریخ را در قالبی متفاوت بازیابی کنم)، تاریخ همیشه یک روز اختلاف دارد. به مثال زیر توجه کنید:

var date = new Date("2011-09-24");
console.log(date);

گزارشها :

Fri Sep 23 2011 20:00:00 GMT-0400 (Eastern Daylight Time)

پاسخ شماره ۱

چیزهای عجیب و غریب زیادی با یک شیء DATE در JS اتفاق میافتد که رشتهها را تبدیل میکند، برای مثال تاریخ زیر که شما ارائه کردید را در نظر بگیرید

توجه: مثالهای زیر ممکن است بسته به منطقه زمانی شما و زمان فعلی، یک روز مرخصی باشند یا نباشند.

new Date("2011-09-24"); // Year-Month-Day
// => Fri Sep 23 2011 17:00:00 GMT-0700 (MST) - ONE DAY OFF.

با این حال، اگر فرمت رشته را به ماه-روز-سال تغییر دهیم...

new Date("09-24-2011");
// => Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

یکی عجیب دیگر

new Date("2011-09-24");
// => Fri Sep 23 2011 17:00:00 GMT-0700 (MST) - ONE DAY OFF AS BEFORE.

new Date("2011/09/24"); // change from "-" to "/".
// => Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

ما میتوانیم به راحتی خطهای فاصله در تاریخ شما "2011-09-24" را هنگام ساخت یک تاریخ جدید تغییر دهیم

new Date("2011-09-24".replace(/-/g, '\/')); // => "2011/09/24".
// => Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

اگر رشته تاریخ مانند "2011-09-24T00:00:00" داشتیم چه میشد؟

new Date("2011-09-24T00:00:00");
// => Fri Sep 23 2011 17:00:00 GMT-0700 (MST) - ONE DAY OFF.

حالا همانطور که قبلتر، خط تیره را به اسلش تغییر دهید؛ چه اتفاقی میافتد؟

new Date("2011/09/24T00:00:00");
// => Invalid Date.

من معمولاً باید قالب تاریخ 2011-09-24T00:00:00 را مدیریت کنم، بنابراین این کاری است که انجام میدهم.

new Date("2011-09-24T00:00:00".replace(/-/g, '\/').replace(/T.+/, ''));
// => Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

بهروزرسانی

اگر آرگومانهای جداگانهای به سازنده تاریخ ارائه دهید، میتوانید خروجیهای مفید دیگری همانطور که در زیر توضیح داده شده است، به دست آورید

توجه: آرگومانها میتوانند از نوع عدد (Number) یا رشته (String) باشند. من مثالهایی با مقادیر مختلط نشان خواهم داد.

دریافت اولین ماه و روز یک سال مشخص

new Date(2011, 0); // Normal behavior as months in this case are zero based.
// => Sat Jan 01 2011 00:00:00 GMT-0700 (MST)

دریافت آخرین ماه و روز یک سال

new Date((2011 + 1), 0, 0); // The second zero roles back one day into the previous month's last day.
// => Sat Dec 31 2011 00:00:00 GMT-0700 (MST)

نمونهای از آرگومانهای عدد و رشته. توجه داشته باشید که ماه مارس است چون ماهها دوباره از صفر شروع میشوند.

new Date(2011, "02"); 
// => Tue Mar 01 2011 00:00:00 GMT-0700 (MST)

اگر همان کار را انجام دهیم اما با روز صفر، چیز متفاوتی به دست میآوریم.

new Date(2011, "02", 0); // Again the zero roles back from March to the last day of February.
// => Mon Feb 28 2011 00:00:00 GMT-0700 (MST)

اضافه کردن یک روز صفر به هر سال و ماه، آخرین روز ماه قبل را به دست میآورد. اگر با اعداد منفی ادامه دهید، میتوانید به عقب برگردید و روز دیگری را کم کنید.

new Date(2011, "02", -1);
// => Sun Feb 27 2011 00:00:00 GMT-0700 (MST)

پاسخ شماره ۲

توجه داشته باشید که زمان تابستانی شرقی -۴ ساعت است و ساعاتی که در تاریخی که برمیگردانید دارید ۲۰ هستند.

20h + 4h = 24h

که نیمهشب ۲۰۱۱-۰۹-۲۴ است. تاریخ در زمان هماهنگ جهانی (UTC/GMT) تجزیه شد زیرا شما فقط یک رشته تاریخ بدون نشانگر منطقه زمانی ارائه دادید. اگر یک رشته تاریخ/زمان بدون نشانگر داده بودید (new Date("2011-09-24T00:00:00"))، در منطقه زمانی محلی شما تجزیه میشد. (از نظر تاریخی نواقصی در این زمینه وجود داشته، نه کمتر به این دلیل که مشخصات بیش از یک بار تغییر کرده است، اما مرورگرهای مدرن باید مشکلی نداشته باشند؛ یا شما همیشه میتوانید یک نشانگر منطقه زمانی اضافه کنید.)

شما تاریخ درست را میگیرید، فقط هرگز منطقه زمانی صحیح را مشخص نکردهاید.

اگر نیاز دارید به مقادیر تاریخ دسترسی پیدا کنید، میتوانید از getUTCDate() یا هر یک از توابع دیگر getUTC*() استفاده کنید:

var d,
  days;
d = new Date('2011-09-24');
days = ['Sun', 'Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat'];
console.log(days[d.getUTCDay()]);

پاسخ شماره ۳

برای نرمالسازی تاریخ و حذف افست ناخواسته (آزمایش شده در اینجا: https://jsfiddle.net/7xp1xL5m/):

var doo = new Date("2011-09-24");
console.log(  new Date( doo.getTime() + Math.abs(doo.getTimezoneOffset()*60000) )  );
// Output: Sat Sep 24 2011 00:00:00 GMT-0400 (Eastern Daylight Time)

این نیز همان کار را انجام میدهد و اعتبار به @tpartee (در اینجا آزمایش شده: https://jsfiddle.net/7xp1xL5m/1/ ):

var doo = new Date("2011-09-24");
console.log( new Date( doo.getTime() - doo.getTimezoneOffset() * -60000 )  );

پاسخ شماره ۴

من معتقدم که این مربوط به تنظیم منطقه زمانی است. تاریخی که ایجاد کردهاید به وقت GMT است و زمان پیشفرض نیمه شب است، اما منطقه زمانی شما EDT است، بنابراین ۴ ساعت کسر میشود. برای اطمینان این را امتحان کنید:

var doo = new Date("2011-09-25 EDT");

پاسخ شماره ۵

فقط میخواهم اضافه کنم که ظاهراً افزودن یک فاصله در پایان رشته، از زمان جهانی هماهنگ (UTC) برای ایجاد استفاده خواهد کرد.

new Date("2016-07-06")
> Tue Jul 05 2016 17:00:00 GMT-0700 (Pacific Daylight Time)

new Date("2016-07-06 ")
> Wed Jul 06 2016 00:00:00 GMT-0700 (Pacific Daylight Time)

ویرایش: این یک راه حل توصیهشده نیست، تنها یک پاسخ جایگزین است. لطفاً از این روش استفاده نکنید زیرا آنچه در حال رخ دادن است بسیار نامشخص است. راههای متعددی وجود دارد که کسی میتواند این را بازسازی کند و به طور تصادفی باعث ایجاد باگ شود.

پاسخ شماره ۶

اگر میخواهید ساعت ۰ یک تاریخ مشخص را در منطقه زمانی محلی به دست آورید، قسمتهای مختلف تاریخ را به سازنده Date منتقل کنید.

new Date(2011,08,24); // month value is 0 based, others are 1 based.

پاسخ شماره ۷

اگر به یک راه حل ساده برای این نیاز دارید، ببینید:

new Date('1993-01-20'.split('-')); 

پاسخ شماره ۸

شما میتوانید این تاریخ را به تاریخ UTC تبدیل کنید با

new Date(Date.UTC(Year, Month, Day, Hour, Minute, Second))

و همیشه توصیه میشود که از تاریخ UTC (منطقه زمانی جهانی) به جای تاریخ با زمان محلی استفاده شود، زیرا به طور پیشفرض تاریخها در پایگاه داده با UTC ذخیره میشوند. بنابراین، استفاده و تفسیر تاریخها در فرمت UTC در سراسر پروژه یک روش خوب است. برای مثال،

Date.getUTCYear(), getUTCMonth(), getUTCDay(), getUTCHours()

بنابراین، استفاده از تاریخهای UTC تمام مشکلات مربوط به مسائل منطقه زمانی را حل میکند.

پاسخ شماره ۹

مشکل شما به طور خاص مربوط به منطقه زمانی است. به قسمت GMT-0400 توجه کنید - این یعنی شما ۴ ساعت عقبتر از GMT هستید. اگر ۴ ساعت به تاریخ/زمان نمایش داده شده اضافه کنید، دقیقاً نیمهشب ۲۰۱۱/۰۹/۲۴ را خواهید داشت. از متد toUTCString() استفاده کنید تا رشته GMT را دریافت کنید:

var doo = new Date("2011-09-24");
console.log(doo.toUTCString());

پاسخ شماره ۱۰

این احتمالاً پاسخ خوبی نیست، اما من فقط میخواهم تجربه خودم را در مورد این مسئله به اشتراک بگذارم.

اپلیکیشن من به طور جهانی از تاریخ UTC با فرمت 'YYYY-MM-DD' استفاده میکند، در حالی که پلاگین datepicker که من استفاده میکنم فقط تاریخ JS را قبول میکند، بنابراین برای من در نظر گرفتن هر دو یعنی UTC و JS سخت است. بنابراین وقتی میخواهم تاریخی با فرمت 'YYYY-MM-DD' را به datepicker منتقل کنم، ابتدا آن را با استفاده از moment.js یا هر ابزاری که میخواهید به فرمت 'MM/DD/YYYY' تبدیل میکنم، و اکنون تاریخی که در datepicker نمایش داده میشود درست است. برای مثال شما

var d = new Date('2011-09-24'); // d will be 'Fri Sep 23 2011 20:00:00 GMT-0400 (EDT)' for my lacale
var d1 = new Date('09/24/2011'); // d1 will be 'Sat Sep 24 2011 00:00:00 GMT-0400 (EDT)' for my lacale

ظاهراً d1 همانی است که میخواهم. امیدوارم این برای بعضی افراد مفید باشد.