BSD's date -j -f seems to mix seconds and minutes from the current time of the day while still accepting '%H%p' in the time format. All I want to do is convert input format to correct unix time. Also, changing %Z's value to anything other than system's timezone gives an error.

❯ /bin/date -j -f '%H%p %Z' '11PM PDT' '+%s'; gdate -d '11PM' '+%s'
# Run again
❯ /bin/date -j -f '%H%p %Z' '11PM PDT' '+%s'; gdate -d '11PM' '+%s'

What do I want?

  1. Not make the minutes/seconds of the time I run the command affect the result
  2. Make any timezone work for %Z

I am ok with another POSIX compliant way to get this done if it is unnecessarily difficult with date.

I am using zsh, so a zsh solution could also work, if any. strftime -r seems promising, but produces negative values.

2 Answers 2


You should be able to specify :%M:%S as part of the format string and specify :00:00 as the time

% /bin/date -j -f '%H:%M:%S%p %Z' '11:00:00PM GMT'
Wed May 25 19:00:00 EDT 2022

The manpage for FreeBSD's date command says Parsing is done using strptime(3) and that manpage says

 The %Z format specifier only accepts time zone abbreviations of the local
 time zone, or the value "GMT".  This limitation is because of ambiguity
 due to of the over loading of time zone abbreviations.  One such example
 is EST which is both Eastern Standard Time and Eastern Australia Summer

So date can not be used to do time zone conversions like this.

You could, instead, calculate the GMT offset and use that, with %z.


% /bin/date -j -f '%H:%M:%S%p %z' "11:00:00PM $(TZ=America/Los_Angeles date +%z)"
Thu May 26 02:00:00 EDT 2022

And, correctly, 11pm tonight in Los Angeles (currently PDT) is 2am the next day in New York.


Since you're tagging with zsh, note that zsh has builtin time parsing and formatting with its strftime builtin in the zsh/datetime module which is a raw interface to the standard strftime() (+ localtime()) and strptime() (+ mktime()) standard functions (with extension to support subseconds).

So here, you can do portably (on BSD, GNU or any system with neither GNU nor BSD date):

zmodload zsh/datetime
TZ=America/Los_Angeles strftime -s today %Y-%m-%d
TZ=America/Los_Angeles strftime -r "%Y-%m-%d %I%p" "$today 11PM"

Which today 2022-05-26 my time, but still 2022-05-25 Los Angeles time gives 1653544800 (2022-05-26T06:00:00+00:00).

Note that %H is the hour of the day in 24-hour format. You need %I if using 12 hour format with %p.

You also need to specify the date, otherwise it defaults to 1900-01-01 (0 value in the tm_year and other date-related fields of the struct tm returned by strptime()), hence your negative number.

Also beware that %p is locale-dependant. You may want to set the locale to C to make sure PM is always recognised.

Assuming that by CST you mean US central standard (or summer?) time (and not China time or Australian central time), you'd replace America/Los_Angeles with for instance America/Regina or whatever zone is relevant to you or TZ=CST6 to hardcode a time zone labelled CST that is always 6 hours West of UTC and use that regardless of the time of the year (Winter / Summer).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.