ОСТЕРЕГАЙТЕСЬ ВРЕМЕНИ
Использование объекта date для непосредственного представления даты просто поставит вас перед проблемой чрезмерной точности. Вы должны управлять временем и часовым поясом, чтобы не пускать их, и они могут вернуться обратно на любом этапе. Принятый ответ на этот вопрос попадает в ловушку.
Дата в JavaScript не имеет понятия о часовом поясе . Это момент времени (тики с начала эпохи) с удобными (статическими) функциями для перевода в и из строк, с использованием по умолчанию «локального» часового пояса устройства или, если указан, UTC или другого часового пояса. Чтобы представить just-a-date ™ с объектом даты, вы хотите , чтобы ваши даты представляли полночь UTC в начале рассматриваемой даты. Это общее и необходимое соглашение, которое позволяет вам работать с датами независимо от сезона или часового пояса их создания. Таким образом, вы должны быть очень бдительными, чтобы управлять понятием часового пояса, как при создании объекта «Дата в формате UTC», так и при его сериализации.
Многие люди смущены поведением консоли по умолчанию. Если вы распылите дату на консоль, вы увидите, что вы увидите ваш часовой пояс. Это просто потому, что консоль вызывает toString()
вашу дату и toString()
дает вам местное представительство. Базовая дата не имеет часового пояса ! (До тех пор, пока время соответствует смещению часового пояса, у вас все еще будет объект даты UTC в полночь)
Десериализация (или создание полуночных UTC Date объектов)
Это шаг округления с хитростью в том, что есть два «правильных» ответа. В большинстве случаев вы хотите, чтобы ваша дата отражала часовой пояс пользователя. Нажмите, если сегодня ваш день рождения . Пользователи в Новой Зеландии и США нажимают одновременно и получают разные даты. В таком случае сделай это ...
// create a date (utc midnight) reflecting the value of myDate and the environment's timezone offset.
new Date(Date.UTC(myDate.getFullYear(),myDate.getMonth(), myDate.getDate()));
Иногда международная сопоставимость превосходит локальную точность. В таком случае сделай это ...
// the date in London of a moment in time. Device timezone is ignored.
new Date(Date.UTC(myDate.getUTCFullYear(), myDate.getUTCMonth(), myDate.getUTCDate()));
Десериализовать дату
Часто даты на проводе будут в формате ГГГГ-ММ-ДД. Чтобы десериализовать их, сделайте это ...
var midnightUTCDate = new Date( dateString + 'T00:00:00Z');
Сериализация
Позаботившись об управлении часовым поясом при создании, теперь вы должны быть уверены, что часовой пояс не будет отображаться при преобразовании обратно в строковое представление. Так что вы можете смело использовать ...
toISOString()
getUTCxxx()
getTime() //returns a number with no time or timezone.
.toLocaleDateString("fr",{timezone:"UTC"}) // whatever locale you want, but ALWAYS UTC.
И полностью избегать всего остального, особенно ...
getYear()
, getMonth()
,getDate()
Так что, чтобы ответить на ваш вопрос, 7 лет слишком поздно ...
<input type="date" onchange="isInPast(event)">
<script>
var isInPast = function(event){
var userEntered = new Date(event.target.valueAsNumber); // valueAsNumber has no time or timezone!
var now = new Date();
var today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() ));
if(userEntered.getTime() < today.getTime())
alert("date is past");
else if(userEntered.getTime() == today.getTime())
alert("date is today");
else
alert("date is future");
}
</script>
Вижу это работает ...
Обновление 2019 ... бесплатные вещи ...
Учитывая популярность этого ответа, я поместил все это в код. Следующая функция возвращает обернутый объект даты и предоставляет только те функции, которые безопасно использовать с just-a-date ™.
Вызовите его с объектом Date, и он будет преобразован в JustADate, отражая часовой пояс пользователя. Назовите его строкой: если строка соответствует ISO 8601 с указанием часового пояса, мы просто округлим часть времени. Если часовой пояс не указан, мы конвертируем его в дату, отражающую местный часовой пояс, как и для объектов даты.
function JustADate(initDate){
var utcMidnightDateObj = null
// if no date supplied, use Now.
if(!initDate)
initDate = new Date();
// if initDate specifies a timezone offset, or is already UTC, just keep the date part, reflecting the date _in that timezone_
if(typeof initDate === "string" && initDate.match(/((\+|-)\d{2}:\d{2}|Z)$/gm)){
utcMidnightDateObj = new Date( initDate.substring(0,10) + 'T00:00:00Z');
} else {
// if init date is not already a date object, feed it to the date constructor.
if(!(initDate instanceof Date))
initDate = new Date(initDate);
// Vital Step! Strip time part. Create UTC midnight dateObj according to local timezone.
utcMidnightDateObj = new Date(Date.UTC(initDate.getFullYear(),initDate.getMonth(), initDate.getDate()));
}
return {
toISOString:()=>utcMidnightDateObj.toISOString(),
getUTCDate:()=>utcMidnightDateObj.getUTCDate(),
getUTCDay:()=>utcMidnightDateObj.getUTCDay(),
getUTCFullYear:()=>utcMidnightDateObj.getUTCFullYear(),
getUTCMonth:()=>utcMidnightDateObj.getUTCMonth(),
setUTCDate:(arg)=>utcMidnightDateObj.setUTCDate(arg),
setUTCFullYear:(arg)=>utcMidnightDateObj.setUTCFullYear(arg),
setUTCMonth:(arg)=>utcMidnightDateObj.setUTCMonth(arg),
addDays:(days)=>{
utcMidnightDateObj.setUTCDate(utcMidnightDateObj.getUTCDate + days)
},
toString:()=>utcMidnightDateObj.toString(),
toLocaleDateString:(locale,options)=>{
options = options || {};
options.timezone = "UTC";
locale = locale || "en-EN";
return utcMidnightDateObj.toLocaleDateString(locale,options)
}
}
}
// if initDate already has a timezone, we'll just use the date part directly
console.log(JustADate('1963-11-22T12:30:00-06:00').toLocaleDateString())
date1 === date2
видимому, не обеспечивает согласованного поведения; это лучше сделатьdate1.valueOf() === b.valueOf()
или дажеdate1.getTime() === date2.getTime()
. Странность.