Date published: 2025-06-20
Source:
Amy and ChatGPT (ID1356)Author: Howard, Amy (ID633)
Primary doc? 0
Published in:
Race described:
Full text? 0
Online link:
Content id: 27777
Filename received: ChatGPT Image Sep 30, 2025, 10_10_30 PM.png
Filename assigned: 2025-09-30_chatgpt_timeclock.webp
2025-09-30 - 0000-00-00
Time calculator
Skip to content
Chat history
You said:
write a script for a time calculator that allows me to enter a start and stop time and yield hours and minutes as well as decimal quantity. I will put it on my wordpress blog
ChatGPT said:
Thought
Got it. Here are two drop-in options. Pick one:
Option A — paste in a Gutenberg “Custom HTML” block
<div class="ppv-timecalc" data-widget="timecalc">
<form>
<div style="display:grid;gap:.5rem;grid-template-columns:repeat(2,minmax(0,1fr));max-width:560px">
<label>Start
<input type="time" id="ppv-start" required step="60">
</label>
<label>Stop
<input type="time" id="ppv-stop" required step="60">
</label>
<label>Break (minutes)
<input type="number" id="ppv-break" min="0" step="1" value="0" inputmode="numeric">
</label>
<label>Rounding
<select id="ppv-round">
<option value="none">None</option>
<option value="0.25">Quarter hours (0.25)</option>
<option value="0.1">Tenths (0.1)</option>
<option value="0.01">Hundredths (0.01)</option>
<option value="1/6">6-min (0.1h=6m)</option>
</select>
</label>
</div>
<div style="margin:.75rem 0;display:flex;gap:.5rem;flex-wrap:wrap">
<button type="button" id="ppv-calc">Calculate</button>
<button type="reset" id="ppv-reset">Reset</button>
</div>
<div id="ppv-output" aria-live="polite" style="border:1px solid #ddd;padding:1rem;border-radius:.5rem;max-width:560px">
<strong>Result:</strong>
<div id="ppv-result-text">—</div>
</div>
<small style="display:block;margin-top:.5rem;max-width:560px;opacity:.8">
Notes: crosses midnight automatically (e.g., 22:30 → 02:15). Break is subtracted. “Rounding” applies to decimal hours only.
</small>
</form>
</div>
<script>
(function(){
const $ = sel => document.querySelector(sel);
function parseTimeToMinutes(t){
if(!t) return NaN;
const [h,m] = t.split(':').map(Number);
return h*60 + (m||0);
}
function roundDecimalHours(h, mode){
if(mode === 'none') return h;
if(mode === '1/6') { // 6-minute increments = 0.1h
return Math.round(h/0.1)*0.1;
}
const step = Number(mode);
return Math.round(h/step)*step;
}
function fmt(h, m){
const pad = n => String(n).padStart(2,'0');
return `${h}:${pad(m)}`;
}
function calc(){
const start = parseTimeToMinutes($('#ppv-start').value);
const stop = parseTimeToMinutes($('#ppv-stop').value);
const brk = Number($('#ppv-break').value||0);
const mode = $('#ppv-round').value;
if(Number.isNaN(start) || Number.isNaN(stop)){
$('#ppv-result-text').textContent = 'Enter start and stop times.';
return;
}
// handle overnight
let minutes = stop - start;
if(minutes < 0) minutes += 24*60;
// subtract break
minutes -= Math.max(0, brk);
if(minutes < 0){
$('#ppv-result-text').textContent = 'Break exceeds worked time.';
return;
}
const hoursInt = Math.floor(minutes/60);
const minsInt = minutes % 60;
const decimal = minutes/60;
const decimalRounded = roundDecimalHours(decimal, mode);
const decimalRoundedStr = decimalRounded.toFixed(
mode==='none' ? 3 :
mode==='0.25' ? 2 :
mode==='0.1' ? 1 :
mode==='1/6' ? 1 : 2
);
$('#ppv-result-text').innerHTML =
`<div><b>Hours:Minutes</b> = ${fmt(hoursInt, minsInt)}</div>
<div><b>Decimal hours</b> = ${decimal.toFixed(3)} (rounded: ${decimalRoundedStr})</div>
<div><b>Total minutes</b> = ${minutes}</div>`;
}
$('#ppv-calc').addEventListener('click', calc);
// auto-calc on input
['#ppv-start','#ppv-stop','#ppv-break','#ppv-round'].forEach(sel=>{
$(sel).addEventListener('input', calc);
});
$('#ppv-reset').addEventListener('click', ()=>{ setTimeout(()=>{$('#ppv-result-text').textContent='—';},0); });
})();
</script>
<style>
.ppv-timecalc label{display:flex;flex-direction:column;font-weight:600;font-size:.95rem}
.ppv-timecalc input, .ppv-timecalc select, .ppv-timecalc button{
font:inherit; padding:.5rem .6rem; border:1px solid #ccc; border-radius:.5rem;
}
.ppv-timecalc button{cursor:pointer}
.ppv-timecalc button:hover{filter:brightness(.98)}
</style>
Option B — WordPress shortcode (drop into your child theme’s functions.php)
This gives you a [timecalc] shortcode you can place anywhere.
// === Paperless Ponte Vedra: Time Calculator Shortcode ===
function ppv_timecalc_shortcode($atts){
ob_start(); ?>
<div class="ppv-timecalc" data-widget="timecalc">
<form>
<div style="display:grid;gap:.5rem;grid-template-columns:repeat(2,minmax(0,1fr));max-width:560px">
<label>Start
<input type="time" id="ppv-start" required step="60">
</label>
<label>Stop
<input type="time" id="ppv-stop" required step="60">
</label>
<label>Break (minutes)
<input type="number" id="ppv-break" min="0" step="1" value="0" inputmode="numeric">
</label>
<label>Rounding
<select id="ppv-round">
<option value="none">None</option>
<option value="0.25">Quarter hours (0.25)</option>
<option value="0.1">Tenths (0.1)</option>
<option value="0.01">Hundredths (0.01)</option>
<option value="1/6">6-min (0.1h=6m)</option>
</select>
</label>
</div>
<div style="margin:.75rem 0;display:flex;gap:.5rem;flex-wrap:wrap">
<button type="button" id="ppv-calc">Calculate</button>
<button type="reset" id="ppv-reset">Reset</button>
</div>
<div id="ppv-output" aria-live="polite" style="border:1px solid #ddd;padding:1rem;border-radius:.5rem;max-width:560px">
<strong>Result:</strong>
<div id="ppv-result-text">—</div>
</div>
<small style="display:block;margin-top:.5rem;max-width:560px;opacity:.8">
Notes: crosses midnight automatically (e.g., 22:30 → 02:15). Break is subtracted. “Rounding” applies to decimal hours only.
</small>
</form>
</div>
<style>
.ppv-timecalc label{display:flex;flex-direction:column;font-weight:600;font-size:.95rem}
.ppv-timecalc input,.ppv-timecalc select,.ppv-timecalc button{font:inherit;padding:.5rem .6rem;border:1px solid #ccc;border-radius:.5rem}
.ppv-timecalc button{cursor:pointer}
.ppv-timecalc button:hover{filter:brightness(.98)}
</style>
<script>
(function(){
const root = document.currentScript.closest('.ppv-timecalc');
const $ = sel => root.querySelector(sel);
function parseTimeToMinutes(t){ if(!t) return NaN; const [h,m]=t.split(':').map(Number); return h*60+(m||0); }
function roundDecimalHours(h, mode){
if(mode==='none') return h;
if(mode==='1/6') return Math.round(h/0.1)*0.1;
const step = Number(mode); return Math.round(h/step)*step;
}
function fmt(h,m){ const pad=n=>String(n).padStart(2,'0'); return h+':'+pad(m); }
function calc(){
const start=parseTimeToMinutes($('#ppv-start').value);
const stop=parseTimeToMinutes($('#ppv-stop').value);
const brk=Number($('#ppv-break').value||0);
const mode=$('#ppv-round').value;
if(Number.isNaN(start)||Number.isNaN(stop)){ $('#ppv-result-text').textContent='Enter start and stop times.'; return; }
let minutes=stop-start; if(minutes<0) minutes+=24*60;
minutes-=Math.max(0,brk);
if(minutes<0){ $('#ppv-result-text').textContent='Break exceeds worked time.'; return; }
const hInt=Math.floor(minutes/60), mInt=minutes%60, dec=minutes/60;
const decR=roundDecimalHours(dec, mode);
const decRstr=decR.toFixed(mode==='none'?3:mode==='0.25'?2:mode==='0.1'||mode==='1/6'?1:2);
$('#ppv-result-text').innerHTML =
'<div><b>Hours:Minutes</b> = '+fmt(hInt,mInt)+'</div>'+
'<div><b>Decimal hours</b> = '+dec.toFixed(3)+' (rounded: '+decRstr+')</div>'+
'<div><b>Total minutes</b> = '+minutes+'</div>';
}
root.querySelector('#ppv-calc').addEventListener('click', calc);
['#ppv-start','#ppv-stop','#ppv-break','#ppv-round'].forEach(sel=>$(sel).addEventListener('input', calc));
root.querySelector('#ppv-reset').addEventListener('click', ()=>{ setTimeout(()=>{ $('#ppv-result-text').textContent='—'; },0); });
})();
</script>
<?php
return ob_get_clean();
}
add_shortcode('timecalc','ppv_timecalc_shortcode');
How to use
Option A: paste the HTML block where you want the calculator.
Option B: add the PHP to your child theme (or a small “Code Snippets” plugin), then put [timecalc] in any post/page.
Behavior you get (no surprises)
Accepts 24-hour or your browser’s AM/PM time picker.
Handles overnight shifts cleanly (e.g., 22:30 → 02:15).
Subtracts an optional break in minutes.
Shows HH:MM, total minutes, raw decimal hours (3 d.p.), and a rounded decimal (tenths, quarters, hundredths, or 6-minute billing).
Live updates as you type + a Calculate button for mouse first users.
Accessible: labeled fields, results announced via aria-live.
Want me to skin it to your site palette and Divi classes? Give me your hex codes and I’ll wire it up.
You said:
nothing happens when I click calculate
ChatGPT said:
Thought
You’re hitting a JS-scope/ordering issue. Fix it by scoping the code to the widget container and waiting for DOM ready. Replace just your <script>…</script> with this version:
<script>
document.addEventListener('DOMContentLoaded', function(){
// Support multiple calculators on one page + avoid ID collisions
document.querySelectorAll('.ppv-timecalc[data-widget="timecalc"]').forEach(function(root){
const $ = sel => root.querySelector(sel);
function parseTimeToMinutes(t){
if(!t) return NaN;
const [h,m] = t.split(':').map(Number);
return h*60 + (m||0);
}
function roundDecimalHours(h, mode){
if(mode === 'none') return h;
if(mode === '1/6') return Math.round(h/0.1)*0.1; // 6-min increments
const step = Number(mode);
return Math.round(h/step)*step;
}
function fmt(h, m){
const pad = n => String(n).padStart(2,'0');
return `${h}:${pad(m)}`;
}
function calc(){
const start = parseTimeToMinutes($('#ppv-start')?.value);
const stop = parseTimeToMinutes($('#ppv-stop')?.value);
const brk = Number($('#ppv-break')?.value || 0);
const mode = $('#ppv-round')?.value || 'none';
if(Number.isNaN(start) || Number.isNaN(stop)){
$('#ppv-result-text').textContent = 'Enter start and stop times.';
return;
}
let minutes = stop - start;
if(minutes < 0) minutes += 24*60; // overnight
minutes -= Math.max(0, brk); // subtract break
if(minutes < 0){
$('#ppv-result-text').textContent = 'Break exceeds worked time.';
return;
}
const hoursInt = Math.floor(minutes/60);
const minsInt = minutes % 60;
const decimal = minutes/60;
const decimalRounded = roundDecimalHours(decimal, mode);
const decimalRoundedStr = decimalRounded.toFixed(
mode==='none' ? 3 :
mode==='0.25' ? 2 :
mode==='0.1' ? 1 :
mode==='1/6' ? 1 : 2
);
$('#ppv-result-text').innerHTML =
`<div><b>Hours:Minutes</b> = ${fmt(hoursInt, minsInt)}</div>
<div><b>Decimal hours</b> = ${decimal.toFixed(3)} (rounded: ${decimalRoundedStr})</div>
<div><b>Total minutes</b> = ${minutes}</div>`;
}
// Wire up events inside this widget only
root.querySelector('#ppv-calc')?.addEventListener('click', calc);
['#ppv-start','#ppv-stop','#ppv-break','#ppv-round'].forEach(sel=>{
root.querySelector(sel)?.addEventListener('input', calc);
});
root.querySelector('#ppv-reset')?.addEventListener('click', ()=>{
setTimeout(()=>{ root.querySelector('#ppv-result-text').textContent='—'; },0);
});
});
});
</script>
Why this works:
Waits for DOMContentLoaded so the button exists before we attach listeners.
Scopes all queries to the .ppv-timecalc container, so other IDs/plugins won’t collide.
Safe-guards (?.) prevent a silent failure if a field is missing.
If you’d rather not rely on inline scripts (some themes/plugins defer/strip them), use the shortcode version I gave earlier (Option B). It already scopes to the widget via document.currentScript.closest(...) and avoids the global-ID trap.
You said:
excellent. thank you
ChatGPT said:
You’re very welcome, Amy — glad it’s working now! That script should keep running reliably no matter how your theme handles scripts. If you later want it styled to look like a native Divi module (matching your brand colors and buttons), just let me know your hex codes and I’ll drop in a tailored CSS layer so it feels seamless on Paperless Ponte Vedra.
draw a picture of an old-fashioned timeclock for the time calculator you just made for me
Cross references
No cross references.