# Convert timezone offset to integer

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"
``````

Output

``````-0400
-256
``````

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

``````-0400
-4
``````

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
2.75

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

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.

• `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.

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

``````\$ date +%-:::z
-4
``````

Otherwise (assume -0427):

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

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

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

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) }'
``````
• 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