git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: :format:%s for date fields seems to be shifted by timezone

From
clime <clime7@gmail.com>
Date
May 6, 2020, 18:03 UTC
Message-ID
<CAGqZTUs+xCPjQdeQVfU6EWARmZdjcgcHeSNxkKaTf316rX+8pg@mail.gmail.com>
In-Reply-To
<20200504154343.GA12842@coredump.intra.peff.net>
On Mon, 4 May 2020 at 17:43, Jeff King <peff@peff.net> wrote:
Show 65 quoted lines
>
> On Sun, May 03, 2020 at 12:15:14PM +0200, clime wrote:
>
> > my current timezone is UTC+0200.
> >
> > I create a test repo, add one commit and create a tag:
> >
> > Now:
> >
> > $  git for-each-ref --format="%(taggerdate:format:%s)" refs/tags
> > 1588504146
> >
> > $ date +"%s"
> > 1588500585
> >
> > $  git for-each-ref --format="%(taggerdate:raw)" refs/tags
> > 1588500546 +0200
> >
> > Somehow %(taggerdate:format:%s) gives a Unix timestamp which is one
> > hour in future and it is different than what ` date +"%s"` gives
> > around approximately the same time the tag was created.
>
> It's caused by strftime() being clever with DST. Try this:
>
>   git commit --date=@1559361600 --allow-empty -m summer
>   git commit --date=@1577854800 --allow-empty -m winter
>   git log --format=%ad --date=unix >unix
>   git log --format=%ad --date=format:%s >strftime
>   diff -u unix strftime
>
> We get the winter time right, but the summer time wrong.
>
> The issue is that strftime() takes a broken-down "struct tm", not a unix
> time_t. We have all of the right values for hour/minute/etc there, so
> using "format:%H:%M:%S" prints what you'd expect. But we never set the
> "isdst" field, so when it tries to convert back to unix time, it applies
> a one-hour offset (if it's "summer" in your local timezone).
>
> Unfortunately I don't think we can solve this easily. If we were
> operating completely in your local timezone, then we would have gotten
> that "struct tm" from localtime(), and its isdst field would be set
> properly. And indeed, if you use "--date=format-local:%s", the problem
> goes away.
>
> But when we're formatting in the original author's timezone, which is
> the default, we have no idea if they were in dst then or not. We only
> know their offset-to-gmt, so we munge the time_t ourselves and use
> gmtime().
>
> So there are a few reasons I think this is the best we can do:
>
>  - the full timezone information literally isn't there in Git; we might
>    know the author was in +0200, but we don't know if they were
>    observing DST, or if they were simply in a timezone further east.
>
>  - even if we had a zone, there's no system function to convert a time_t
>    to a tm in an arbitrary timezone (hence the gmtime() hack above;
>    we've tried playing games with $TZ and tzset(), but it's awkward and
>    unportable)
>
>  - likewise, strftime() is doing the reverse conversion using the local
>    timezone anyway, which would be wrong.
>
> So my advice is not to use "%s" (which isn't portable anyway). Use
> "--date=unix" or "%(taggerdate:unix)".
Hello Jeff,

what about just printing the raw timestamp from either commit or tag, i.e. avoiding any conversion for format:%s?

Best regards! clime

>
> -Peff
Previous: Jeff KingNext: Jeff King
Message 3 of 4 in “:format:%s for date fields seems to be shifted by timezone”
  1. climeMay 3, 2020
  2. Jeff KingMay 4, 2020
  3. climeMay 6, 2020
  4. Jeff KingMay 6, 2020

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.