Calculating seconds since the Unix Epoch when there is no +"%s" option for the 'date' command available - date

I wanted to calculate the seconds since the Unix Epoch (1970-01-01 00:00:00). Usually I would use
date +"%s"
Now, on my system the +"%s" option is not available but I easily got around using some other 'date' options and parsed it using bc:
date -u +"scale=0;(((((%Y-1970)*365.2425+%j)*24+%H)*60+%M)*60+%S)/1" | bc
This is short for
years = year_now - 1970
days = years * 365.2425 + day_of_year_now
hours = days * 24 + hour_now
minutes = hours * 60 + minute_now
seconds = minutes * 60 + second_now
So far so good. Then I discovered that the result of this calculation does not match with the result of the +"%s" option. I needed to add a magic number:
date -u +"scale=0;(((((%Y-1970)*365.2425+%j)*24+%H)*60+%M)*60+%S-36936)/1" | bc
Why?
Additionally, several months later, this magic number has changed from -36936 to -99792.
Why?
I'm sure something is wrong with my maths. I do not need better solutions in other script languages but I'd appreciate if somebody could correct my maths, please. Maybe someone has the source code for date and could show me its internal algorithm for +"%s" ... ?

Here is a POSIX way that should then work on all Unix and Unix like systems:
awk 'BEGIN {srand();print srand()}'
If you use ksh93, this should also work:
printf "%(%s)T\n"

Most system will have perl installed:
perl -le 'print time'

Related

Ubuntu Terminal command: Show what time after X seconds?

I need to know if there is a command where I can show what time it will be after X seconds.
In my case: I often need to set "sleep (seconds)"; in terminal before and between other following commands (seperated by ;) and it would be greatfull to see what time it will be after (seconds).
I know this command: date -d#(seconds) -u +%H:%M:%S. But this only show me the duration, so its a conversion. That is a compromise but not exactly what I need.
I hope I explained it understandable and someone can help me^^
Best regards and thanks in advance
You can do a sum to current timestamp (in second) with the coming sleep delay (in seconds too) with $((a + b)).
Then, your initial command transforms to:
date -d#$((timestamp + 10)) -u +%H:%M:%S
The final command can look like:
date -d#$((`date +%s` + 60)) -u +%H:%M:%S
EDIT: As per the OP comment bellow this answer, "Why do I have to add 3600 for not having a timestamp in the past?"
This is due to the local of your system. Indeed, in one part of the command you get the total elapsed seconds from 1970 ... regarding your local, while on the other part, you print the timestamp in reference to UTC.
As your local may be UTC+1 this explains why you have to add one more extra hour (3600 seconds).
You can stick to your system's local with:
date -d#$((`date +%s` + 60)) +%H:%M:%S

18 digit julian timestamp in perl

I need to get 18-digit Julian Timestamp in my perl script. Could anyone help me in this? However I have written a subroutine to achieve this but it does not look good to me since it always gives me a number ending with 6 zeroes. Please help to get a proper 18-digit J-timestamp.
sub GetJulianTimestamp()
{
my $t = `perl -e 'print time, "\n"'`;
return (($t * 1000000 ) + 210866803200000000);
}
Based on the comments, you appear to be asking how to obtain the number of microseconds since the unix epoch.
use Time::HiRes qw( );
my $microsec_time = int( Time::HiRes::time() * 1_000_000 );
return 210866803200000000 + $microsec_time;
I agree with the answer given by ikegami, except the amount to be added to the unix epoch needs to be changed. The value 210866803200000000 corresponds to November 24, 4714 BC, 00:00 Universal Time, Gregorian proleptic calendar. But the epoch of Julian dates is at noon, not midnight. So the amount to be added should be 210,866,760,000,000,000. And of course there is no official name for a Julian date that has been converted to microseconds, so anyone using such a number would have to provide an explanation to anyone who is receiving the data.

Generating Dates between two date ranges in AWK

I need to create a list of days between a date interval.
Say for example from 2001-01-01 to 2009-12-31:
2001-01-01
2001-01-02
2001-01-03
..
2009-12-29
2009-12-30
2009-12-31
I know how to do it but maybe someone has a script already made?
If not, I will make such a script and upload it so others won't waste time on this when they need it.
I do not know awk from GnuWin32, but if the functions "mktime" and "strftime" are available, you can try the following code:
BEGIN {
START_DATE="2001-02-01"
END_DATE="2001-03-05"
S2=START_DATE
gsub("-"," ",S2)
T=mktime(S2 " 01 00 00")
if (T<0)
printf("%s is invalid.\n",START_DATE) >> "/dev/stderr"
else
{
for(S=START_DATE; END_DATE>S ;T+=86440) print S=strftime("%F",T)
}
}
The key is to convert the start date to a number meaning the seconds since the Epoch, add 86400 seconds (one day or 24 x 60 x 60) and convert back to the ISO date format.
After some trials I realized the mktime() function admits wrong dates as good (for instance, 2000-14-03).
Best regards

strftime '%z', (localtime) is not working as expected in solaris machines

I tried this code in linux machines,
my $sysdate = strftime "%Y%m%d%T", (localtime);
my $daylight_saving_time = strftime '%z', (localtime);
i get below output,
sysdate = 2013051402:12:02
daylight_saving_time = -0400
I tried same in solaries machines, i got this
sysdate = 2013051402:12:02
daylight_saving_time = %z
Anyone know the change to be done to get the daylight saving in solaries machines.
Thanks in Advance.
The issue is that POSIX::strftime just calls your system's strftime(3), so
you get whatever that is - or - is not. %z is not part of the POSIX.1 standard
and is not consistent across systems. On other older versions of OSes, like HPUX, %z, is
the same as %Z (time zone name). This is only for older versions.
On Solaris 8, 9 strftime does not support %z - with Solaris 10 it does.
This holds on more moderns versions Solaris 10 & Solaris 11:
%z Replaced by offset from UTC in ISO 8601:2000 standard format
(+hhmm or -hhmm), or by no characters if no time zone is deter-
minable. For example, "-0430" means 4 hours 30 minutes behind UTC
(west of Greenwich). If tm_isdst is zero, the standard time off-
set is used. If tm_isdst is greater than zero, the daylight sav-
ings time offset if used. If tm_isdst is negative, no characters
are returned.
So, this a C library function issue, perl sits on top of those libraries. I do not have a workaround.
Maybe the Date::Manip::TZ works on Solaris:
use Date::Manip::TZ;
my $tz = new Date::Manip::TZ;
say "tz: $tz";

Perl module for parsing natural language time duration specifications (similar to the "at" command)?

I'm writing a perl script that takes a "duration" option, and I'd like to be able to specify this duration in a fairly flexible manner, as opposed to only taking a single unit (e.g. number of seconds). The UNIX at command implements this kind of behavior, by allowing specifications such as "now + 3 hours + 2 days". For my program, the "now" part is implied, so I just want to parse the stuff after the plus sign. (Note: the at command also parses exact date specifications, but I only want to parse durations.)
Is there a perl module for parsing duration specifications like this? I don't need the exact syntax accepted by at, just any reasonable syntax for specifying time durations.
Edit: Basically, I want something like DateTime::Format::Flexible for durations instead of dates.
Take a look at DateTime::Duration and DateTime::Format::Duration:
use DateTime::Duration;
use DateTime::Format::Duration;
my $formatter = DateTime::Format::Duration->new(
pattern => '%e days, %H hours'
);
my $dur = $formatter->parse_duration('2 days, 5 hours');
my $dt = DateTime->now->add_duration($dur);
Time::ParseDate has pretty flexible syntax for relative times. Note that it always returns an absolute time, so you can't tell the difference between "now + 3 hours + 2 days" and "3 hours + 2 days" (both of those are valid inputs to parsedate, and will return the same value). You could subtract time if you want to get a duration instead.
Also, it doesn't return DateTime objects, just a UNIX epoch time. I don't know if that's a problem for your application.
I ended up going with Time::Duration::Parse.