ccpizza
ccpizza

Reputation: 31666

Unexpected output parsing seconds with macos ootb /bin/date

Formatting a time interval in seconds as minutes:seconds using MacOS ootb /bin/date works as expected using the "+%M:%S" format:

# convert 200 seconds to 03:20
date -j -f "%s" 200  "+%M:%S"
# OUTPUT: 03:20

# convert 3595 seconds to 59:55
date -j -f "%s" 3595  "+%M:%S"
# OUTPUT: 59:55

However when the parsed value is more than one hour (3600+ seconds) the format string "+%H:%M:%S" (and the equivalent "+%T") appears to have an off-by-one error:

date -j -f "%s" 3600  "+%H:%M:%S"
# ACTUAL OUTPUT: 02:00:00
# EXPECTED OUTPUT: 01:00:00

The manpage for date mentions that Parsing is done using strptime(3) which in turn points to strftime which says:

%s is replaced by the number of seconds since the Epoch, UTC (see mktime(3)).

According to the above I would expect 3600 to be parsed and formatted as 01:00:00 and NOT as 02:00:00.

Is there something wrong with the arguments I am passing or is this an implementation bug?

Upvotes: 0

Views: 68

Answers (1)

Gordon Davisson
Gordon Davisson

Reputation: 125718

The basic problem is that date doesn't deal with time intervals, it deals with absolute time+dates. When you use date -j -f "%s" 200, it doesn't interpret the "200" as meaning an interval of 200 seconds, it means 200 seconds after midnight, January 1 1970, UTC. So if I run that on my Mac, I get this:

$ date -j -f "%s" 200
Wed Dec 31 16:03:20 PST 1969

...because I'm in the US Pacific time zone. I'm currently on Pacific Daylight time, but at 200 seconds after midnight, January 1 1970, UTC, this area would've been on Pacific Standard time, so it uses that to display the time & date.

You're seeing essentially the same thing, but since your area is one hour ahead of UTC (or was on January 1, 1970), you get an hour added instead of 8 subtracted. You don't notice this unless you display the hours, but it'll happen even if the time "interval" is less than 3600:

$ date -j -f "%s" 200 "+%H:%M:%S"
16:03:20

(In your time zone, you'll presumably see "01:03:20".) You can get even weirder results in a time zone with a non-hour offset:

$ TZ=Canada/Newfoundland date -j -f "%s" 200  "+%H:%M:%S"
20:33:20

You can mostly work around this by telling date to output in UTC, either with -u or TZ=UTC:

$ date -ju -f "%s" 3600  "+%H:%M:%S"
01:00:00
$ TZ=UTC date -j -f "%s" 3600  "+%H:%M:%S"
01:00:00

But at least in my opinion, this is still just a hack; the fundamental problem is that you're mixing up intervals with absolute times, and I'm not convinced this won't cause other problems as well.

Upvotes: 2

Related Questions