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?

3 Answers 3

4

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

- after the % symbol removes zero padding.

[1] Relevant answer

1
  • -400 hours? ;-) Commented Mar 28, 2018 at 17:58
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.

2
  • bc... that's a new one for me. Commented Mar 28, 2018 at 18:13
  • @datUser Just a standard calculator. Takes expressions on standard input and produces result on standard output. Commented Mar 28, 2018 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) }' 
4
  • 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()). Commented Mar 29, 2018 at 12:58
  • @StéphaneChazelas Yes, it is a GNU extension. Are you implying that a GNU date answer is invalid? Commented Mar 29, 2018 at 19:21
  • Not at all, it was a "Note" as additional information. I was the one giving you that upvote. Commented Mar 29, 2018 at 19:44
  • @StéphaneChazelas Simpler, older and POSIX compliant solutions added. Commented Mar 29, 2018 at 20:35

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.