Uważaj na strefę czasową
Używanie obiektu date do natychmiastowego przedstawienia tylko daty, powoduje ogromny problem z nadmierną precyzją. Musisz zarządzać czasem i strefą czasową, aby je trzymać, a oni mogą wrócić na każdym kroku. Przyjęta odpowiedź na to pytanie wpada w pułapkę.
Data javascript nie ma pojęcia strefy czasowej . Jest to chwila (tyka od epoki) z przydatnymi (statycznymi) funkcjami do tłumaczenia na i z ciągów, domyślnie wykorzystując „lokalną” strefę czasową urządzenia lub, jeśli określono, UTC lub inną strefę czasową. Aby reprezentować just-a-date ™ za pomocą obiektu daty, chcesz, aby twoje daty reprezentowały północ UTC na początku danej daty. Jest to powszechna i niezbędna konwencja, która pozwala pracować z datami niezależnie od sezonu lub strefy czasowej ich utworzenia. Musisz więc zachować czujność, aby zarządzać pojęciem strefy czasowej, zarówno podczas tworzenia obiektu o północy według czasu UTC, jak i podczas serializowania go.
Wielu ludzi jest zdezorientowanych domyślnym zachowaniem konsoli. Jeśli natryskasz datę na konsolę, zobaczysz, że wynik będzie zawierać strefę czasową. Wynika to tylko z tego, że konsola dzwoni toString()
w twoim dniu i toString()
zapewnia lokalną reprezentację. Data bazowa nie ma strefy czasowej ! (Dopóki czas odpowiada przesunięciu strefy czasowej, nadal masz obiekt o północy czasu UTC)
Deserializacja (lub tworzenie obiektów o północy UTC)
Jest to krok zaokrąglania, z tą sztuczką, że istnieją dwie „właściwe” odpowiedzi. Przez większość czasu będziesz chciał, aby data odzwierciedlała strefę czasową użytkownika. Kliknij, jeśli dzisiaj są twoje urodziny . Użytkownicy w Nowej Zelandii i USA klikają jednocześnie i uzyskują różne daty. W takim przypadku zrób to ...
// 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()));
Czasami międzynarodowa porównywalność przewyższa lokalną dokładność. W takim przypadku zrób to ...
// the date in London of a moment in time. Device timezone is ignored.
new Date(Date.UTC(myDate.getUTCFullYear(), myDate.getUTCMonth(), myDate.getUTCDate()));
Deserializuj datę
Często daty na drucie będą miały format RRRR-MM-DD. Aby deserializować je, zrób to ...
var midnightUTCDate = new Date( dateString + 'T00:00:00Z');
Serializacja
Mając na uwadze zarządzanie strefą czasową podczas tworzenia, musisz teraz zachować strefę czasową podczas konwersji z powrotem do reprezentacji ciągu. Możesz więc bezpiecznie używać ...
toISOString()
getUTCxxx()
getTime() //returns a number with no time or timezone.
.toLocaleDateString("fr",{timezone:"UTC"}) // whatever locale you want, but ALWAYS UTC.
I całkowicie unikaj wszystkiego innego, zwłaszcza ...
getYear()
, getMonth()
,getDate()
Aby odpowiedzieć na twoje pytanie, 7 lat za późno ...
<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>
Zobacz, jak działa ...
Aktualizacja 2019 ... darmowe rzeczy ...
Biorąc pod uwagę popularność tej odpowiedzi, umieściłem to wszystko w kodzie. Poniższa funkcja zwraca zawinięty obiekt daty i ujawnia tylko te funkcje, których można bezpiecznie używać z funkcją just-a-date ™.
Zadzwoń do niego z obiektem Date, a rozwiąże to JustADate odzwierciedlające strefę czasową użytkownika. Nazwij to ciągiem znaków: jeśli ciąg znaków to ISO 8601 z określoną strefą czasową, po prostu zaokrąglimy część czasu. Jeśli strefa czasowa nie zostanie określona, przekonwertujemy ją na datę odzwierciedlającą lokalną strefę czasową, tak jak w przypadku obiektów daty.
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
wydaje się nie zapewniać spójnego zachowania; lepiej to zrobić,date1.valueOf() === b.valueOf()
a nawetdate1.getTime() === date2.getTime()
. Osobliwość.