How can I generate Unix timestamps? - unix
Related question is "Datetime To Unix timestamp", but this question is more general.
I need Unix timestamps to solve my last question. My interests are Python, Ruby and Haskell, but other approaches are welcome.
What is the easiest way to generate Unix timestamps?
In Linux or MacOS you can use:
date +%s
where
+%s, seconds since 1970-01-01 00:00:00 UTC. (GNU Coreutils 8.24 Date manual)
Example output now 1454000043.
in Ruby:
>> Time.now.to_i
=> 1248933648
curl icanhazepoch.com
Basically it's unix timestamps as a service (UTaaS)
In python add the following lines to get a time stamp:
>>> import time
>>> time.time()
1335906993.995389
>>> int(time.time())
1335906993
$ date +%s.%N
where (GNU Coreutils 8.24 Date manual)
+%s, seconds since 1970-01-01 00:00:00 UTC
+%N, nanoseconds (000000000..999999999) since epoch
Example output now 1454000043.704350695.
I noticed that BSD manual of date did not include precise explanation about the flag +%s.
In Bash 5 there's a new variable:
echo $EPOCHSECONDS
Or if you want higher precision (in microseconds):
echo $EPOCHREALTIME
In Perl:
>> time
=> 1335552733
The unix 'date' command is surprisingly versatile.
date -j -f "%a %b %d %T %Z %Y" "`date`" "+%s"
Takes the output of date, which will be in the format defined by -f, and then prints it out (-j says don't attempt to set the date) in the form +%s, seconds since epoch.
First of all, the Unix 'epoch' or zero-time is 1970-01-01 00:00:00Z (meaning midnight of 1st January 1970 in the Zulu or GMT or UTC time zone). A Unix time stamp is the number of seconds since that time - not accounting for leap seconds.
Generating the current time in Perl is rather easy:
perl -e 'print time, "\n"'
Generating the time corresponding to a given date/time value is rather less easy. Logically, you use the strptime() function from POSIX. However, the Perl POSIX::strptime module (which is separate from the POSIX module) has the signature:
($sec, $min, $hour, $mday, $mon, $year, $wday, $yday) =
POSIX::strptime("string", "Format");
The function mktime in the POSIX module has the signature:
mktime(sec, min, hour, mday, mon, year, wday = 0, yday = 0, isdst = 0)
So, if you know the format of your data, you could write a variant on:
perl -MPOSIX -MPOSIX::strptime -e \
'print mktime(POSIX::strptime("2009-07-30 04:30", "%Y-%m-%d %H:%M")), "\n"'
in Haskell
import Data.Time.Clock.POSIX
main :: IO ()
main = print . floor =<< getPOSIXTime
in Go
import "time"
t := time.Unix()
in C
time(); // in time.h POSIX
// for Windows time.h
#define UNIXTIME(result) time_t localtime; time(&localtime); struct tm* utctime = gmtime(&localtime); result = mktime(utctime);
in Swift
NSDate().timeIntervalSince1970 // or Date().timeIntervalSince1970
For completeness, PHP:
php -r 'echo time();'
In BASH:
clitime=$(php -r 'echo time();')
echo $clitime
In Haskell...
To get it back as a POSIXTime type:
import Data.Time.Clock.POSIX
getPOSIXTime
As an integer:
import Data.Time.Clock.POSIX
round `fmap` getPOSIXTime
public static Int32 GetTimeStamp()
{
try
{
Int32 unixTimeStamp;
DateTime currentTime = DateTime.Now;
DateTime zuluTime = currentTime.ToUniversalTime();
DateTime unixEpoch = new DateTime(1970, 1, 1);
unixTimeStamp = (Int32)(zuluTime.Subtract(unixEpoch)).TotalSeconds;
return unixTimeStamp;
}
catch (Exception ex)
{
Debug.WriteLine(ex);
return 0;
}
}
Let's try JavaScript:
var t = Math.floor((new Date().getTime()) / 1000);
...or even nicer, the static approach:
var t = Math.floor(Date.now() / 1000);
In both cases I divide by 1000 to go from seconds to millis and I use Math.floor to only represent whole seconds that have passed (vs. rounding, which might round up to a whole second that hasn't passed yet).
If I want to print utc date time using date command I need to using -u argument with date command.
Example
date -u
Output
Fri Jun 14 09:00:42 UTC 2019
nawk:
$ nawk 'BEGIN{print srand()}'
Works even on old versions of Solaris and probably other UNIX systems, where '''date +%s''' isn't implemented
Doesn't work on Linux and other distros where the posix tools have been replaced with the GNU versions (nawk -> gawk etc.)
Pretty unintuitive but definitelly amusing :-)
For Unix-like environment the following will work.
# Current UNIXTIME
unixtime() {
datetime2unixtime "$(date -u +'%Y-%m-%d %H:%M:%S')"
}
# From DateTime(%Y-%m-%d %H:%M:%S)to UNIXTIME
datetime2unixtime() {
set -- "${1%% *}" "${1##* }"
set -- "${1%%-*}" "${1#*-}" "${2%%:*}" "${2#*:}"
set -- "$1" "${2%%-*}" "${2#*-}" "$3" "${4%%:*}" "${4#*:}"
set -- "$1" "${2#0}" "${3#0}" "${4#0}" "${5#0}" "${6#0}"
[ "$2" -lt 3 ] && set -- $(( $1-1 )) $(( $2+12 )) "$3" "$4" "$5" "$6"
set -- $(( (365*$1)+($1/4)-($1/100)+($1/400) )) "$2" "$3" "$4" "$5" "$6"
set -- "$1" $(( (306*($2+1)/10)-428 )) "$3" "$4" "$5" "$6"
set -- $(( ($1+$2+$3-719163)*86400+$4*3600+$5*60+$6 ))
echo "$1"
}
# From UNIXTIME to DateTime format(%Y-%m-%d %H:%M:%S)
unixtime2datetime() {
set -- $(( $1%86400 )) $(( $1/86400+719468 )) 146097 36524 1461
set -- "$1" "$2" $(( $2-(($2+2+3*$2/$3)/$5)+($2-$2/$3)/$4-(($2+1)/$3) ))
set -- "$1" "$2" $(( $3/365 ))
set -- "$#" $(( $2-( (365*$3)+($3/4)-($3/100)+($3/400) ) ))
set -- "$#" $(( ($4-($4+20)/50)/30 ))
set -- "$#" $(( 12*$3+$5+2 ))
set -- "$1" $(( $6/12 )) $(( $6%12+1 )) $(( $4-(30*$5+3*($5+4)/5-2)+1 ))
set -- "$2" "$3" "$4" $(( $1/3600 )) $(( $1%3600 ))
set -- "$1" "$2" "$3" "$4" $(( $5/60 )) $(( $5%60 ))
printf "%04d-%02d-%02d %02d:%02d:%02d\n" "$#"
}
# Examples
unixtime # => Current UNIXTIME
date +%s # Linux command
datetime2unixtime "2020-07-01 09:03:13" # => 1593594193
date -u +%s --date "2020-07-01 09:03:13" # Linux command
unixtime2datetime "1593594193" # => 2020-07-01 09:03:13
date -u --date #1593594193 +"%Y-%m-%d %H:%M:%S" # Linux command
https://tech.io/snippet/a3dWEQY
With NodeJS, just open a terminal and type: node -e "console.log(new Date().getTime())" or node -e "console.log(Date.now())"
In Rust:
use std::time::{SystemTime, UNIX_EPOCH};
fn main() {
let now = SystemTime::now();
println!("{}", now.duration_since(UNIX_EPOCH).unwrap().as_secs())
}
If you need a Unix timestamp from a shell script (Bourne family: sh, ksh, bash, zsh, ...), this should work on any Unix machine as unlike the other suggestions (perl, haskell, ruby, python, GNU date), it is based on a POSIX standard command and feature.
PATH=`getconf PATH` awk 'BEGIN {srand();print srand()}'
Related
To improve Calculate Number of Days Command
Would like to generate report, which calculate the number of days, the material is in the warehouse. The number of days is the difference between date ($3 field) the material comes in and against (01 OCT 2014) manual feed date. Input.csv Des11,Material,DateIN,Des22,Des33,MRP,Des44,Des55,Des66,Location,Des77,Des88 aa,xxx,19-AUG-14.08:08:01,cc,dd,x20,ee,ff,gg,XX128,hh,jj aa,xxx,19-AUG-14.08:08:01,cc,dd,x20,ee,ff,gg,XX128,hh,jj aa,yyy,13-JUN-14.09:06:08,cc,dd,x20,ee,ff,gg,XX128,hh,jj aa,yyy,13-JUN-14.09:06:08,cc,dd,x20,ee,ff,gg,XX128,hh,jj aa,yyy,05-FEB-14.09:02:09,cc,dd,x20,ee,ff,gg,YY250,hh,jj aa,yyy,05-FEB-14.09:02:09,cc,dd,y35,ee,ff,gg,YY250,hh,jj aa,zzz,05-FEB-14.09:02:09,cc,dd,y35,ee,ff,gg,YY250,hh,jj aa,zzz,11-JUN-13.05:06:17,cc,dd,y35,ee,ff,gg,YY250,hh,jj aa,zzz,11-JUN-13.05:06:17,cc,dd,y35,ee,ff,gg,YY250,hh,jj aa,zzz,11-JUN-13.05:06:17,cc,dd,y35,ee,ff,gg,YY250,hh,jj Currently i am using below command to popualte Ageing - No of days at $13 field ( thanks to gboffi) awk -F, 'NR>0 {date=$3; gsub("[-.]"," ",date); printf $0 ",";system("date --date=\"" date "\" +%s")} ' Input.csv | awk -F, -v OFS=, -v now=`date --date="01 OCT 2014 " +%s` ' NR>0 {$13=now-$13; $13=$13/24/3600;print $0}' >Op_Step11.csv while using the above command in Cygwin (windows), it is taking 50 minutes for 1 Lac (1,00,000) rows of sample input. Since my actual input file contains 25 million rows of lines , it seems that the script will take couple of days , Looking for your suggestions to improve the command and advice !!! Expected Output: Des11,Material,DateIN,Des22,Des33,MRP,Des44,Des55,Des66,Location,Des77,Des88,Ageing-NoOfDays aa,xxx,19-AUG-14.08:08:01,cc,dd,x20,ee,ff,gg,XX128,hh,jj,42.6611 aa,xxx,19-AUG-14.08:08:01,cc,dd,x20,ee,ff,gg,XX128,hh,jj,42.6611 aa,yyy,13-JUN-14.09:06:08,cc,dd,x20,ee,ff,gg,XX128,hh,jj,109.621 aa,yyy,13-JUN-14.09:06:08,cc,dd,x20,ee,ff,gg,XX128,hh,jj,109.621 aa,yyy,05-FEB-14.09:02:09,cc,dd,x20,ee,ff,gg,YY250,hh,jj,237.624 aa,yyy,05-FEB-14.09:02:09,cc,dd,y35,ee,ff,gg,YY250,hh,jj,237.624 aa,zzz,05-FEB-14.09:02:09,cc,dd,y35,ee,ff,gg,YY250,hh,jj,237.624 aa,zzz,11-JUN-13.05:06:17,cc,dd,y35,ee,ff,gg,YY250,hh,jj,476.787 aa,zzz,11-JUN-13.05:06:17,cc,dd,y35,ee,ff,gg,YY250,hh,jj,476.787 aa,zzz,11-JUN-13.05:06:17,cc,dd,y35,ee,ff,gg,YY250,hh,jj,476.787 I don't have the access to change the input format and dont have perl & python access. Update#3: BEGIN{ FS=OFS=","} { t1=$3 t2="01-OCT-14.00:00:00" print $0,(cvttime(t2) - cvttime(t1))/24/3600 } function cvttime(t, a) { split(t,a,"[-.:]") match("JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC",a[2]) a[2] = sprintf("%02d",(RSTART+2)/3) return( mktime("20"a[3]" "a[2]" "a[1]" "a[4]" "a[5]" "a[6]) ) }
Since you are on cygwin you are using GNU awk which has it's own built-in time functions and so you do not need to be trying to use the shell date command. Just tweak this old command I had lying around to suit your input and output format: function cvttime(t, a) { split(t,a,"[/:]") match("JanFebMarAprMayJunJulAugSepOctNovDec",a[2]) a[2] = sprintf("%02d",(RSTART+2)/3) return( mktime(a[3]" "a[2]" "a[1]" "a[4]" "a[5]" "a[6]) ) } BEGIN{ t1="01/Dec/2005:00:04:42" t2="01/Dec/2005:17:14:12" print cvttime(t2) - cvttime(t1) } It uses GNU awk for time functions, see http://www.gnu.org/software/gawk/manual/gawk.html#Time-Functions
Here is an example in Perl: use feature qw(say); use strict; use warnings; use Text::CSV; use Time::Piece; my $csv = Text::CSV->new; my $te = Time::Piece->strptime('01-OCT-14', '%d-%b-%y'); my $fn = 'Input.csv'; open (my $fh, '<', $fn) or die "Could not open file '$fn': $!\n"; chomp(my $head = <$fh>); say "$head,Ageing-NoOfDays"; while (my $line = <$fh>) { chomp $line; if ($csv->parse($line)) { my $t = ($csv->fields())[2]; my $tp = Time::Piece->strptime($t, '%d-%b-%y.%T'); my $s = $te - $tp; say "$line," . $s->days; } else { warn "Line could not be parsed: $line\n"; } } close($fh);
RHL5 to Sunsolaries
Below code works in bash but it is not working in ksh. Presently i am using RHL5 version os below code is working fine but in sunsolaries it is not working. In sunsolaries we are using Korn Shell. #!/bin/bash #give start date and enddate in the format yyyy_mm_dd startdate="${1//_/-}" # change underscores into dashes enddate="${2//_/-}" enddate=`date -d "$enddate + $i day" "+%Y_%m_%d"` #Increases enddate by 1 day so that loop runs on given enddate also enddate="${enddate//_/-}" echo "StartDate: $startdate EndDate+1Day: $enddate" nextdate=$startdate #nextdate runs from startdate to enddate while [ 1 ] do echo "$nextdate $enddate" if [ "$nextdate" == "$enddate" ];then #after given enddate loop breaks break fi day=`date -d "$nextdate"` arr=(${day// / }) echo "${arr[0]}" if [ "${arr[0]}" == "Sat" ];then #checking if day is Saturday, if true then increase nextday and continue nextdate=`date -d "$nextdate + 1 day" "+%Y_%m_%d"` nextdate="${nextdate//_/-}" continue fi #####your code begins here echo "creating file file_$nextdate.txt" touch "file_$nextdate.txt" #test code, just creating files with date, remove this #####your code ends here nextdate=`date -d "$nextdate + 1 day" "+%Y_%m_%d"` #increasing nextday by 1 day nextdate="${nextdate//_/-}" done Please help me how it works in ksh Thanks
Your script is using several time the Gnu date specific -d option. Either find a different way to achieve what it does in you use case, or install Gnu date on the Solaris machine if it isn't already.
Check the date and time entered by user in UNIX
I have a Shell script which uses the date and time parameters entered by the user. Date as mm/dd/yyyy and Time as HH:MM . What would be the easiest means to check the user had entered the proper date [ like month should be less than 12.... for time MM should be less than 60... Do we have any built in functions in UNIX for checking the timestamp?
You could use the unix date tool to parse and verify it for you, and test the return code e.g. A valid date, return code of 0: joel#bohr:~$ date -d "12/12/2000 13:00" Tue Dec 12 13:00:00 GMT 2000 joel#bohr:~$ echo $? 0 An invalid date, return code 1: joel#bohr:~$ date -d "13/12/2000 13:00" date: invalid date `13/12/2000 13:00' joel#bohr:~$ echo $? 1 You can vary the input format accepted by date by using the +FORMAT option (man date) Putting it all together as a little script: usrdate=$1 date -d "$usrdate" > /dev/null 2>&1 if [ $? -eq 0 ]; then echo "Date $usrdate was valid" else echo "Date $usrdate was invalid" fi
You could use grep to check that the input conforms to the correct format: if ! echo "$INPUT" | grep -q 'PATTERN'; then # handle input error fi where PATTERN is a regular expressino that matches all valid inputs and only valid inputs. I leave constructing that pattern to you ;-).
(Late answer) Something that you can use: ... DATETIME=$1 #validate datetime.. tmp=`date -d "$DATETIME" 2>&1` ; #return is: "date: invalid date `something'" if [ "${tmp:6:7}" == "invalid" ]; then echo "Invalid datetime: $DATETIME" ; else ... valid datetime, do something with it ... fi
Converting dates in AWK
I have a file containing many columns of text, including a timestamp along the lines of Fri Jan 02 18:23 and I need to convert that date into MM/DD/YYYY HH:MM format. I have been trying to use the standard `date' tool with awk getline to do the conversion, but I can't quite figure out how to pass the fields into the 'date' command in the format it expects (quoted with " or 's,) as getline needs the command string enclosed in quotes too. Something like "date -d '$1 $2 $3 $4' +'%D %H:%M'" | getline var Now that I think about it, I guess what I'm really asking is how to embed awk variables into a string.
If you're using gawk, you don't need the external date which can be expensive to call repeatedly: awk ' BEGIN{ m=split("Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec",d,"|") for(o=1;o<=m;o++){ months[d[o]]=sprintf("%02d",o) } format = "%m/%d/%Y %H:%M" } { split($4,time,":") date = (strftime("%Y") " " months[$2] " " $3 " " time[1] " " time[2] " 0") print strftime(format, mktime(date)) }' Thanks to ghostdog74 for the months array from this answer.
you can try this. Assuming just the date you specified is in the file awk ' { cmd ="date \"+%m/%d/%Y %H:%M\" -d \""$1" "$2" "$3" "$4"\"" cmd | getline var print var close(cmd) }' file output $ ./shell.sh 01/02/2010 18:23 and if you are not using GNU tools, like if you are in Solaris for example, use nawk nawk 'BEGIN{ m=split("Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec",d,"|") for(o=1;o<=m;o++){ months[d[o]]=sprintf("%02d",o) } cmd="date +%Y" cmd|getline yr close(cmd) } { day=$3 mth=months[$2] print mth"/"day"/"yr" "$4 } ' file
I had a similar issue converting a date from RRDTool databases using rrdfetch but prefer one liners that I've been using since Apollo computer days. Data looked like this: localTemp rs1Temp rs2Temp thermostatMode 1547123400: 5.2788174937e+00 4.7788174937e+00 -8.7777777778e+00 2.0000000000e+00 1547123460: 5.1687014581e+00 4.7777777778e+00 -8.7777777778e+00 2.0000000000e+00 One liner: rrdtool fetch -s -14400 thermostatDaily.rrd MAX | sed s/://g | awk '{print "echo ""\`date -r" $1,"\`" " " $2 }' | sh Result: Thu Jan 10 07:25:00 EST 2019 5.3373432378e+00 Thu Jan 10 07:26:00 EST 2019 5.2788174937e+00 On the face of it this doesn't look very efficient to me but this kind of methodology has always proven to be fairly low overhead under most circumstances even for very large files on very low power computer (like 25Mhz NeXT Machines). Yes Mhz. Sed deletes the colon, awk is used to print the other various commands of interest including just echoing the awk variables and sh or bash executes the resulting string. For methodology or large files or streams I just head the first few lines and gradually build up the one liner. Throw away code.
crontab report of what runs in a specified start and end datetime
Are there any tools or reports out there that given a crontab file can output which jobs run within a specified time-frame. Our crontab file has become very large and our system administrators struggle to find out which jobs need to be rerun when we have scheduled downtime on the server. We're trying to figure out which jobs we need to run. I was planning on writing my own script but wondering if there was something out there already
One thing you can do is: Get Perl module Schedule::Cron Modify it to sleep only optionally (create "fast-forward" mode and where it does sleep($sleep) change to do nothing when fast-forwarding. This will also require changing $now = time; call to do $now++. Modify it to be able indicate start and end times for emulation. Create a Perl one-liner which takes the output of crontab -l and converts it into similar contab but one which replaces command cmd1 arg1 arg2 with a perl subroutine sub { print "Execution: cmd1 arg1 arg2\n"} Run the scheduler in the fast-forward mode, as indicated in the POD. It will read in your modified crontab, and emulate the execution.
There is a fine and clean solution for a 'simulation mode' of Schedule::Cron (and for any other module using sleep,time,alarm internally without modifying Schedule::Cron itself. You can use Time::Mock for throtteling, e.g. with perl -MTime::Mock=throttle,600 schedule.pl one can speedup your 'time machine' by a factor 600 (so, instead of sleeping for 10 minutes it will only sleep a second). Please refer to the manpage of Time::Mock for more details. For using a crontab file directly with Schedule::Cron you should be able to take the example from the README directly: use Schedule::Cron; my $cron = new Schedule::Cron(sub { system(shift) }, file => "/var/spool/crontab.perl"); $cron->run(); The trick here is to use a default dispatcher method which calls system() with the stored parameters. Please let me know, whether this will work for you or whether it will need to be fixed. Instead of system, you could use print as well, of course.
Here's a similar approach to DVK's but using Perl module Schedule::Cron::Events. This is very much a "caveat user" posting - a starting point. Given this crontab file a_crontab.txt: 59 21 * * 1-5 ls >> $HOME/work/stack_overflow/cron_ls.txt # A comment 18 09 * * 1-5 echo "wibble" The below script cron.pl, run as follows, gives: $ perl cron.pl a_crontab.txt "2009/11/09 00:00:00" "2009/11/12 00:00:00" 2009/11/09 09:18:00 "echo "wibble"" 2009/11/09 21:59:00 "ls >> $HOME/work/stack_overflow/cron_ls.txt" 2009/11/10 09:18:00 "echo "wibble"" 2009/11/10 21:59:00 "ls >> $HOME/work/stack_overflow/cron_ls.txt" 2009/11/11 09:18:00 "echo "wibble"" 2009/11/11 21:59:00 "ls >> $HOME/work/stack_overflow/cron_ls.txt" 2009/11/12 09:18:00 "echo "wibble"" 2009/11/12 21:59:00 "ls >> $HOME/work/stack_overflow/cron_ls.txt" Prototype (!) script: use strict; use warnings; use Schedule::Cron::Events; my $crontab_file = shift || die "! Must provide crontab file name"; my $start_time = shift || die "! Must provide start time YYYY/MM/DD HH:MM:SS"; my $stop_time = shift || die "! Must provide stop time YYYY/MM/DD HH:MM:SS"; open my $fh, '<', $crontab_file or die "! Could not open file $crontab_file for reading: $!"; my $table = []; while ( <$fh> ) { next if /^\s*$/; next if /^\s*#/; chomp; push #$table, new Schedule::Cron::Events( $_, Date => [ smhdmy_from_iso( $start_time ) ] ); } close $fh; my $events = []; for my $cron ( #$table ) { my $event_time = $stop_time; while ( $event_time le $stop_time ) { my ( $sec, $min, $hour, $day, $month, $year ) = $cron->nextEvent; $event_time = sprintf q{%4d/%02d/%02d %02d:%02d:%02d}, 1900 + $year, 1 + $month, $day, $hour, $min, $sec; push #$events, qq{$event_time "} . $cron->commandLine . q{"}; } } print join( qq{\n}, sort #$events ) . qq{\n}; sub smhdmy_from_iso { my $input = shift; my ( $y, $m, $d, $H, $M, $S ) = ( $input =~ m=(\d{4})/(\d\d)/(\d\d) (\d\d):(\d\d):(\d\d)= ); ( $S, $M, $H, $d, --$m, $y - 1900 ); } Hope you can adapt to your needs.