1

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?

Jeff Schaller
  • 66,199
  • 35
  • 114
  • 250
111---
  • 4,424
  • 3
  • 27
  • 50

3 Answers3

4

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

- after the % symbol removes zero padding.

[1] Relevant answer

NOLFXceptMe
  • 494
  • 3
  • 6
1

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.

Kusalananda
  • 320,670
  • 36
  • 633
  • 936
  • `bc`... that's a new one for me. – 111--- Mar 28 '18 at 18:13
  • @datUser Just [a standard calculator](http://pubs.opengroup.org/onlinepubs/9699919799.2016edition/utilities/bc.html). Takes expressions on standard input and produces result on standard output. – Kusalananda Mar 28 '18 at 18:17
1

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? –  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. –  Mar 29 '18 at 20:35