Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect daylight saving time in bash

Tags:

date

bash

dst

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.

like image 323
jhutar Avatar asked Nov 11 '13 08:11

jhutar


People also ask

How do I check my DST time?

Test transition of DST, i.e. when you are currently in summer time, select a time value from winter. Test boundary cases, such as a timezone that is UTC+12, with DST, making the local time UTC+13 in summer and even places that are UTC+13 in winter.

How does Linux handle Daylight Savings time?

On Linux, the hardware clock that keeps the system time when the computer is shut down can be set in either local time or in UTC time. If you have it in UTC time, nothing needs to be done to it when DST begins or ends.

Does Unix time account for daylight savings?

This still does not account for daylight savings!


3 Answers

Perl to the rescue:

if perl -e 'exit ((localtime)[8])' ; then
    echo winter
else
    echo summer
fi
like image 178
choroba Avatar answered Oct 21 '22 18:10

choroba


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!

like image 32
UlfR Avatar answered Oct 21 '22 17:10

UlfR


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).

like image 10
Toby Speight Avatar answered Oct 21 '22 17:10

Toby Speight