How to perform date operations in bash - bash

Basically, I want to take a time, and day of the week, in UTC+8, and adjust the datetime object to a given UTC offset, within bash, I don't have any code to show because I'm not sure how to start attempting this in the first place honestly
(I'm writing a custom script for a friend who lives in UTC+8 and want to make the input as easy as possible for them, basically they just give it a time in their timezone, and a day of the week, and it'll tell them what date and time that'll be in a different timezone, for an overarching purpose)

For a reference, look at the section 1 of the manual page for "date":
In your shell, just type: man 1 date
or see the online man page:
https://man7.org/linux/man-pages/man1/date.1.html
One way is to parse the date into the number of seconds since epoch (since 1970), and then convert that number of seconds into the format you want:
For example:
$ date +%s --date='2022-12-27 11:30:17 +008'
1672140137
$ date +%c --date='#1672140137'
Tue 27 Dec 2022 06:22:17 AM EST
or you could also convert to ISO format then back to local time
$ date -Iseconds --date='TZ="GMT" 2022-12-22 11:33:44 +08'
2022-12-21T22:33:44-05:00
$ date --date='2022-12-21T22:33:44-05:00'
Wed 21 Dec 2022 10:33:44 PM EST
I hope this helps you get started with some ideas for converting to/from different timezones.
Also, to help with user input, you can show the current month calendar using cal
$ cal
December 2022
Su Mo Tu We Th Fr Sa
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
$ date --date='Fri 08:30'
Fri 30 Dec 2022 08:30:00 AM EST
In the above example, I specified "Fri 08:30" which gets set to the next Friday at 08:30 in the morning for my local timezone.

Related

bash variable doubles in value - why?

I have a simple shell script set up to capture images every X seconds. For some reason the value of X seems to double each time through the loop.
#!/bin/bash
# basic setup for time-lapse
SECONDS=1
while true
do
DATE=$(date +"%Y-%m-%d_%H%M%S")
filename=${DATE}_img.jpg
# fswebcam -r 1280x720 --timestamp "%a %Y-%b-%d %H:%M (%Z)" /home/pi/JPGS/$filename
date
echo "pausing for ${SECONDS} seconds"
sleep $SECONDS
date
echo "====="
done
This is the output I get. The value of SECONDS is not manipulated inside the loop, so I'm confused with what is happening here. Also, the original interval was 30 seconds, I changed it to 1 seconds for testing purposes, and the date calls are for testing/debugging too.
Sun Mar 3 17:51:57 CST 2019
pausing for 1 seconds
Sun Mar 3 17:51:58 CST 2019
=====
Sun Mar 3 17:51:58 CST 2019
pausing for 2 seconds
Sun Mar 3 17:52:00 CST 2019
=====
Sun Mar 3 17:52:00 CST 2019
pausing for 4 seconds
Sun Mar 3 17:52:04 CST 2019
=====
Sun Mar 3 17:52:04 CST 2019
pausing for 8 seconds
Sun Mar 3 17:52:12 CST 2019
=====
Sun Mar 3 17:52:12 CST 2019
pausing for 16 seconds
Sun Mar 3 17:52:28 CST 2019
=====
Sun Mar 3 17:52:28 CST 2019
pausing for 32 seconds
Sun Mar 3 17:53:00 CST 2019
=====
Sun Mar 3 17:53:00 CST 2019
pausing for 64 seconds
Sun Mar 3 17:54:04 CST 2019
=====
Sun Mar 3 17:54:04 CST 2019
pausing for 128 seconds
What am I missing here?
This is under a Raspberry Pi
Pick a different name for $SECONDS.
$SECONDS is a built-in shell variable. It expands to the number of seconds since the shell was started.
From the Bash manual:
'SECONDS'
This variable expands to the number of seconds since the shell was
started. Assignment to this variable resets the count to the value
assigned, and the expanded value becomes the value assigned plus the
number of seconds since the assignment.
$SECONDS is actually a special Bash Variable for timing the number of seconds a script has been running. Because it's a timer, it increments automatically every second without the script doing anything. Just change the variable name to something else and you should be fine.

Display Previous Months in Shell

I have extracted the current month using
currentMonth=`date +"%b"`
I want to get all previous five months in a file. Suppose its October now, i want Sep, Aug, Jul, Jun, May in a file. I tried using multiple utilities like cal, ncal, date but could not achieve this.
I want the months in the file as
Sep
Aug
Jul
Jun
May
Any help or suggestion is greatly appreciated.
Simple bash/shell solution (for Unix):
for i in 1 2 3 4 5; do date -d" - $i month" +%b; done
The output:
Sep
Aug
Jul
Jun
May
For MacOS:
for i in {1..5}; do date -v-"$i"m +%b; done

Ruby unix date incorrect

I have the following Unix timestamp: 1478698378000
And I'm trying to show this as a datetime in Ruby, e.g.
<%= Time.at(#timestamp).to_datetime %>
Which should be returning a date of: Wed, 09 Nov 2016 13:32:58 GMT but the above code actually returns a date of: 48828-02-01T13:26:40+00:00 Ignore formatting!
As you can see it thinks that timestamp is 2nd Feb 48828 13:26:40.
Why is the datetime coming out completely incorrect and the year so far into the future like that? Checking the timestamp on http://www.epochconverter.com/ reveals the timestamp to be correct, so it's Ruby that's returning it incorrectly.
Time.at expects seconds as an argument and your timestamp is an amount of milliseconds. See documentation on Time.at
Why won’t you check the unix timestamp correctness against “Fashion Week Magazine” or “Cosmopolitan” Site?
Unix timestamp is an amount of seconds lasted since 1970-01-01 UTC:
date --date='#1478698378000'
mar feb 1 14:26:40 CET 48828
BTW, dropping last three zeroes gives you back what you’ve expected:
date --date='#1478698378'
mié nov 9 14:32:58 CET 2016

12 hrs to 24 hrs converter shell script

I want the date format Thu Nov 3 17:21:08 2016 to be converted to Thursday, 3 November 2016 7:48:24 PM AEDT .
Actually, i want to achieve in converting the 12hrs time to 24hrs format using a shell script .
Thanks
I believe below command would help you to go ahead:
date +"%T"

Detect daylight saving time in bash

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.
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!
Perl to the rescue:
if perl -e 'exit ((localtime)[8])' ; then
echo winter
else
echo summer
fi
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).
for info :
zdump -v Europe/Paris | grep 2020
gives this :
Europe/Paris Sun Mar 29 00:59:59 2020 UT = Sun Mar 29 01:59:59 2020 CET isdst=0 gmtoff=3600
Europe/Paris Sun Mar 29 01:00:00 2020 UT = Sun Mar 29 03:00:00 2020 CEST isdst=1 gmtoff=7200
Europe/Paris Sun Oct 25 00:59:59 2020 UT = Sun Oct 25 02:59:59 2020 CEST isdst=1 gmtoff=7200
Europe/Paris Sun Oct 25 01:00:00 2020 UT = Sun Oct 25 02:00:00 2020 CET isdst=0 gmtoff=3600

Resources