Coding interviews
using System;
using System.Linq;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
var clock=new ManualClock(new DateTimeOffset(2030,1,1,0,0,0,TimeSpan.Zero));
var window=new SubmissionWindow(clock,TimeSpan.FromMinutes(30));
clock.Advance(TimeSpan.FromMinutes(29)); Console.WriteLine("before:"+window.Allowed().ToString().ToLowerInvariant());
clock.Advance(TimeSpan.FromMinutes(1)); Console.WriteLine("at deadline:"+window.Allowed().ToString().ToLowerInvariant());
sealed class SubmissionWindow { private readonly TimeProvider clock; private readonly DateTimeOffset deadline;
public SubmissionWindow(TimeProvider clock,TimeSpan duration) { if(duration<TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(duration)); this.clock=clock; deadline=clock.GetUtcNow()+duration; }
public bool Allowed()=>clock.GetUtcNow()<deadline;
}
sealed class ManualClock(DateTimeOffset now):TimeProvider { private DateTimeOffset current=now; public override DateTimeOffset GetUtcNow()=>current; public void Advance(TimeSpan duration) { if(duration<TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(duration)); current+=duration; } }
Reveal answer and reasoning
The output lines, in order, are “before:true”; “at deadline:false”. The window captures a deadline thirty minutes after the fixed starting instant. Advancing the manual clock twenty-nine minutes makes Allowed true, then one more minute makes it false. The output depends on supplied logical timestamps rather than processor speed or wall-clock sleeps. The clock subclass overrides only the operation used by this policy.
The strict comparison makes the equality boundary observable. Constructing the window reads the clock once to establish the deadline; later reads compare against that fixed value. Reconstructing a new window on each request would instead extend the allowance, which would be a different and usually unintended service contract.
Creating the window and checking it use O(1) time and state. Capturing one deadline avoids repeatedly extending the interval on every query. UTC timestamps simplify this fixture, but a real elapsed-duration budget may require monotonic timestamps and a clear clock-change policy. A manual GetUtcNow override does not automatically control TimeProvider timers or Task.Delay. Client-supplied timestamps are also not trustworthy authorization evidence.
The code neither persists deadlines across restarts nor arbitrates concurrent submissions arriving at a server boundary.
What a strong answer covers
- Exact output: before:true | at deadline:false
- The window captures a deadline thirty minutes after the fixed starting instant.
- A manual GetUtcNow override does not automatically control TimeProvider timers or Task.Delay.
Common pitfall
A manual GetUtcNow override does not automatically control TimeProvider timers or Task.Delay. Client-supplied timestamps are also not trustworthy authorization evidence. The code neither persists deadlines across restarts nor arbitrates concurrent submissions arriving at a server boundary.
Follow-up questions
- Test zero duration, a negative duration and one tick before the deadline. Hint: equality belongs to the rejected side because the comparison is strictly less than. Avoid adding sleeps to obtain these boundary cases.
- How should an absolute deadline behave when the authoritative wall clock moves backward?
Self-review
Choose what to revisit. These marks are your own assessment and are separate from lesson completion.