I need to report a time in seconds since 1st January 1900. I have the number of seconds since the start of the Unix epoch.
Can anybody point me to a definitive reference to the number of seconds between 1/1/1900 and 1/1/1970?
According to the Time protocol in RFC 868 it is 2208988800L.
The Time
The time is the number of seconds since 00:00 (midnight) 1 January 1900
GMT, such that the time 1 is 12:00:01 am on 1 January 1900 GMT; this
base will serve until the year 2036.
For example:
the time 2,208,988,800 corresponds to 00:00 1 Jan 1970 GMT,
2,398,291,200 corresponds to 00:00 1 Jan 1976 GMT,
2,524,521,600 corresponds to 00:00 1 Jan 1980 GMT,
2,629,584,000 corresponds to 00:00 1 May 1983 GMT,
and -1,297,728,000 corresponds to 00:00 17 Nov 1858 GMT.
70 years = 2,208,988,800 seconds, 01-01-1900 00:00 to 01:01-1970 00:00
Related
exp_date=Thu Sep 9 14:06:38 UTC 2021 reduce 30 days from exp_date in shell script
I know from current date I can use this date --date "30 days ago" But when I try it from a date variable to do the same its not working
Use date to get your date in epoch seconds.
Subtract 30 days of seconds.
Convert the epoch seconds to ... whatever you need:
root#pi:~# date
Sun 19 Sep 2021 04:07:01 PM CDT
root#pi:~# date -d #$(( $(date -d 'Wed Nov 13 14:06:38 UTC 1954' +%s) - 30*86400 ))
Thu 14 Oct 1954 08:06:38 AM CST
I wanted to construct a spring cron expression that executes At 23:00:00pm, on first Sunday, every 2 months starting in January, so far I have this
0 0 23 ? 1/2 SUN but this one executes At 23:00:00pm, every Sunday, every 2 months starting in January. how can I make it execute only the first Sunday every two months?
0 0 23 ? 1/2 SUN next excution dates are as follows
Sun Mar 07 23:00:00 UTC 2021
Sun Mar 14 23:00:00 UTC 2021
Sun Mar 21 23:00:00 UTC 2021
Sun Mar 28 23:00:00 UTC 2021
Sun May 02 23:00:00 UTC 2021
Sun May 09 23:00:00 UTC 2021
Sun May 16 23:00:00 UTC 2021
Sun May 23 23:00:00 UTC 2021
Sun May 30 23:00:00 UTC 2021
Sun Jul 04 23:00:00 UTC 2021
but what I wanted was
Sun Mar 07 23:00:00 UTC 2021
Sun May 02 23:00:00 UTC 2021
Sun Jul 04 23:00:00 UTC 2021
how can I improve my expression to get the above result?
0 0 23 1-7 1/2 SUN
The only part you are missing, is day number in the range 1-7.
Code to verify the schedule:
var sundays = CronExpression.parse("0 0 23 1-7 1/2 SUN");
var nextDate = LocalDateTime.now();
var dateFormatter = DateTimeFormatter.ofPattern("EEE, MMM d, yyyy 'at' hh:mm:ss a");
for (var i = 0; i < 10; i++) {
nextDate = sundays.next(nextDate);
System.out.println(nextDate.format(dateFormatter));
}
Will run at:
Sun, Mar 7, 2021 at 11:00:00 pm
Sun, May 2, 2021 at 11:00:00 pm
Sun, Jul 4, 2021 at 11:00:00 pm
Sun, Sep 5, 2021 at 11:00:00 pm
Sun, Nov 7, 2021 at 11:00:00 pm
...
I have a list of files with the substring YYYYMMDDHH in them (example: 2016112200 means 2016 November 22th at 00 hours). These files are: temp_2016102200.data, temp_2016102212.data, temp_2016102300.data, temp_2016102312.data, ..., temp_20170301.data. And I also have other family of files substituting temp by wind.
For each string YYYYMMDDHH I want to create a tar with the temp and its correspondent wind file. I don't want this process to stop if one or both files are missing.
My idea was to loop from 12 hours to 12 hours, but I am having some problems because to specify the date I did: b=$(date -d '2016111400' +'%Y%m%d%H') but bash informs me that that is not a valid date...
Thanks.
It's not bash telling you the date format is wrong: date is telling you. Not everything you type is a bash command.
As Kamil comments, you have to split it up so that date can parse it. The YYYY-mm-dd HH:MM:SS format is parsable. Using bash parameter expansion to extract the relevant substrings:
$ d=2016111400
$ date -d "${d:0:4}-${d:4:2}-${d:6:2} ${d:8:2}:00:00"
Mon Nov 14 00:00:00 EST 2016
Now, when you want to add 12 hours, you have to be careful to do it in the right place in the datetime string: if you add a + character after the time, it will be parsed as a timezone offset, so put the relative part either first or between the date and the time.
$ date -d "+12 hours ${d:0:4}-${d:4:2}-${d:6:2} ${d:8:2}:00:00"
Mon Nov 14 12:00:00 EST 2016
As a loop, you could do:
d=2016111400
for ((i=1; i<=10; i++)); do
# print this datetime
date -d "${d:0:4}-${d:4:2}-${d:6:2} ${d:8:2}:00:00"
# add 12 hours
d=$( date -d "+12 hours ${d:0:4}-${d:4:2}-${d:6:2} ${d:8:2}:00:00" "+%Y%m%d%H" )
done
outputs:
Mon Nov 14 00:00:00 EST 2016
Mon Nov 14 12:00:00 EST 2016
Tue Nov 15 00:00:00 EST 2016
Tue Nov 15 12:00:00 EST 2016
Wed Nov 16 00:00:00 EST 2016
Wed Nov 16 12:00:00 EST 2016
Thu Nov 17 00:00:00 EST 2016
Thu Nov 17 12:00:00 EST 2016
Fri Nov 18 00:00:00 EST 2016
Fri Nov 18 12:00:00 EST 2016
OK, a "nicer" way to loop
start=2019043000
end=2019050300
plus12hours() {
local d=$1
date -d "+12 hours ${d:0:4}-${d:4:2}-${d:6:2} ${d:8:2}:00:00" "+%Y%m%d%H"
}
for (( d = start; d <= end; d = $(plus12hours "$d") )); do
printf "%d\t%s\n" "$d" "$(date -d "${d:0:4}-${d:4:2}-${d:6:2} ${d:8:2}:00:00")"
done
2019043000 Tue Apr 30 00:00:00 EDT 2019
2019043012 Tue Apr 30 12:00:00 EDT 2019
2019050100 Wed May 1 00:00:00 EDT 2019
2019050112 Wed May 1 12:00:00 EDT 2019
2019050200 Thu May 2 00:00:00 EDT 2019
2019050212 Thu May 2 12:00:00 EDT 2019
2019050300 Fri May 3 00:00:00 EDT 2019
DateTime#parse on 'Mon, 30 Dec 2013 00:00:00 UTC +00:00' is wrong for the week. I chose ISO 8601 week-based year and week number %V (week number 01..53 of the week-based year).
With format "%V-%y":
DateTime.parse('Mon, 30 Dec 2013 00:00:00 UTC +00:00').strftime "%V-%y"
#⇒ "01-13"
DateTime.parse('Mon, 30 Dec 2013 00:00:00 UTC +00:00').strftime "%W-%y"
#⇒ "52-13"
Date.strptime('01-13', '%V-%y')
#⇒ Tue, 01 Jan 2013
Date.strptime('52-13', '%V-%y')
#⇒ Tue, 01 Jan 2013
Mon, 30 Dec 2013 00:00:00 UTC +00:00 is not "01-13".
But if I use "%W" format, the result is correct ("52-13").
What is it? Or did I make some mistakes?
With week-based week number (%V) one should use week-based year (%g):
DateTime.parse('Mon, 30 Dec 2013 00:00:00 UTC +00:00').strftime "%V-%g"
#⇒ "01-14"
The cday, cweek and cyear are the methods based on the commercial dates.
commercial: Creates a date object denoting the given week date.
So, the last days of an year can be the same week to the new year's starting days. For example 2013 december last dates and 2014 Jan starting days are of the same week, so the week number of the date 'Mon, 30 Dec 2013 00:00:00 UTC +00:00' comes to the new week of next year after all the weeks of the year are completed.
So,
"Mon, 30 Dec 2013 00:00:00 UTC +00:00".to_date.cweek ==> 1
"Mon, 30 Dec 2013 00:00:00 UTC +00:00".to_date.cwday ==>1 (1st week day of week 1 2014(but date is still of 2013)
"Mon, 30 Dec 2013 00:00:00 UTC +00:00".to_date.cwyear ==> 2014
Those are commercial dates, Now check,
"Mon, 30 Dec 2013 00:00:00 UTC +00:00".to_date.year ==> 2013
This is Normal year.
This has a perfect example
As we know that each year have the following max day in each month as follows:
Jan - 31 days
Feb - 28 days / 29 days (leap year)
Mar - 31 days
Apr - 30 days
May - 31 days
Jun - 30 days
Jul - 31 days
Aug - 31 days
Sep - 30 days
Oct - 31 days
Nov - 30 days
Dec - 31 days
How to I get bash to return the value (last day of each month) for the current year without using if else or switch or while loop?
my take:
for m in {1..12}; do
date -d "$m/1 + 1 month - 1 day" "+%b - %d days";
done
To explain: for the first iteration when m=1 the -d argument is "1/1 + 1 month - 1 day" and "1/1" is interpreted as Jan 1st. So Jan 1 + 1 month - 1 day is Jan 31. Next iteration "2/1" is Feb 1st, add a month subtract a day to get Feb 28 or 29. And so on.
cat <<EOF
Jan - 31 days
Feb - `date -d "yesterday 3/1" +"%d"` days
Mar - 31 days
Apr - 30 days
May - 31 days
Jun - 30 days
Jul - 31 days
Aug - 31 days
Sep - 30 days
Oct - 31 days
Nov - 30 days
Dec - 31 days
EOF
cal $(date +"%m %Y") |
awk 'NF {DAYS = $NF}; END {print DAYS}'
This uses the standard cal utility to display the specified month, then runs a simple Awk script to pull out just the last day's number.
Assuming you allow "for", then the following in bash
for m in {1..12}; do
echo $(date -d $m/1/1 +%b) - $(date -d "$(($m%12+1))/1 - 1 days" +%d) days
done
produces this
Jan - 31 days
Feb - 29 days
Mar - 31 days
Apr - 30 days
May - 31 days
Jun - 30 days
Jul - 31 days
Aug - 31 days
Sep - 30 days
Oct - 31 days
Nov - 30 days
Dec - 31 days
Note: I removed the need for cal
For those that enjoy trivia:
Number months from 1 to 12 and look at the binary representation in four
bits {b3,b2,b1,b0}. A month has 31 days if and only if b3 differs from b0.
All other months have 30 days except for February.
So with the exception of February this works:
for m in {1..12}; do
echo $(date -d $m/1/1 +%b) - $((30+($m>>3^$m&1))) days
done
Result:
Jan - 31 days
Feb - 30 days (wrong)
Mar - 31 days
Apr - 30 days
May - 31 days
Jun - 30 days
Jul - 31 days
Aug - 31 days
Sep - 30 days
Oct - 31 days
Nov - 30 days
Dec - 31 days
Try using this code
date -d "-$(date +%d) days month" +%Y-%m-%d
Returns the number of days in the month compensating for February changes in leap years without looping or using an if statement
This code tests date to see if Feb 29th of the requested year is valid, if so then it updates the second character in the day offset string. The month argument selects the respective substring and adds the month difference to 28.
function daysin()
{
s="303232332323" # normal year
((!($2%4)&&($2%100||!($2%400)))) && s=313232332323 # leap year
echo $[ ${s:$[$1-1]:1} + 28 ]
}
daysin $1 $2 #daysin [1-12] [YYYY]
On a Mac which features BSD date you can just do:
for i in {2..12}; do date -v1d -v"$i"m -v-1d "+%d"; done
Quick Explanation
-v stands for adjust. We are adjusting the date to:
-v1d stands for first day of the month
-v"$i"m defined the month e.g. (-v2m for Feb)
-v-1d minus one day (so we're getting the last day of the previous month)
"+%d" print the day of the month
for i in {2..12}; do date -v1d -v"$i"m -v-1d "+%d"; done
31
28
31
30
31
30
31
31
30
31
30
You can add year of course. See examples in the manpage (link above).
Contents of script.sh:
#!/bin/bash
begin="-$(date +'%-m') + 2"
end="10+$begin"
for ((i=$begin; i<=$end; i++)); do
echo $(date -d "$i month -$(date +%d) days" | awk '{ printf "%s - %s days", $2, $3 }')
done
Results:
Jan - 31 days
Feb - 29 days
Mar - 31 days
Apr - 30 days
May - 31 days
Jun - 30 days
Jul - 31 days
Aug - 31 days
Sep - 30 days
Oct - 31 days
Nov - 30 days
for m in $(seq 1 12); do cal $(date +"$m %Y") | grep -v "^$" |tail -1|grep -o "..$"; done
iterate from 1 to 12 (for...)
print calendar table for each month (cal...)
remove empty lines from output (grep -v...)
print last number in the table (tail...)
There is no sense, to avoid using cal, because it is required by POSIX, so should be there
A variation for the accepted answer to show the use of "yesterday"
$ for m in {1..12}; do date -d "yesterday $m/1 + 1 month" "+%b - %d days"; done
Jan - 31 days
Feb - 28 days
Mar - 31 days
Apr - 30 days
May - 31 days
Jun - 30 days
Jul - 31 days
Aug - 31 days
Sep - 30 days
Oct - 31 days
Nov - 30 days
Dec - 31 days
How it works?
Show the date of yesterday for the date "month/1" after adding 1 month
I needed this few times, so when in PHP comes with easy in bash is not,
so I used this till throw me error "invalid arithemtic operator"
and even with warrings in spellcheck ( "mt" stands for month, "yr" for year )
last=$(echo $(cal ${mt} ${yr}) | awk '{print $NF}')
so this works fine...
### get last day of month
#
# implement from PHP
# src: https://www.php.net/manual/en/function.cal-days-in-month.php
#
if [ $mt -eq 2 ];then
if [[ $(bc <<< "${yr} % 4") -gt 0 ]];then
last=28
else
if [[ $(bc <<< "${yr} % 100") -gt 0 ]];then
last=29
else
[[ $(bc <<< "${yr} % 400") -gt 0 ]] && last=28 || last=29
fi
fi
else
[[ $(bc <<< "(${mt}-1) % 7 % 2") -gt 0 ]] && last=30 || last=31
fi
Building on patm's answer using BSD date for macOS (patm's answer left out December):
for i in {1..12}; do date -v1m -v1d -v+"$i"m -v-1d "+%b - %d days"; done
Explanation:
-v, when using BSD date, means adjust date to:
-v1m means go to first month (January of current year).
-v1d means go to first day (so now we are in January 1).
-v+"$i"m means go to next month.
-v-1d means subtract one day. This gets the last day of the previous month.
"+%b - %d days" is whatever format you want the output to be in.
This will output all the months of the current year and the number of days in each month. The output below is for the as-of-now current year 2022:
Jan - 31 days
Feb - 28 days
Mar - 31 days
Apr - 30 days
May - 31 days
Jun - 30 days
Jul - 31 days
Aug - 31 days
Sep - 30 days
Oct - 31 days
Nov - 30 days
Dec - 31 days