DevTools Geburtstag: optionale Uhrzeit, Alter mit Jahren/Monaten/Tagen/Std/Min, Gelebte Tage mit Nachkommastelle
This commit is contained in:
@@ -585,30 +585,57 @@ function DatetimeRechner({ mobile }) {
|
|||||||
|
|
||||||
// ── Tab 2: Geburtstag ──
|
// ── Tab 2: Geburtstag ──
|
||||||
const [bday, setBday] = useState('');
|
const [bday, setBday] = useState('');
|
||||||
|
const [bdayTime, setBdayTime] = useState('');
|
||||||
const [bdayResult, setBdayResult] = useState(null);
|
const [bdayResult, setBdayResult] = useState(null);
|
||||||
|
|
||||||
function calcBday(val) {
|
function calcBday(date, time) {
|
||||||
setBday(val);
|
const dateVal = date ?? bday;
|
||||||
if (!val) { setBdayResult(null); return; }
|
const timeVal = time ?? bdayTime;
|
||||||
const birth = new Date(val);
|
setBday(dateVal);
|
||||||
|
setBdayTime(timeVal);
|
||||||
|
if (!dateVal) { setBdayResult(null); return; }
|
||||||
|
// Build birth datetime: if time given use it, else midnight
|
||||||
|
const birthStr = timeVal ? `${dateVal}T${timeVal}:00` : `${dateVal}T00:00:00`;
|
||||||
|
const birth = new Date(birthStr);
|
||||||
if (isNaN(birth)) { setBdayResult(null); return; }
|
if (isNaN(birth)) { setBdayResult(null); return; }
|
||||||
|
const hasTime = !!timeVal;
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
let age = today.getFullYear() - birth.getFullYear();
|
|
||||||
const hadBday = today.getMonth() > birth.getMonth() ||
|
|
||||||
(today.getMonth() === birth.getMonth() && today.getDate() >= birth.getDate());
|
|
||||||
if (!hadBday) age--;
|
|
||||||
|
|
||||||
const nextBday = new Date(today.getFullYear(), birth.getMonth(), birth.getDate());
|
// Age in years
|
||||||
|
let ageY = today.getFullYear() - birth.getFullYear();
|
||||||
|
let ageM = today.getMonth() - birth.getMonth();
|
||||||
|
let ageD = today.getDate() - birth.getDate();
|
||||||
|
if (ageD < 0) { ageM--; const prev = new Date(today.getFullYear(), today.getMonth(), 0); ageD += prev.getDate(); }
|
||||||
|
if (ageM < 0) { ageY--; ageM += 12; }
|
||||||
|
|
||||||
|
// Hours and minutes since last birthday (only if time entered)
|
||||||
|
let ageH = null, ageMi = null;
|
||||||
|
if (hasTime) {
|
||||||
|
ageH = today.getHours() - birth.getHours();
|
||||||
|
ageMi = today.getMinutes() - birth.getMinutes();
|
||||||
|
if (ageMi < 0) { ageH--; ageMi += 60; }
|
||||||
|
if (ageH < 0) { ageD--; ageH += 24;
|
||||||
|
if (ageD < 0) { ageM--; const prev = new Date(today.getFullYear(), today.getMonth(), 0); ageD += prev.getDate();
|
||||||
|
if (ageM < 0) { ageY--; ageM += 12; } } }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next birthday
|
||||||
|
const nextBday = new Date(today.getFullYear(), birth.getMonth(), birth.getDate(),
|
||||||
|
hasTime ? birth.getHours() : 0, hasTime ? birth.getMinutes() : 0, 0);
|
||||||
if (nextBday <= today) nextBday.setFullYear(today.getFullYear()+1);
|
if (nextBday <= today) nextBday.setFullYear(today.getFullYear()+1);
|
||||||
const diffMs = nextBday - today;
|
const diffMs = nextBday - today;
|
||||||
const diffD = (diffMs / 86400000).toFixed(1);
|
const diffD = (diffMs / 86400000).toFixed(1);
|
||||||
const totalD = Math.floor((today - birth) / 86400000);
|
const totalMs = today - birth;
|
||||||
const nextWday = WEEKDAYS[nextBday.getDay()];
|
const totalD = (totalMs / 86400000).toFixed(1);
|
||||||
|
|
||||||
setBdayResult({ age, diffD, totalD,
|
// Age string
|
||||||
|
let ageStr = `${ageY} Jahre, ${ageM} Monate, ${ageD} Tage`;
|
||||||
|
if (hasTime && ageH !== null) ageStr += `, ${ageH} Std. ${pad2(ageMi)} Min.`;
|
||||||
|
|
||||||
|
setBdayResult({ ageStr, diffD, totalD,
|
||||||
wday: WEEKDAYS[birth.getDay()],
|
wday: WEEKDAYS[birth.getDay()],
|
||||||
geburtstag: `${pad2(birth.getDate())}.${pad2(birth.getMonth()+1)}.${birth.getFullYear()}`,
|
geburtstag: `${pad2(birth.getDate())}.${pad2(birth.getMonth()+1)}.${birth.getFullYear()}${hasTime?' '+timeVal:''}`,
|
||||||
nextDate: `${pad2(nextBday.getDate())}.${pad2(nextBday.getMonth()+1)}.${nextBday.getFullYear()} (${nextWday})`,
|
nextDate: `${pad2(nextBday.getDate())}.${pad2(nextBday.getMonth()+1)}.${nextBday.getFullYear()} (${WEEKDAYS[nextBday.getDay()]})`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -704,24 +731,29 @@ function DatetimeRechner({ mobile }) {
|
|||||||
<div style={{display:'flex',alignItems:'flex-end',gap:10,marginBottom:16,flexWrap:'wrap'}}>
|
<div style={{display:'flex',alignItems:'flex-end',gap:10,marginBottom:16,flexWrap:'wrap'}}>
|
||||||
<div>
|
<div>
|
||||||
<div style={lbl}>Geburtsdatum</div>
|
<div style={lbl}>Geburtsdatum</div>
|
||||||
<input style={{...inp, maxWidth:220}} type="date" value={bday}
|
<input style={{...inp, maxWidth:180}} type="date" value={bday}
|
||||||
onChange={e=>calcBday(e.target.value)}/>
|
onChange={e=>calcBday(e.target.value, null)}/>
|
||||||
</div>
|
</div>
|
||||||
{!!bday && <button style={{...S.btn('#ff6b9d',false), fontSize:11, padding:'6px 14px'}}
|
<div>
|
||||||
onClick={()=>{ setBday(''); setBdayResult(null); }}>✕ Leeren</button>}
|
<div style={lbl}>Uhrzeit (optional)</div>
|
||||||
|
<input style={{...inp, maxWidth:130}} type="time" value={bdayTime}
|
||||||
|
onChange={e=>calcBday(null, e.target.value)}/>
|
||||||
|
</div>
|
||||||
|
{!!(bday||bdayTime) && <button style={{...S.btn('#ff6b9d',false), fontSize:11, padding:'6px 14px'}}
|
||||||
|
onClick={()=>{ setBday(''); setBdayTime(''); setBdayResult(null); }}>✕ Leeren</button>}
|
||||||
</div>
|
</div>
|
||||||
{bdayResult && (
|
{bdayResult && (
|
||||||
<div>
|
<div>
|
||||||
<DtRow label="Geburtsdatum" value={`${bdayResult.geburtstag} (${bdayResult.wday})`}/>
|
<DtRow label="Geburtsdatum" value={`${bdayResult.geburtstag} (${bdayResult.wday})`}/>
|
||||||
<DtRow label="Alter" value={`${bdayResult.age} Jahre`}/>
|
<DtRow label="Alter" value={bdayResult.ageStr}/>
|
||||||
<DtRow label="Nächster Geburtstag" value={bdayResult.nextDate}/>
|
<DtRow label="Nächster Geburtstag" value={bdayResult.nextDate}/>
|
||||||
<DtRow label="Tage bis Geburtstag" value={`${bdayResult.diffD} Tage`}/>
|
<DtRow label="Tage bis Geburtstag" value={`${bdayResult.diffD} Tage`}/>
|
||||||
<DtRow label="Gelebte Tage" value={`${bdayResult.totalD.toLocaleString('de-DE')} Tage`} muted/>
|
<DtRow label="Gelebte Tage" value={`${Number(bdayResult.totalD).toLocaleString('de-DE')} Tage`} muted/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!bdayResult && (
|
{!bdayResult && (
|
||||||
<div style={{color:'rgba(255,255,255,0.4)',fontFamily:'monospace',fontSize:11}}>
|
<div style={{color:'rgba(255,255,255,0.4)',fontFamily:'monospace',fontSize:11}}>
|
||||||
Geburtsdatum eingeben
|
Geburtsdatum eingeben · Uhrzeit ist optional
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user