Detect daylight saving time in bash

2019-04-19 20:20发布

问题:

I want to detect if I'm in winter or summer time. My current approach is:

if date +%Z | grep -e CET -e EST; then
  # I'm in winter time
else
  # I'm in summer time
fi

which have obvious drawback as you have to know all the timezone names.

回答1:

Perl to the rescue:

if perl -e 'exit ((localtime)[8])' ; then
    echo winter
else
    echo summer
fi


回答2:

I don't now if this exactly answers your question, but it gives you some tools to help you better understand and test whats going on.

You can use date and environment-var TZ to help you.

So for example I live in Sweden so my timezone location is Europe/Stockholm. So in the winter date +%Z reports CET and in the summer CEST. The nice thing is that you could specify timezone for the environment of a specific command, then you could specify what date the date command should present. So by summing up this you could do any of the following:

TZ=Europe/Stockholm date +%Z # CET or CEST depending of when its run
TZ=Europe/Stockholm date --date=20170101 +%Z # CET
TZ=Europe/Stockholm date --date=20170601 +%Z # CEST
TZ=CET date --date=20170101 +%Z # CET
TZ=CET date --date=20170601 +%Z # CEST, note that its auto adjusted to CEST

If you instead want the time difference to UTC you could use lowercase-z:

TZ=Europe/Stockholm date +%z # +0100 or +0200 depending of when its run
TZ=Europe/Stockholm date --date=20170101 +%z # +0100
TZ=Europe/Stockholm date --date=20170601 +%z # +0200
TZ=CET date --date=20170101 +%z # +0100
TZ=CET date --date=20170601 +%z # +0200

NOTE: You can not use TZ=CEST or TZ=ULFR since that is not a valid TZ:

TZ=CEST date --date=20170101 +%z # +0000
TZ=ULFR date --date=20170101 +%z # +0000

crontab example:

We run our servers on UTC but some of the jobs run by crontab needs to be run at a specified wallclock (CET/CEST) time. So since we want the jobs to be run one hour later in the winter (the clock is put one hour forward in the summer witch makes it reach a specified UTC-time one hour earlier in the summer than in the winter) we do sleep before the actual job is executed in the winter.

We want the job /whatever/bin/foobar to be run at 04:15 wallclock time every day. But since cron runs on UTC the job needs to be set one hour earlier for CET and two hours earlier for CEST. That would be the same as always running the command two hours earlier but sleeping for an hour during winter-time. Ex crontab row:

15 2 * * * [ `TZ=CET date +\%Z` = CET ] && sleep 3600; /whatever/bin/foobar

If you have a nicer solution to this issue, then please feel free to advice me!



回答3:

In the northern hemisphere, in regions with daylight savings, then it's active when the offset is greater than the offset is in January. In southern hemisphere time zones, daylight savings is active when the offset is greater than that in July.

You can discover the offsets in January and July, as well as now:

OFF_1=$(date -d '1 Jan' +%z)
OFF_7=$(date -d '1 Jul' +%z)
OFF_NOW=$(date +%z)

If your zone doesn't have daylight savings, all three will be the same (this year). In any case, we can make two comparisons, one for the northern hemisphere and one for the southern; if the current offset is greater than either one of those, then the current zone is in daylight savings time:

if  test $OFF_NOW -gt $OFF_1  ||  test $OFF_NOW -gt $OFF_7
then
  # I'm in summer time
else
  # I'm in winter time
fi

The assumption here is that all regions that observe daylight savings have their transition somewhere between July and January. That's true in all zones, as far as I know. The only case where this might fail is in a year where the winter offset changes (such 1940 in the UK, when the subsequent winter was on GMT+1).



标签: bash date dst