Snowflake • inspect the timestamp contract — Choose an explicit conversion signature and preserve the distinction between an unzoned wall-clock result and a zone-offset timestamp,…

HTML for this example

Select the code and use your copy shortcut. Changes in this preview are temporary.

<!doctype html>
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Snowflake • inspect the timestamp contract</title><style>*{box-sizing:border-box}body{margin:0;background:var(--bg,#f3f7fa);color:var(--ink,#203342);font:16px/1.55 system-ui,Segoe UI,sans-serif}main{max-width:1100px;margin:auto;padding:28px 30px 50px}h1{font-size:clamp(27px,3.5vw,40px);line-height:1.18;letter-spacing:-.035em;margin:8px 0 12px}h2{font-size:21px;line-height:1.35;margin:0 0 16px}h3{font-size:18px}.eyebrow{color:var(--accent,#176783);font-size:12px;letter-spacing:.12em;font-weight:800;text-transform:uppercase}.intro,.muted,small{color:#516272}.intro{margin:0 0 24px}.panel{padding:24px;border:1px solid var(--line,#d6e0e7);border-radius:12px;background:white;margin:18px 0}.grid{display:grid;grid-template-columns:1fr 1fr;gap:22px}.grid>*{min-width:0}.controls{display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin:16px 0}button,input,textarea,select{font:inherit}button{border:1px solid var(--accent,#176783);background:var(--accent,#176783);color:white;padding:10px 16px;min-height:44px;border-radius:7px;font-weight:700;cursor:pointer}button.secondary{background:white;color:var(--accent,#176783)}button[aria-pressed=true]{background:var(--tint,#e3f2f8);color:var(--ink,#203342);box-shadow:inset 0 0 0 2px var(--accent,#176783)}button:hover{filter:brightness(.96)}:focus-visible{outline:3px solid #d56b00;outline-offset:3px}label{display:block;margin:12px 0 5px;font-size:14px;font-weight:650}input:not([type=checkbox]),select,textarea{width:100%;padding:10px 12px;min-height:44px;border:1px solid #94a5b2;background:white;color:inherit;border-radius:7px}textarea{resize:vertical;min-height:120px}input[type=checkbox]{width:20px;height:20px;margin-right:9px}label.inline{display:flex;align-items:center;font-weight:500;gap:7px}.result{padding:24px;background:var(--tint,#e3f2f8);border:1px solid var(--line,#c8dce7);border-radius:12px}.big{font-size:clamp(30px,5vw,48px);font-weight:780;line-height:1.25;letter-spacing:-.035em;margin:10px 0}.trace{font:15px/1.7 ui-monospace,Consolas,monospace;white-space:pre-wrap;overflow-wrap:anywhere}.error{color:#a12820;font-weight:650;min-height:24px}.table-wrap{overflow-x:auto}table{border-collapse:collapse;width:100%;font-size:15px}th,td{text-align:left;border-bottom:1px solid var(--line,#d6e0e7);padding:12px 9px;vertical-align:top}th{font-size:12px;text-transform:uppercase;letter-spacing:.03em;color:#516272}code,pre,.code{font:14px/1.65 ui-monospace,Consolas,monospace}pre{white-space:pre-wrap;overflow-wrap:anywhere;background:var(--tint,#eef3f7);padding:16px;border-radius:6px}details{border-top:1px solid var(--line,#d6e0e7);margin:24px 0;padding-top:16px}summary{cursor:pointer;font-weight:700;min-height:44px}footer{border-top:1px solid var(--line,#d6e0e7);margin-top:26px;padding-top:16px;font-size:13px;color:#516272}.bar{height:16px;background:#dce4ea;border-radius:20px;overflow:hidden;margin:12px 0}.bar span{display:block;height:100%;background:var(--accent,#176783)}[hidden]{display:none!important}@media(max-width:720px){main{padding:20px}.grid{grid-template-columns:1fr;gap:12px}.panel,.result{padding:20px}}@media(max-width:400px){main{padding:16px}.panel,.result{padding:16px}button{padding:10px 13px}}
body{--accent:#19608d;--bg:#f3f7fb;--tint:#e5f2fc;--line:#cbdfed}.type-line{display:flex;gap:18px;flex-wrap:wrap;align-items:center}.type-line b{background:#16547c;color:white;padding:5px 12px;border-radius:5px;font:700 15px ui-monospace,Consolas,monospace}.result .big{font-size:clamp(23px,3.6vw,44px);font-variant-numeric:tabular-nums}.result{border-left:5px solid #2586b5}</style></head><body><main>
<header><span class="eyebrow">Typed timestamp lab / January 15, 2024</span><h1>The clock is only half the result.</h1><p class="intro">Compare three fixed contracts and inspect the logical value, offset, and returned type.</p></header>
<nav class="controls" aria-label="Conversion case"><button type="button" id="c1" class="secondary">C1 · explicit NTZ</button><button type="button" id="c2" class="secondary">C2 · offset TZ</button><button type="button" id="c3" class="secondary">C3 · session NTZ</button></nav>
<section class="result"><span class="eyebrow">Expected logical result • local arithmetic</span><div class="big" id="result">2024-01-15 12:00:00</div><div class="type-line"><b id="result-type">TIMESTAMP_NTZ</b><span id="offset">No attached offset</span></div><p id="rule">Three arguments: explicit UTC source, UTC target.</p><p id="trace" class="trace"></p></section>
<div class="grid"><section class="panel"><h2 id="case-title">C1 · Wall clock → wall clock</h2><label for="clock">Input wall-clock time (HH:MM)</label><input id="clock" type="text" value="12:00"><p id="input-type" class="muted">Explicit TIMESTAMP_NTZ · date fixed at 2024-01-15.</p><div id="offset-input" hidden><label for="input-offset">Input UTC offset (±HHMM)</label><input id="input-offset" type="text" value="+0200"></div><div id="session-input" hidden><label class="inline"><input type="checkbox" id="session">Use the declared fixture session TIMEZONE = UTC</label><small>This declares an assumption; it does not set or verify a Snowflake session.</small></div><label class="inline"><input type="checkbox" id="null-target">Use a SQL NULL target argument</label><div class="controls"><button type="button" id="calculate">Calculate expectation</button><button type="button" id="reset" class="secondary">Reset fixtures</button></div><p id="error" class="error" role="alert"></p></section>
<section class="panel"><h2>Native SELECT specification</h2><label for="sql">Generated SQL — manual copying</label><textarea id="sql" class="code" readonly rows="8"></textarea><div class="controls"><button type="button" id="select-sql" class="secondary">Select text</button></div><small>Select the exact SQL, then copy it manually to your authorized native workflow.</small></section></div>
<section class="panel"><h2>Same noon, different evidence</h2><div class="table-wrap"><table><thead><tr><th>Case</th><th>Original expected value</th><th>Return type</th><th>Source rule</th></tr></thead><tbody><tr><td>C1</td><td>12:00, no offset</td><td>NTZ</td><td>Explicit UTC argument</td></tr><tr><td>C2</td><td>10:00 +0000</td><td>TZ</td><td>Noon +0200 input</td></tr><tr><td>C3</td><td>12:00 +0000</td><td>TZ</td><td>Declared UTC session</td></tr></tbody></table></div></section>
<details><summary>Keep native evidence separate</summary><p>Record the actual input type, logical result, output formatting, session TIMEZONE, environment/version, source revision, and any subsequent cast. Determine the active TZDB release on the authorized instance with SYSTEM$GET_TZDB_VERSION; availability and results are unobserved here.</p><label for="native-notes">Native observations (optional, not saved)</label><textarea id="native-notes" placeholder="Leave blank until observed on your instance."></textarea></details>
<footer>A bounded HTML companion, not a Snowflake runtime. UTC-only source/target fixtures and explicit numeric offsets are supported; no IANA/DST ambiguity policy is inferred. NULL is distinct from invalid input. Expected display is logical notation, not captured Snowflake formatting or native type evidence.</footer>
</main><script>const $=id=>document.getElementById(id);const on=(id,e,fn)=>$(id).addEventListener(e,fn);const txt=(id,v)=>$(id).textContent=v;const esc=s=>String(s).replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));const positive=x=>String(x).trim()!==''&&Number.isFinite(Number(x))&&Number(x)>0;const num=x=>Number(x.toPrecision(10)).toString();function enter(id,fn){on(id,'keydown',e=>{if(e.key==='Enter'&&!e.isComposing&&e.keyCode!==229){e.preventDefault();fn()}})}function selectText(id){$(id).focus();$(id).select()}

let caseId='c1';
function timestampExpectation(which,clock,offset,session,isNull){if(!/^(?:[01]\d|2[0-3]):[0-5]\d$/.test(clock))throw Error('Enter a valid 24-hour time as HH:MM.');let minutes=0;if(which==='c2'){if(!/^[+-](?:0\d|1[0-4])[0-5]\d$/.test(offset)||(/^[-+]14/.test(offset)&&!offset.endsWith('00')))throw Error('Use an offset from -1400 through +1400, with valid minutes.');minutes=(Number(offset.slice(1,3))*60+Number(offset.slice(3)))*(offset[0]==='-'?-1:1)}if(which==='c3'&&!session)throw Error('Declare the UTC session assumption for C3; an unknown session cannot be inferred.');if(isNull)return {value:'NULL',type:'NULL',offset:'No timestamp value',trace:'A SQL NULL argument produces NULL.'};const [h,m]=clock.split(':').map(Number),date=new Date(Date.UTC(2024,0,15,h,m)-minutes*60000);return {value:date.toISOString().slice(0,19).replace('T',' '),type:which==='c1'?'TIMESTAMP_NTZ':'TIMESTAMP_TZ',offset:which==='c1'?'No attached offset':'+0000',trace:which==='c2'?clock+' '+offset+' represents the same instant as '+date.toISOString().slice(11,16)+' UTC.':which==='c1'?'Wall-clock fields unchanged; source UTC is an argument, not attached metadata.':'NTZ is interpreted using the declared UTC session.'}}
function pending(){txt('result','Expectation pending');txt('result-type','');txt('offset','');txt('trace','');$('sql').value='';txt('error','')}
function calculate(){try{const r=timestampExpectation(caseId,$('clock').value,$('input-offset').value,$('session').checked,$('null-target').checked);txt('result',r.value);txt('result-type',r.type);txt('offset',r.offset);txt('trace',r.trace);const target=$('null-target').checked?'NULL':"'UTC'",lit='2024-01-15 '+$('clock').value+':00';$('sql').value=caseId==='c1'?"SELECT CONVERT_TIMEZONE('UTC', "+target+",\n  '"+lit+"'::TIMESTAMP_NTZ) AS c1;":'SELECT CONVERT_TIMEZONE('+target+",\n  '"+lit+(caseId==='c2'?' '+$('input-offset').value:'')+"'::TIMESTAMP_"+(caseId==='c2'?'TZ':'NTZ')+') AS '+caseId+';';if(caseId==='c3')$('sql').value='-- Assumes session TIMEZONE = UTC; verify separately.\n'+$('sql').value;txt('error','')}catch(e){pending();txt('result','No current expectation');txt('error',e.message)}}
function choose(which){caseId=which;for(const id of ['c1','c2','c3'])$(id).setAttribute('aria-pressed',String(id===which));$('offset-input').hidden=which!=='c2';$('session-input').hidden=which!=='c3';txt('case-title',{c1:'C1 · Wall clock → wall clock',c2:'C2 · Offset input → UTC instant',c3:'C3 · Session-interpreted NTZ'}[which]);txt('input-type','Explicit TIMESTAMP_'+(which==='c2'?'TZ':'NTZ')+' · date fixed at 2024-01-15.');txt('rule',{c1:'Three arguments: explicit UTC source, UTC target.',c2:'Two arguments: source offset is carried by the input.',c3:'Two arguments: source interpretation depends on the declared session.'}[which]);pending();calculate()}
for(const id of ['c1','c2','c3'])on(id,'click',()=>choose(id));for(const id of ['clock','input-offset','session','null-target']){on(id,'input',pending);on(id,'change',pending)}on('calculate','click',calculate);enter('clock',calculate);on('select-sql','click',()=>selectText('sql'));on('reset','click',()=>{$('clock').value='12:00';$('input-offset').value='+0200';$('session').checked=false;$('null-target').checked=false;choose('c1')});choose('c1');
</script></body></html>