<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Ai-Integration on Damian Galarza | Software Engineering &amp; AI Consulting</title><link>https://www.damiangalarza.com/tags/ai-integration/</link><description>Recent posts from Damian Galarza | Software Engineering &amp; AI Consulting</description><generator>Hugo</generator><language>en-us</language><managingEditor>Damian Galarza</managingEditor><atom:link href="https://www.damiangalarza.com/tags/ai-integration/feed.xml" rel="self" type="application/rss+xml"/><item><title>How to Fix LLM Date and Time Issues in Production</title><link>https://www.damiangalarza.com/posts/2026-01-07-llm-date-time-context-production/</link><pubDate>Wed, 07 Jan 2026 00:00:00 -0500</pubDate><author>Damian Galarza</author><guid>https://www.damiangalarza.com/posts/2026-01-07-llm-date-time-context-production/</guid><description>LLMs don't have access to the current date, causing issues in time-based analysis. Here's how to fix date and time handling in production LLM systems with explicit context.</description><content:encoded><![CDATA[<p>I was recently working on a project to generate summarized reporting using the Anthropic Claude API. What looked good at first eventually revealed some odd behavior in production. This post explains the problem we ran into and how we resolved it.</p>
<h2 id="the-problem">The Problem</h2>
<p>The following is adapted from a real production system but generalized for this post.</p>
<p>Take a theoretical SaaS application. The goal: generate a report of users who have low activity and identify those who are likely to churn. Let&rsquo;s take a look at an example prompt:</p>
<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#89dceb">require</span> <span style="color:#a6e3a1">&#39;anthropic&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#89dceb">require</span> <span style="color:#a6e3a1">&#39;json&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">class</span> <span style="color:#f9e2af">ChurnRiskAnalyzer</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f9e2af">SYSTEM_PROMPT</span> <span style="color:#89dceb;font-weight:bold">=</span> <span style="color:#89dceb;font-weight:bold">&lt;&lt;~</span><span style="color:#f9e2af">PROMPT</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f9e2af">You</span> are a customer success analyst<span style="color:#89dceb;font-weight:bold">.</span> <span style="color:#f9e2af">Your</span> job is to analyze user engagement
</span></span><span style="display:flex;"><span>    data <span style="color:#89dceb;font-weight:bold">and</span> identify customers at risk of churning<span style="color:#89dceb;font-weight:bold">.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f9e2af">When</span> analyzing users, identify which users are recently converted <span style="color:#f9e2af">AND</span> at high
</span></span><span style="display:flex;"><span>    risk of churning due to low engagement<span style="color:#89dceb;font-weight:bold">.</span> <span style="color:#f9e2af">Pay</span> special attention <span style="color:#a6e3a1">to</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#89dceb;font-weight:bold">-</span> <span style="color:#f9e2af">Login</span> frequency relative to their plan type
</span></span><span style="display:flex;"><span>    <span style="color:#89dceb;font-weight:bold">-</span> <span style="color:#f9e2af">Feature</span> adoption breadth
</span></span><span style="display:flex;"><span>    <span style="color:#89dceb;font-weight:bold">-</span> <span style="color:#f9e2af">Time</span> since trial conversion
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f9e2af">For</span> each user, <span style="color:#a6e3a1">state</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#fab387">1</span><span style="color:#89dceb;font-weight:bold">.</span> <span style="color:#f9e2af">Days</span> since conversion
</span></span><span style="display:flex;"><span>    <span style="color:#fab387">2</span><span style="color:#89dceb;font-weight:bold">.</span> <span style="color:#f9e2af">Whether</span> they qualify as a <span style="color:#a6e3a1">&#34;recent conversion&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fab387">3</span><span style="color:#89dceb;font-weight:bold">.</span> <span style="color:#f9e2af">Your</span> churn risk assessment <span style="color:#89dceb;font-weight:bold">and</span> reasoning
</span></span><span style="display:flex;"><span>  <span style="color:#f9e2af">PROMPT</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">def</span> <span style="color:#89b4fa">initialize</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f5e0dc">@client</span> <span style="color:#89dceb;font-weight:bold">=</span> <span style="color:#f9e2af">Anthropic</span><span style="color:#89dceb;font-weight:bold">::</span><span style="color:#f9e2af">Client</span><span style="color:#89dceb;font-weight:bold">.</span>new
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">def</span> <span style="color:#89b4fa">analyze</span>(low_engagement_users)
</span></span><span style="display:flex;"><span>    user_prompt <span style="color:#89dceb;font-weight:bold">=</span> build_user_prompt(low_engagement_users)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    response <span style="color:#89dceb;font-weight:bold">=</span> <span style="color:#f5e0dc">@client</span><span style="color:#89dceb;font-weight:bold">.</span>messages<span style="color:#89dceb;font-weight:bold">.</span>create(
</span></span><span style="display:flex;"><span>      <span style="color:#a6e3a1">model</span>: <span style="color:#a6e3a1">&#39;claude-sonnet-4-20250514&#39;</span>,
</span></span><span style="display:flex;"><span>      <span style="color:#a6e3a1">max_tokens</span>: <span style="color:#fab387">1024</span>,
</span></span><span style="display:flex;"><span>      <span style="color:#89dceb">system</span>: <span style="color:#f9e2af">SYSTEM_PROMPT</span>,
</span></span><span style="display:flex;"><span>      <span style="color:#a6e3a1">messages</span>: <span style="color:#89dceb;font-weight:bold">[</span>
</span></span><span style="display:flex;"><span>        { <span style="color:#a6e3a1">role</span>: <span style="color:#a6e3a1">&#39;user&#39;</span>, <span style="color:#a6e3a1">content</span>: user_prompt }
</span></span><span style="display:flex;"><span>      <span style="color:#89dceb;font-weight:bold">]</span>
</span></span><span style="display:flex;"><span>    )
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    response<span style="color:#89dceb;font-weight:bold">.</span>content<span style="color:#89dceb;font-weight:bold">.</span>first<span style="color:#89dceb;font-weight:bold">.</span>text
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">private</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">def</span> <span style="color:#89b4fa">build_user_prompt</span>(users)
</span></span><span style="display:flex;"><span>    <span style="color:#89dceb;font-weight:bold">&lt;&lt;~</span><span style="color:#f9e2af">PROMPT</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f9e2af">Analyze</span> the following low<span style="color:#89dceb;font-weight:bold">-</span>engagement users from the past <span style="color:#fab387">30</span> <span style="color:#a6e3a1">days</span>:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      <span style="color:#6c7086;font-style:italic">#{JSON.pretty_generate(users)}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f9e2af">PROMPT</span>
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">end</span>
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic"># Example usage</span>
</span></span><span style="display:flex;"><span>analyzer <span style="color:#89dceb;font-weight:bold">=</span> <span style="color:#f9e2af">ChurnRiskAnalyzer</span><span style="color:#89dceb;font-weight:bold">.</span>new
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>low_engagement_users <span style="color:#89dceb;font-weight:bold">=</span> <span style="color:#89dceb;font-weight:bold">[</span>
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e3a1">engagement_id</span>: <span style="color:#a6e3a1">&#39;eng_001&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#a6e3a1">last_login</span>: <span style="color:#a6e3a1">&#39;2025-12-28&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#a6e3a1">logins_past_30_days</span>: <span style="color:#fab387">2</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#a6e3a1">features_used</span>: <span style="color:#89dceb;font-weight:bold">[</span><span style="color:#a6e3a1">&#39;dashboard&#39;</span><span style="color:#89dceb;font-weight:bold">]</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#a6e3a1">user</span>: {
</span></span><span style="display:flex;"><span>      <span style="color:#89dceb">id</span>: <span style="color:#a6e3a1">&#39;usr_4821&#39;</span>,
</span></span><span style="display:flex;"><span>      <span style="color:#a6e3a1">email</span>: <span style="color:#a6e3a1">&#39;sarah@acme.co&#39;</span>,
</span></span><span style="display:flex;"><span>      <span style="color:#a6e3a1">plan</span>: <span style="color:#a6e3a1">&#39;pro&#39;</span>,
</span></span><span style="display:flex;"><span>      <span style="color:#a6e3a1">trial_converted_at</span>: <span style="color:#a6e3a1">&#39;2025-02-15&#39;</span>,
</span></span><span style="display:flex;"><span>      <span style="color:#a6e3a1">company</span>: <span style="color:#a6e3a1">&#39;Acme Corp&#39;</span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  },
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e3a1">engagement_id</span>: <span style="color:#a6e3a1">&#39;eng_002&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#a6e3a1">last_login</span>: <span style="color:#a6e3a1">&#39;2025-12-20&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#a6e3a1">logins_past_30_days</span>: <span style="color:#fab387">1</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#a6e3a1">features_used</span>: <span style="color:#89dceb;font-weight:bold">[]</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#a6e3a1">user</span>: {
</span></span><span style="display:flex;"><span>      <span style="color:#89dceb">id</span>: <span style="color:#a6e3a1">&#39;usr_9174&#39;</span>,
</span></span><span style="display:flex;"><span>      <span style="color:#a6e3a1">email</span>: <span style="color:#a6e3a1">&#39;mike@newstartup.io&#39;</span>,
</span></span><span style="display:flex;"><span>      <span style="color:#a6e3a1">plan</span>: <span style="color:#a6e3a1">&#39;pro&#39;</span>,
</span></span><span style="display:flex;"><span>      <span style="color:#a6e3a1">trial_converted_at</span>: <span style="color:#a6e3a1">&#39;2025-12-01&#39;</span>,
</span></span><span style="display:flex;"><span>      <span style="color:#a6e3a1">company</span>: <span style="color:#a6e3a1">&#39;NewStartup&#39;</span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">]</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#89dceb">puts</span> analyzer<span style="color:#89dceb;font-weight:bold">.</span>analyze(low_engagement_users)
</span></span></code></pre></div><p>Let&rsquo;s assume the date is December 29th, 2025.</p>
<p>In this example we have two users with low engagement. <code>sarah@acme.co</code> converted back in February 2025 and has 2 logins in the past 30 days. <code>mike@newstartup.io</code> converted December 1st, 2025 and has just 1 login.</p>
<p>The expected behavior: flag Mike as at risk since he converted recently and has minimal engagement. What actually happened: both Mike and Sarah were flagged. Let&rsquo;s look at why.</p>
<h2 id="lack-of-guidance">Lack of guidance</h2>
<p>In the first version of our system prompt, we mention that we want to include recent conversions—but we never define what &ldquo;recent&rdquo; means. This leaves it up to the model to decide, which leads to non-deterministic and confusing results. The fix is to provide explicit guidance:</p>
<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#cba6f7">class</span> <span style="color:#f9e2af">ChurnRiskAnalyzer</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f9e2af">SYSTEM_PROMPT</span> <span style="color:#89dceb;font-weight:bold">=</span> <span style="color:#89dceb;font-weight:bold">&lt;&lt;~</span><span style="color:#f9e2af">PROMPT</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f9e2af">You</span> are a customer success analyst<span style="color:#89dceb;font-weight:bold">.</span> <span style="color:#f9e2af">Your</span> job is to analyze user engagement
</span></span><span style="display:flex;"><span>    data <span style="color:#89dceb;font-weight:bold">and</span> identify customers at risk of churning<span style="color:#89dceb;font-weight:bold">.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    A <span style="color:#a6e3a1">&#34;recent conversion&#34;</span> is defined as a user who converted from
</span></span><span style="display:flex;"><span>    trial to paid within the past <span style="color:#fab387">30</span> days<span style="color:#89dceb;font-weight:bold">.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f9e2af">When</span> analyzing users, identify which users are recently converted <span style="color:#f9e2af">AND</span> at high
</span></span><span style="display:flex;"><span>    risk of churning due to low engagement<span style="color:#89dceb;font-weight:bold">.</span> <span style="color:#f9e2af">Pay</span> special attention <span style="color:#a6e3a1">to</span>:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#89dceb;font-weight:bold">-</span> <span style="color:#f9e2af">Login</span> frequency relative to their plan type
</span></span><span style="display:flex;"><span>    <span style="color:#89dceb;font-weight:bold">-</span> <span style="color:#f9e2af">Feature</span> adoption breadth
</span></span><span style="display:flex;"><span>    <span style="color:#89dceb;font-weight:bold">-</span> <span style="color:#f9e2af">Time</span> since trial conversion
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f9e2af">For</span> each user, <span style="color:#a6e3a1">state</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#fab387">1</span><span style="color:#89dceb;font-weight:bold">.</span> <span style="color:#f9e2af">Days</span> since conversion
</span></span><span style="display:flex;"><span>    <span style="color:#fab387">2</span><span style="color:#89dceb;font-weight:bold">.</span> <span style="color:#f9e2af">Whether</span> they qualify as a <span style="color:#a6e3a1">&#34;recent conversion&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#fab387">3</span><span style="color:#89dceb;font-weight:bold">.</span> <span style="color:#f9e2af">Your</span> churn risk assessment <span style="color:#89dceb;font-weight:bold">and</span> reasoning
</span></span><span style="display:flex;"><span><span style="color:#f9e2af">PROMPT</span>
</span></span></code></pre></div><p>Now the model has explicit guidance on what makes a &ldquo;recent conversion.&rdquo; But we can&rsquo;t stop here.</p>
<h2 id="providing-a-reference-date">Providing a reference date</h2>
<p>We&rsquo;ve updated the prompt to provide explicit guidance on what makes a recent conversion, but there&rsquo;s still one problem—the model doesn&rsquo;t know what the current date is. LLMs have no system clock access; they only know what you tell them. One way to resolve this is to provide the date as part of the prompt:</p>
<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span>  <span style="color:#cba6f7">def</span> <span style="color:#89b4fa">build_user_prompt</span>(users)
</span></span><span style="display:flex;"><span>    <span style="color:#89dceb;font-weight:bold">&lt;&lt;~</span><span style="color:#f9e2af">PROMPT</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f9e2af">Today</span><span style="color:#f38ba8">&#39;</span>s date <span style="color:#a6e3a1">is</span>: <span style="color:#6c7086;font-style:italic">#{Date.today.iso8601}.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      <span style="color:#f9e2af">Analyze</span> the following low<span style="color:#89dceb;font-weight:bold">-</span>engagement users from the past <span style="color:#fab387">30</span> <span style="color:#a6e3a1">days</span>:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      <span style="color:#6c7086;font-style:italic">#{JSON.pretty_generate(users)}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f9e2af">PROMPT</span>
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">end</span>
</span></span></code></pre></div><p>Now the model has everything it needs for accurate reporting. Running this updated version correctly excludes Sarah, who signed up months ago, and flags only Mike.</p>
<h2 id="conclusion">Conclusion</h2>
<p>When working with LLMs and time-sensitive data:</p>
<ol>
<li><strong>Be explicit about definitions</strong> - Don&rsquo;t assume the model interprets terms like &ldquo;recent&rdquo; the same way you do.</li>
<li><strong>Always provide the current date</strong> - LLMs have no awareness of real-time; include today&rsquo;s date in your prompt.</li>
<li><strong>Test with edge cases</strong> - Run your prompts with data that spans different time periods to catch these issues early.</li>
</ol>
<p>These might seem like small details, but in production systems where accuracy matters, they make the difference between useful analysis and misleading results. Subtle errors like these erode trust quickly.</p>
<hr>
<p>Building LLM features into a Rails app and running into issues like this? My book <a href="/building-llm-applications/">Building LLM Applications in Rails</a> covers the patterns that hold up in production.</p>
]]></content:encoded></item></channel></rss>