Födelsedagsmatematik
Har du någonsin undrat hur gammal du är ... i millisekunder? Eller exakt hur många veckor det är mellan två datum? Lugn, lugn – i det här inlägget kan du få svar på alla dina "Hur många [enhet] är det mellan [datum] och [datum]?"-frågor!
For example your birthdayFor example today's date
31.790120641616
Months381.496581748059
Weeks1658.770576313
Days11611.394034190
Hours278673.456821
Minutes16720407.409233
Seconds1003224444.554
Milliseconds1003224444554
Datumberäkningar
Välj start- och slutdatum ovan och få svar på allt du någonsin har undrat över! Startdatumet är min födelsedag och slutdatumet är dagens datum innan du ändrar något. Som du ser uppdateras värdena hela tiden och det gör de så länge slutdatumet är dagens datum. Om du väljer ett annat slutdatum slutar uppdateringarna.
Hur fungerar beräkningarna?
Det finns många tjänster på internet som kan hjälpa en att räkna ut hur många dagar det är mellan två datum. De tjänster jag har stött på räknar dock dagarna i heltal, vilket inte avspeglar att den pågående dagen hela tiden närmar sig nästa dag. Vi behöver decimaler! Jag har inte heller hittat någon tjänst som visar hur många år, månader eller veckor det är mellan två datum med flera decimalers noggrannhet. Klart att det måste finnas!
Vid valet av startdatum finns även möjligheten att ange klockslag genom att klicka i "Ange även klockslag". På så sätt kan du till exempel ange ditt födelsedatum med klockslag för att ta reda på exakt hur många minuter du är. Beräkningarna för sekunder och millisekunder var trevliga att ta med, men är inte särskilt relevanta eftersom millisekunder eller sekunder inte går att välja i start- eller slutdatum. När "Ange även klockslag" inte är ifylld antas klockslaget 00:00:00:00 och när klockslag är valt antas sekundvärdet 00. Om du klickar på "I dag" väljs den exakta nuvarande millisekunden. När slutdatumet sätts till "I dag" räknar värdena hela tiden upp till nuvarande millisekund så att du kan följa hur du åldras i realtid.
I JavaScript finns det inbyggda Date-objektet som innehåller massor av bra information och därför är bra att använda i den här typen av beräkningar. Med new Date() skapas ett nytt Date-objekt med information om nuvarande millisekund, som kan tas fram med hjälp av en rad olika funktioner som hör till Date-objektet. Här är några exempel för datumet 2020-10-12.
const now = new Date()
const currentYear = now.getFullYear()
// currentYear = 2020
const currentMonth = now.getMonth()
// currentMonth = 9
const currentDate = now.getDate()
// currentDate = 12
const currentTime = now.getTime()
// currentTime = 1602486314645
Två av dessa funktioner som kan verka lite märkliga är getMonth och getTime. Trots att det är 2020-10-12 blir currentMonth 9. Det beror på att månaderna räknas från 0. Januari är alltså 0 och så vidare till och med december som är månad 11. getTime skulle man kunna tro skulle vara ett klockslag i stil med "09:05", men returnerar i stället något så konstigt som antalet millisekunder från midnatt 1970-01-01. Det är JavaScripts strategi för att ange en exakt tid. Alla tider före 1970-01-01 representeras alltså i ett negativt tal om getTime används.
Funktionerna för att beräkna millisekunder, sekunder, minuter, timmar, dagar och veckor mellan två Date-objekt är alla triviala. Så här kan dessa beräknas med JavaScript:
function getMillisecondsDiff(startDate, endDate) {
return endDate.getTime() - startDate.getTime()
}
För att beräkna antalet sekunder mellan två Date-objekt kan funktionen getMillisecondsDiff återanvändas, så här:
function getSecondsDiff(startDate, endDate) {
const milliseconds = getMillisecondsDiff(startDate, endDate)
const seconds = milliseconds / 1000
return seconds
}
Sen fortsätter vi på precis samma sätt genom att hela tiden återanvända funktionerna:
Beräkna minuter mellan två Date-objektfunction getMinutesDiff(startDate, endDate) {
const seconds = getSecondsDiff(startDate, endDate)
const minutes = seconds / 60
return minutes
}
Beräkna timmar mellan två Date-objekt
function getHoursDiff(startDate, endDate) {
const minutes = getMinutesDiff(startDate, endDate)
const hours = minutes / 60
return hours
}
Beräkna dagar mellan två Date-objekt
function getDaysDiff(startDate, endDate) {
const hours = getHoursDiff(startDate, endDate)
const days = hours / 24
return days
}
Beräkna veckor mellan två Date-objekt
function getWeeksDiff(startDate, endDate) {
const days = getDaysDiff(startDate, endDate)
const weeks = days / 7
return weeks
}
Dessa funktioner bygger alla på enkel matematik. Att räkna ut exakt hur många månader eller år det är mellan två Date-objekt ska däremot visa sig vara betydligt svårare.
Beräkna månader mellan datum
Innan vi går in på beräkningar i kod måste vi fundera över hur en månad definieras. Eftersom en månads längd varierar, till skillnad från dagar per vecka och minuter per timme och liknande, är det inte självklart hur många månader 10 dagar är. Ska en genomsnittlig månads längd användas? Nja – det är både klurigt att räkna ut med tanke på komplexiteten kring skottår och det skulle också resultera i konstigheter som att 1–15 februari skulle räknas som mindre än en månad även om mer än hälften av den aktuella månaden har passerat.
Jag landar i att den nuvarande månadens längd används för att beräkna decimalerna. Låt mig förklara vad jag menar med några exempel.
Exempel 1Startdatum: 2018-01-01 kl. 00:00
Slutdatum: 2020-02-01 kl. 00:00
För att beräkna antalet månader mellan startdatum och slutdatum i Exempel 1 kan vi börja med att beräkna hur många hela månader som finns mellan datumen. Hela 2018 och 2019 ger 24 månader och januari ger en till månad, vilket resulterar i 25 hela månader. Men hur blir det om startmånaden är till exempel april i exemplet ovan? Vi testar det som ett nytt exempel.
Exempel 2Startdatum: 2018-04-01 kl. 00:00
Slutdatum: 2020-02-01 kl. 00:00
Detta kan beräknas på samma sätt som för Exempel 1 med tillägget att startmånaden dras av från resultatet. Alltså 12 + 12 + 2 - 4 = 22 månader. Beräkningen ser ut så här i JavaScript:
Beräkna antalet hela månader mellan två Date-objektconst fullMonths =
(endDate.getFullYear() - startDate.getFullYear()) * 12 +
endDate.getMonth() -
startDate.getMonth()
För att detta verkligen ska vara hela månader förutsätts att det är första dagen i respektive månad. Vi behöver alltså kompensera för att det inte alltid är det. Vi tar ett tredje exempel:
Exempel 3Startdatum: 2018-04-24 kl. 00:00
Slutdatum: 2020-02-06 kl. 00:00
Min tanke här är att beräkningen borde utgå från att det är 22 månader mellan 2018-04-24 kl. 00:00 och 2020-02-24 kl. 00:00, därefter används februaris längd för att ta bort eller lägga till resten. För att det ska bli så exakt som möjligt kan antalet millisekunder mellan slutdatum och 2020-02-24 kl. 00:00 beräknas och divideras med antalet millisekunder i slutdatumets månad. Så här:
Beräkna det exakta antalet månader med decimaler mellan två Date-objekt
const daysInEndDateMonth = new Date(
endDate.getFullYear(),
endDate.getMonth() + 1,
0,
).getDate()
const millisecondsInEndDateMonth = daysInEndDateMonth * 24 * 60 * 60 * 1000
const startDateInEndDateMonth = new Date(
endDate.getFullYear(),
endDate.getMonth(),
startDate.getDate(),
startDate.getHours(),
startDate.getMinutes(),
startDate.getSeconds(),
startDate.getMilliseconds(),
)
const millisecondsDiffInEndDateMonth =
endDate.getTime() - startDateInEndDateMonth.getTime()
const fractionalMonth =
millisecondsDiffInEndDateMonth / millisecondsInEndDateMonth
const months = fullMonths + fractionalMonth
Genom att bryta ut i funktioner blir getMonthsDiff så här:
function getMonthsDiff(startDate, endDate) {
const fullMonths = getFullMonth(startDate, endDate)
const daysInEndDateMonth = getDaysInMonth(endDate)
const millisecondsInEndDateMonth =
convertDaysToMilliseconds(daysInEndDateMonth)
const startDateInEndDateMonth = getStartDateInEndDateMonth(startDate, endDate)
const millisecondsDiffInEndDateMonth =
endDate.getTime() - startDateInEndDateMonth.getTime()
const fractionalMonth =
millisecondsDiffInEndDateMonth / millisecondsInEndDateMonth
const months = fullMonths + fractionalMonth
return months
}
function getFullMonth(startDate, endDate) {
return (
(endDate.getFullYear() - startDate.getFullYear()) * 12 +
endDate.getMonth() -
startDate.getMonth()
)
}
function getDaysInMonth(date) {
return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate()
}
function convertDaysToMilliseconds(days) {
return days * 24 * 60 * 60 * 1000
}
function getStartDateInEndDateMonth(startDate, endDate) {
return new Date(
endDate.getFullYear(),
endDate.getMonth(),
startDate.getDate(),
startDate.getHours(),
startDate.getMinutes(),
startDate.getSeconds(),
startDate.getMilliseconds(),
)
}
Vi kan nu testa getMonthsDiff genom att skicka in start- och slutdatum från Exempel 3:
const startDate = new Date("2018-04-24 00:00")
const endDate = new Date("2020-02-06 00:00")
const monthsDiff = getMonthsDiff(startDate, endDate)
// monthsDiff = 21.379310344827587
Lite handräkning kan visa att det verkar stämma. I stället för beräkningar med millisekunder kan vi testa att göra en kontroll med hela dagar vilket borde stämma ändå eftersom klockslaget är detsamma för start- och slutdatumet i exemplet.
Hela månader är fortfarande 22 stycken (enligt ovan). Men sedan får vi ta bort 24 - 6 = 18 dagar dividerat med antalet dagar som finns i februari 2020 som är 29 eftersom 2020 är ett skottår. 18/29 = 0,62068966. Slutligen får vi att antalet månader är 22 - 0,62068966 = 21,3793103 vilket ju exakt stämmer överens med svaret från funktionen getMonthsDiff.
Beräkna år mellan datum
Exakt samma beräkningsprincip kan användas för att beräkna år mellan två datum:
Beräkna år mellan två Date-objektfunction getYearsDiff(startDate, endDate) {
const fullYears = endDate.getFullYear() - startDate.getFullYear()
const millisecondsInEndDateYear = getMillisecondsInYear(startDate)
const startMonthInEndDateYear = getStartMonthInEndDateYear(startDate, endDate)
const millisecondsDiffInEndDateYear =
endDate.getTime() - startMonthInEndDateYear.getTime()
const fractionalYears =
millisecondsDiffInEndDateYear / millisecondsInEndDateYear
const years = fullYears + fractionalYears
return years
}
function getMillisecondsInYear(date) {
return (
new Date(date.getFullYear(), 12, 0).getTime() -
new Date(date.getFullYear(), 0, 1).getTime()
)
}
function getStartMonthInEndDateYear(startDate, endDate) {
return new Date(
endDate.getFullYear(),
startDate.getMonth(),
startDate.getDate(),
startDate.getHours(),
startDate.getMinutes(),
startDate.getSeconds(),
startDate.getMilliseconds(),
)
}
Vi testar även getYearsDiff med ett par exempeldatum:
const startDate = new Date("2018-01-01")
const endDate = new Date("2020-01-01")
const yearsDiff = getYearsDiff(startDate, endDate)
// yearsDiff = 2
Att det är exakt två år mellan 2018-01-01 och 2020-01-01 stämmer ju finfint. Låt oss testa något lite mer komplicerat:
År mellan två nya Date-objektconst startDate = new Date("2018-05-03")
const endDate = new Date("2020-03-22")
const yearsDiff = getYearsDiff(startDate, endDate)
// yearsDiff = 1.8846153846153846
Jag gör ingen manuell kontrollberäkning här men även getYearsDiff verkar göra vad den ska (och jag har kontrollberäknat själv).
Det var det! Jag kan skryta med att vara 1658.770576356 veckor gammal och du kan själv se hur gammal du är – exakt.
