<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: perez odiyo</title>
    <description>The latest articles on DEV Community by perez odiyo (@perezodiyo).</description>
    <link>https://dev.to/perezodiyo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3945422%2F496b7531-ce1b-4b5c-afb1-4e3e5a34bd5d.png</url>
      <title>DEV Community: perez odiyo</title>
      <link>https://dev.to/perezodiyo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/perezodiyo"/>
    <language>en</language>
    <item>
      <title># Go Beginner Mistake #2: Why `time.Now().Format("YYYY-MM-DD")` Doesn't Work in Go</title>
      <dc:creator>perez odiyo</dc:creator>
      <pubDate>Sat, 06 Jun 2026 16:24:40 +0000</pubDate>
      <link>https://dev.to/perezodiyo/-go-beginner-mistake-2-why-timenowformatyyyy-mm-dd-doesnt-work-in-go-3j22</link>
      <guid>https://dev.to/perezodiyo/-go-beginner-mistake-2-why-timenowformatyyyy-mm-dd-doesnt-work-in-go-3j22</guid>
      <description>&lt;p&gt;&lt;em&gt;Dearest learner&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I hope this post finds you well.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you're here because &lt;code&gt;time.Now().Format("YYYY-MM-DD")&lt;/code&gt; isn't doing what you expected, pull up a chair. I spent an embarrassing amount of time staring at that exact problem, and today I'd like to save you the trouble.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  First, Some Embarrassing Context
&lt;/h2&gt;

&lt;p&gt;If you read my last post, you already know I was building a Net-Cat project in Go and got burned by &lt;code&gt;log.Println()&lt;/code&gt; silently adding its own timestamp to my output. Fun times.&lt;/p&gt;

&lt;p&gt;Well — I hadn't even gotten to that bug yet. Before I ran into the &lt;code&gt;log&lt;/code&gt; problem, I was still fighting a more basic battle: &lt;strong&gt;just getting a timestamp to print correctly in the first place.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is that story.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Expected
&lt;/h2&gt;

&lt;p&gt;I come from a JavaScript background. In JS, formatting a date looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// JavaScript&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 2025-01-15T14:32:05.000Z&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in Python, it's something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Python
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%Y-%m-%d&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# 2025-01-15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the pattern? Both use &lt;strong&gt;placeholder tokens&lt;/strong&gt;. &lt;code&gt;YYYY&lt;/code&gt; means "put the 4-digit year here." &lt;code&gt;MM&lt;/code&gt; means "put the month here." &lt;code&gt;%d&lt;/code&gt; means "put the day here." They're basically fill-in-the-blank templates where each token represents a concept.&lt;/p&gt;

&lt;p&gt;So when I opened a Go file and typed this, it felt completely natural:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// What I tried first (very wrong)&lt;/span&gt;
&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"YYYY-MM-DD"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hit run.&lt;/p&gt;

&lt;p&gt;The output was: &lt;code&gt;YYYY-MM-DD&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Just... the string. Printed back at me, unchanged. No date. No numbers. Nothing.&lt;/p&gt;

&lt;p&gt;I sat there for a second. Then I tried &lt;code&gt;"yyyy-mm-dd"&lt;/code&gt;. Same thing. Then &lt;code&gt;"%Y-%m-%d"&lt;/code&gt; like Python. Same thing. Go was just printing whatever I typed, completely unbothered.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Thing Nobody Warned Me About
&lt;/h2&gt;

&lt;p&gt;Here's what Go actually does, and I wish someone had just said this to me directly on day one:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Go doesn't use placeholder tokens. It uses a real, specific reference date.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That reference date is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Mon Jan 2 15:04:05 MST 2006
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or written out in numbers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;01/02 03:04:05PM '06 -0700
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You use &lt;em&gt;that exact date&lt;/em&gt; — in whatever arrangement you want — as your format string. Go looks at your string, recognises the pieces of that reference date inside it, and replaces them with today's values.&lt;/p&gt;

&lt;p&gt;So instead of &lt;code&gt;"YYYY-MM-DD"&lt;/code&gt;, you write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2006-01-02"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c"&gt;// Output: 2025-01-15&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;2006&lt;/code&gt; is the year. That &lt;code&gt;01&lt;/code&gt; is the month. That &lt;code&gt;02&lt;/code&gt; is the day. Not because those are magic tokens — but because &lt;strong&gt;January 2nd, 2006&lt;/strong&gt; is the reference date Go was built around.&lt;/p&gt;

&lt;p&gt;The first time I read that, I genuinely thought the documentation was trolling me.&lt;/p&gt;




&lt;h2&gt;
  
  
  And Then I Used the Wrong Date
&lt;/h2&gt;

&lt;p&gt;Even after I understood the concept — &lt;em&gt;"use a real reference date"&lt;/em&gt; — I still got burned. Because I thought: okay, any date will do. I need year-month-day, so I'll just write a date in that order.&lt;/p&gt;

&lt;p&gt;I typed &lt;code&gt;"2020-02-12"&lt;/code&gt; and felt confident.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2020-02-12"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c"&gt;// I expected: 2025-01-15&lt;/span&gt;
&lt;span class="c"&gt;// I got:      10100-10-1110&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output looked like a date the way binary looks like a number — technically valid, completely unreadable.&lt;/p&gt;

&lt;p&gt;Chaos. The numbers were all shuffled wrong.&lt;/p&gt;

&lt;p&gt;Here's why: Go didn't see a random date. It looked at &lt;code&gt;2020&lt;/code&gt; and tried to find pieces of the reference date (&lt;code&gt;Mon Jan 2 15:04:05 MST 2006&lt;/code&gt;) inside it. It found &lt;code&gt;20&lt;/code&gt; — that's the timezone offset token. It found &lt;code&gt;02&lt;/code&gt; — that's the day. &lt;code&gt;12&lt;/code&gt; — that's the 12-hour clock hour. None of it meant what I wanted.&lt;/p&gt;

&lt;p&gt;The format string isn't a template where &lt;em&gt;any&lt;/em&gt; date works. It has to be &lt;strong&gt;that specific date&lt;/strong&gt; — January 2nd, 2006. That's the one Go knows. Any other date is just a string full of ambiguous numbers it'll try to interpret as tokens, with confusing results.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// This is the only date Go understands as a format&lt;/span&gt;
&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2006-01-02"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c"&gt;// ✓&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tattoo it somewhere. &lt;code&gt;2006-01-02&lt;/code&gt;. Year, month, day — from the one reference date. Not your birthday. Not today's date. Not a date that "looks right." The reference date.&lt;/p&gt;




&lt;h2&gt;
  
  
  The "Wait, Why?!" Moment
&lt;/h2&gt;

&lt;p&gt;Okay but &lt;em&gt;why&lt;/em&gt; that specific date? Why not just use &lt;code&gt;YYYY&lt;/code&gt; like a normal language?&lt;/p&gt;

&lt;p&gt;This is the part that actually made me laugh once I understood it.&lt;/p&gt;

&lt;p&gt;That reference date — &lt;code&gt;01/02 03:04:05PM '06 -0700&lt;/code&gt; — is special because each component is a &lt;strong&gt;unique number&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Month: &lt;code&gt;01&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Day: &lt;code&gt;02&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Hour: &lt;code&gt;03&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Minute: &lt;code&gt;04&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Second: &lt;code&gt;05&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Year: &lt;code&gt;06&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Timezone offset: &lt;code&gt;07&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They count up: 1, 2, 3, 4, 5, 6, 7. Go uses this sequence so it can unambiguously look at any format string and know &lt;em&gt;exactly&lt;/em&gt; what each piece represents — no token dictionary needed. If it sees &lt;code&gt;06&lt;/code&gt; in your format string, it knows you want the two-digit year. If it sees &lt;code&gt;2006&lt;/code&gt;, it knows you want the four-digit year. If it sees &lt;code&gt;15&lt;/code&gt;, it knows you want 24-hour time (because the reference hour in 24h format is 15:04).&lt;/p&gt;

&lt;p&gt;It's genuinely clever once it clicks. But until it clicks, it feels completely unhinged.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Aha Moment, In Practice
&lt;/h2&gt;

&lt;p&gt;Once I got it, formatting timestamps became almost fun. Here's what correct usage looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// Date only&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2006-01-02"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="c"&gt;// → 2025-01-15&lt;/span&gt;

    &lt;span class="c"&gt;// Date and time&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2006-01-02 15:04:05"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="c"&gt;// → 2025-01-15 14:32:05&lt;/span&gt;

    &lt;span class="c"&gt;// More readable&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Mon, 02 Jan 2006"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="c"&gt;// → Wed, 15 Jan 2025&lt;/span&gt;

    &lt;span class="c"&gt;// For my Net-Cat project&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[2006-01-02 15:04:05]"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="c"&gt;// → [2025-01-15 14:32:05]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reference date is always the same: &lt;strong&gt;Mon Jan 2 15:04:05 MST 2006&lt;/strong&gt;. You just rearrange and decorate it however you want your output to look.&lt;/p&gt;

&lt;p&gt;I'd actually recommend keeping that reference date somewhere visible while you're learning Go — a sticky note, a comment at the top of your file, whatever works. You'll need to glance at it more than once.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;Go's time formatting is one of those things that feels bizarre at first and obvious in hindsight. Most languages teach you a set of format codes to memorise (&lt;code&gt;%Y&lt;/code&gt;, &lt;code&gt;%m&lt;/code&gt;, &lt;code&gt;YYYY&lt;/code&gt;, etc.) and trust that you'll look them up when you forget them. Go took a different approach: instead of a codebook, it gave you a single example to reference.&lt;/p&gt;

&lt;p&gt;Once you know the reference date, you don't need to memorise anything. You just ask yourself: &lt;em&gt;"How would I write January 2nd, 2006 in the format I want?"&lt;/em&gt; — and that's your format string.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For beginners, here's the mental shift:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Don't think &lt;em&gt;"what token represents the year?"&lt;/em&gt; — think &lt;em&gt;"what does the year 2006 look like in this format?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It's a small shift, but it changes everything.&lt;/p&gt;

&lt;p&gt;I really wish someone had framed it that way for me on day one instead of letting me spend twenty minutes typing &lt;code&gt;"YYYY"&lt;/code&gt; into a terminal like a confused golden retriever.&lt;/p&gt;

&lt;p&gt;Learn from my suffering. Use the reference date. Format your timestamps.&lt;/p&gt;

&lt;p&gt;And if your output still looks weird — check whether you're using &lt;code&gt;log.Println()&lt;/code&gt;. Trust me on that one.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next up: the actual Net-Cat project, and all the new ways it found to humble me.&lt;/em&gt; 🐹&lt;/p&gt;

</description>
      <category>go</category>
      <category>beginners</category>
      <category>learning</category>
    </item>
    <item>
      <title>Go Beginner Mistake #1: When `log.Println()` Made Me Question `time.Now().Format()`</title>
      <dc:creator>perez odiyo</dc:creator>
      <pubDate>Fri, 05 Jun 2026 16:52:20 +0000</pubDate>
      <link>https://dev.to/perezodiyo/go-beginner-mistake-1-when-logprintln-made-me-question-timenowformat-3ig0</link>
      <guid>https://dev.to/perezodiyo/go-beginner-mistake-1-when-logprintln-made-me-question-timenowformat-3ig0</guid>
      <description>&lt;p&gt;&lt;em&gt;A small bug that taught me to read my tools before blaming my code.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Plan
&lt;/h2&gt;

&lt;p&gt;I was building a &lt;strong&gt;Net-Cat project&lt;/strong&gt; in Go — a simplified version of the classic &lt;code&gt;nc&lt;/code&gt; (netcat) Unix tool. One of the features I wanted was a clean timestamp displayed whenever a client connected or sent a message. Something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[2025-01-15 14:32:05] Alice has joined the chat
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple enough, right? I reached for &lt;code&gt;time.Now().Format()&lt;/code&gt; and felt good about it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2006-01-02 15:04:05"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"["&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"] Alice has joined the chat"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I ran it, looked at the output, and... something was &lt;em&gt;off&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Confusing Output
&lt;/h2&gt;

&lt;p&gt;Instead of the clean line I expected, my terminal was showing this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;2025/01/15 14:32:05 [2025-01-15 14:32:05] Alice has joined the chat
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Two timestamps.&lt;/strong&gt; Right next to each other.&lt;/p&gt;

&lt;p&gt;My first thought? &lt;em&gt;My format string must be broken.&lt;/em&gt; I started Googling &lt;code&gt;time.Now().Format&lt;/code&gt; syntax. I tried different layouts. I rewrote the format string three times. Nothing changed. The double timestamp was still there, mocking me.&lt;/p&gt;

&lt;p&gt;I even briefly wondered if Go had some weird timezone bug. (It did not.)&lt;/p&gt;




&lt;h2&gt;
  
  
  The Culprit: &lt;code&gt;log.Println()&lt;/code&gt; vs &lt;code&gt;fmt.Println()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Here's what I didn't know at the time:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;log.Println()&lt;/code&gt; and &lt;code&gt;fmt.Println()&lt;/code&gt; are NOT the same thing.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fmt.Println()&lt;/code&gt; is simple. It prints exactly what you give it, adds a newline, and calls it a day.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, world!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;// Output: Hello, world!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;log.Println()&lt;/code&gt; is different. It's part of Go's &lt;code&gt;log&lt;/code&gt; package, which is designed for &lt;strong&gt;application logging&lt;/strong&gt; — the kind where you always want to know &lt;em&gt;when&lt;/em&gt; something happened. So by default, &lt;code&gt;log&lt;/code&gt; automatically prepends every message with the current date and time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, world!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;// Output: 2025/01/15 14:32:05 Hello, world!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See that prefix? You didn't ask for it. It's just... there. Always. That's the &lt;code&gt;log&lt;/code&gt; package doing its job.&lt;/p&gt;

&lt;p&gt;So when I wrote:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2006-01-02 15:04:05"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"["&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"] Alice has joined the chat"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;log&lt;/code&gt; package saw my message, slapped its own timestamp at the front, and printed both. My code was working perfectly — I just didn't understand the tool I was using.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Does &lt;code&gt;log&lt;/code&gt; Do This?
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;log&lt;/code&gt; package in Go is built for one specific purpose: &lt;strong&gt;structured application logging&lt;/strong&gt;. When you're debugging a server that's been running for days, or tracing a crash in production, the absolute first thing you need to know is &lt;em&gt;when&lt;/em&gt; something happened.&lt;/p&gt;

&lt;p&gt;So the designers of the &lt;code&gt;log&lt;/code&gt; package made that the default. Every log entry gets a timestamp. You don't have to ask for it.&lt;/p&gt;

&lt;p&gt;You can actually control this behaviour with &lt;code&gt;log.SetFlags()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Remove the automatic timestamp entirely&lt;/span&gt;
&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetFlags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"No timestamp here!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;// Output: No timestamp here!&lt;/span&gt;

&lt;span class="c"&gt;// Or keep just the time, not the date&lt;/span&gt;
&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetFlags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ltime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Just the time"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;// Output: 14:32:05 Just the time&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The default flag value is &lt;code&gt;log.LstdFlags&lt;/code&gt;, which equals &lt;code&gt;log.Ldate | log.Ltime&lt;/code&gt; — both date and time. That's the source of my double timestamp.&lt;/p&gt;




&lt;h2&gt;
  
  
  How I Finally Figured It Out
&lt;/h2&gt;

&lt;p&gt;After enough head-scratching, I stopped trying to fix my &lt;code&gt;time.Now().Format()&lt;/code&gt; code and started asking a different question: &lt;em&gt;"Where is this first timestamp actually coming from?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I removed my custom timestamp entirely and just logged a plain string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Alice has joined the chat"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;// Output: 2025/01/15 14:32:05 Alice has joined the chat&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There it was. The timestamp wasn't coming from my code at all. I opened the Go docs for the &lt;code&gt;log&lt;/code&gt; package for the first time, and the very first line told me everything:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Package log implements a simple logging package. Each logging operation makes a single call to the Writer's Write method. A Logger can be used simultaneously from multiple goroutines; it guarantees serialized access to the Writer. The default logger writes to standard error and prints the date and time of each logged message."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Date and time of each logged message.&lt;/strong&gt; Right there in the first paragraph. I just hadn't read it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Fix
&lt;/h2&gt;

&lt;p&gt;For my Net-Cat project, I had two clean options:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 1:&lt;/strong&gt; Switch to &lt;code&gt;fmt.Println()&lt;/code&gt; and keep full control of formatting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2006-01-02 15:04:05"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"["&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"] Alice has joined the chat"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;// Output: [2025-01-15 14:32:05] Alice has joined the chat&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Option 2:&lt;/strong&gt; Keep &lt;code&gt;log.Println()&lt;/code&gt; but disable its automatic prefix.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetFlags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// Call this once at the start of your program&lt;/span&gt;
&lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2006-01-02 15:04:05"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"["&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"] Alice has joined the chat"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;// Output: [2025-01-15 14:32:05] Alice has joined the chat&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I went with Option 1. &lt;code&gt;fmt&lt;/code&gt; was the right tool for user-facing chat messages; &lt;code&gt;log&lt;/code&gt; is better suited for actual application diagnostics.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Lesson
&lt;/h2&gt;

&lt;p&gt;The bug was never in my &lt;code&gt;time.Now().Format()&lt;/code&gt; code. It was in my assumption that &lt;code&gt;log.Println()&lt;/code&gt; behaved like &lt;code&gt;fmt.Println()&lt;/code&gt;. They share a similar name and do similar things on the surface, but they're built for completely different jobs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The takeaway for new Go developers:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;When something isn't working, before you rewrite your logic — make sure you understand every tool you're using.&lt;/strong&gt; A quick trip to the official Go docs (&lt;a href="https://pkg.go.dev" rel="noopener noreferrer"&gt;pkg.go.dev&lt;/a&gt;) can save you an hour of chasing the wrong bug.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Use &lt;code&gt;fmt&lt;/code&gt; when you're talking &lt;strong&gt;to the user&lt;/strong&gt;.&lt;br&gt;
Use &lt;code&gt;log&lt;/code&gt; when you're talking &lt;strong&gt;to yourself&lt;/strong&gt; (or your future debugging self).&lt;/p&gt;

&lt;p&gt;And when output looks weird? Don't assume your code is wrong. Ask where &lt;em&gt;every part&lt;/em&gt; of that output is coming from.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Happy coding — and may your timestamps never double up again.&lt;/em&gt; 🕐&lt;/p&gt;

</description>
      <category>go</category>
      <category>beginners</category>
      <category>debugging</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
