Search code examples
macosepochiso8601bsddarwin

OSX fails to convert ISO8601 to epoch


I'm getting settled on mac os and some of my scripts are not working after linux. One script in particular is very interesting.

So i'm trying to convert ISO8601 date to unix epoch. OSX native way to do it seems to be

$ date -j -f "%FT%TZ" "2015-09-09T13:19:09Z"
Wed  9 Sep 2015 13:19:09 NZST

$ date -j -f "%FT%TZ" "2015-09-09T13:19:09Z"  +%s
1441761549

Looks fine except it's wrong answer. It's exactly 12 hours behind real answer and my timezone +12 so how cloud timezone influence unix epoch ?

And just verifying myself

$ docker run -it --rm trusty date -d"2015-09-09T13:19:09Z" +%s
1441804749

same tools on linux giving correct answer ...

I just want to understand what is wrong here - am i missing something or is it just a broken thing ?

OSX Yosemite 10.10.4

UPD: Just some extra details - i'd suggest it's a difference between date util, except it's not only date.

Stass-MacBook:~ void$ python -c 'import dateutil.parser; print dateutil.parser.parse("2015-09-09T13:19:09Z").strftime("%s")'
1441761549

Stass-MacBook:~ void$ docker run trusty python -c 'import dateutil.parser; print dateutil.parser.parse("2015-09-09T13:19:09Z").strftime("%s")'
1441804749

Solution

  • The short answer is that the output you’re getting is the expected and correct output when you run the macOS/BSD date utility with those arguments. Because it’s different from GNU date.

    To get similar output from GNU date, you’d need to add the --utc option, and run it like so:

    echo $(date --utc -d '2015-09-09T13:19:09Z' +"%a %-d %b %Y %H:%M:%S") $(date +%Z)
    

    If your timezone is set to NZST, then the above will emit this:

    Wed 9 Sep 2015 13:19:09 NZST
    

    That invocation is what you can imagine BSD date doing when run as date -j -f "%FT%TZ" "2015-09-09T13:19:09Z". For one thing, even though you’re saying, put this date/time into the default format (and not change it otherwise), it’s also tossing a timezone in there anyway.

    Another way to think of what it’s doing is: by default BSD date is operating as if you’ve given an equivalent of the --utc option—that is, essentially the opposite of the GNU date default.

    In other words, an important difference with BSD date -j -f is that it really just means: take this string in this other date format and just put it into the default date format that we use here— without considering the local timezone at all.

    same tools on linux giving correct answer ...

    macOS/BSD date and GNU/Linux date aren’t the same tools. They just have the same name.


    As far as getting date in your scripts to behave the same across platforms, you can get GNU date by using homebrew to install the coreutils package:

    brew install coreutils
    

    That will make the GNU version available on your OS X system under the name gdate. So you could then replace date in your scripts with $DATECMD (or something), and then:

    • in your OS X environment, set DATECMD=gdate
    • in your Linux environment, set DATECMD=date

    Of course you could instead just do alias date=gdate but that’s not recommended, because you may sometimes want to run 3rd-party tools that do expect BSD date in your environment.