I am doing some timezone calculations in bash. I'm getting some unexpected values when converting the timezone offset hour output to an integer to do some additional calculations.

Partial script:

offset=$(date +%z)
echo "$offset"
hours=$(( offset ))
echo "$hours"



Desired Output (I accidentally omitted the need to divide by 100 for the final output)


I think that the arithmetic is getting evaluated as octal. How can I evaluate the output from date +%z as decimal?


Using sed and bc:

date +%z | sed -E 's/^([+-])(..)(..)/scale=2;0\1(\2 + \3\/60)/' | bc

This will give you 2.00 back in the timezone I'm in (+0200).

With strange/unusual timezones:

$ echo '+0245' | sed -E 's/^([+-])(..)(..)/scale=2;0\1(\2 + \3\/60)/' | bc

$ echo '-0245' | sed -E 's/^([+-])(..)(..)/scale=2;0\1(\2 + \3\/60)/' | bc

The sed expression will turn the timezone into a "bc script". For the timezone +HHMM, the script will be

scale=2;0+(HH + MM/60)

For -HHMM it will be

scale=2;0-(HH + MM/60)

The zero is in there because my bc does not understand unary +.

If you only ever going to deal with full hour timezones, then you may use

date +%z | sed -E 's/^([+-])(..)../0\1\2/' | bc

which will deal you integers.

| improve this answer | |
  • bc... that's a new one for me. – 111--- Mar 28 '18 at 18:13
  • @datUser Just a standard calculator. Takes expressions on standard input and produces result on standard output. – Kusalananda Mar 28 '18 at 18:17

offset=$(date +%-z) would give an output of -400 in your case.

- after the % symbol removes zero padding.

[1] Relevant answer

| improve this answer | |

If the timezone is a whole number of hours (GNU date):

$ date +%-:::z

Otherwise (assume -0427):

$ date +%-:::z | awk -F: '{x=$1;printf("%s%.2f\n",x>=0?"+":"-",(x>=0?x:-x)+$2/60)}'

Or, for older, more limited date implementations, us plain:

$ date +%z | awk -F '' '{printf("%s%.2f\n",$1,$2$3+($4$5)/60)}'

This is still not POSIX because a null FS is undefined for POSIX awk.

For POSIX we need to split characters with sed:

$ date +%z |\
sed -E 's/(.)(..)(..)/\1 \2 \3/' |\
awk '{ printf("%s%.2f\n",$1,$2+$3/60) }'
| improve this answer | |
  • Note that %:::z is specific to GNU date (from gnulib's fprintftime), it's not even in the GNU libc's strftime() (contrary to %-z which is also not standard but supported by GNU strftime()). – Stéphane Chazelas Mar 29 '18 at 12:58
  • @StéphaneChazelas Yes, it is a GNU extension. Are you implying that a GNU date answer is invalid? – Isaac Mar 29 '18 at 19:21
  • Not at all, it was a "Note" as additional information. I was the one giving you that upvote. – Stéphane Chazelas Mar 29 '18 at 19:44
  • @StéphaneChazelas Simpler, older and POSIX compliant solutions added. – Isaac Mar 29 '18 at 20:35

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.