`date` command on OS X doesn't have ISO 8601 `-I` option? - bash

In a Bash script, I want to print the current datetime in ISO 8601 format (preferably UTC), and it seems that this should be as simple as date -I:
http://ss64.com/bash/date.html
But this doesn't seem to work on my Mac:
$ date -I
date: illegal option -- I
usage: date [-jnu] [-d dst] [-r seconds] [-t west] [-v[+|-]val[ymwdHMS]] ...
[-f fmt date | [[[mm]dd]HH]MM[[cc]yy][.ss]] [+format]
And indeed, man date doesn't list this option.
Anyone know why this is, or any other (easy) way for me to print the date in ISO 8601 format? Thanks!

You could use
date "+%Y-%m-%d"
Or for a fully ISO-8601 compliant date, use one of the following formats:
date -u +"%Y-%m-%dT%H:%M:%SZ"
Output:
2011-08-27T23:22:37Z
or
date +%Y-%m-%dT%H:%M:%S%z
Output:
2011-08-27T15:22:37-0800

In GNU date date -I is the same as date +%F, and -Iseconds and -Iminutes also include time with UTC offset.
$ date +%F # -I or +%Y-%m-%d
2013-05-03
$ date +%FT%T%z # -Iseconds or +%Y-%m-%dT%H:%M:%S%z
2013-05-03T15:59:24+0300
$ date +%FT%H:%M # -Iminutes or +%Y-%m-%dT%H:%M%z
2013-05-03T15:59+0300
-u is like TZ=UTC. +00:00 can be replaced with Z.
$ date -u +%FT%TZ
2013-05-03T12:59:24Z
These are also valid ISO 8601 date or time formats:
20130503T15 (%Y%m%dT%M)
2013-05 (%Y%m)
2013-W18 (%Y-W%V)
2013-W18-5 (%Y-W%V-%u)
2013W185 (%YW%V%u)
2013-123 (%Y-%j, ordinal date)
2013 (%Y)
1559 (%H%M)
15 (%H)
15:59:24+03 (UTC offset doesn't have to include minutes)
These are not:
2013-05-03 15:59 (T is required in the extended format)
201305 (it could be confused with the YYMMDD format)
20130503T15:59 (basic and exteded formats can't be mixed)

A short alternative that works on both GNU and BSD date is:
date -u +%FT%T%z

The coreutils package provides GNU versions of tools. To install:
$ brew install coreutils
You can see what's provided:
$ brew list coreutils
Notice it comes with date:
$ brew list coreutils | grep date
This is the standard GNU date command so it'll take the -I switch:
$ gdate -I
2016-08-09

Just use normal date formatting options:
date '+%Y-%m-%d'
Edit: to include time and UTC, these are equivalent:
date -u -Iseconds
date -u '+%Y-%m-%dT%k:%M:%S%z'

Taking the other answers one step further, you could add a function to your ~/.bashrc or ~/.zshrc to add the date -I flag:
date() {
if [ "$1" = "-I" ]; then
command date "+%Y-%m-%dT%H:%M:%S%z"
else
command date "$#"
fi
}

It's not a feature of Bash, it's a feature of the date binary. On Linux you would typically have the GNU coreutils version of date, whereas on OSX you would have the BSD legacy utilities. The GNU version can certainly be installed as an optional package, or you can roll your own replacement - I believe it should be a simple one-liner e.g. in Perl.

There's a precompiled coreutils package for Mac OS X available at:
http://rudix.org/packages-abc.html#coreutils.

I regularly use 'date -I' in Linux when saving files. ex: touch x.date -I. While the equivalent in MacOS is 'date +%F', it is a bit awkward to type every time I save a file. So, I set an alias "alias dt='date +%F'" then touch x.dt gives me the date.

Related

How to format argument date in older FreeBSD?

I have a function that receives date as an argument and I need to format it so it would work on older FreeBSD on our school server.
selected_date=$(date -j $1 +"%Y-%m-%d")
This is what I have so far. Could someone advise me how to correct it so it would work?
The Code has not change in the last FreeBSD releases.
Make sure your input argument is quoted.
use option -f to specify the date format of your input
if you have non numeric input data, ensure the locale is set.
Example, tested on FreeBSD 8.4 and FreeBSD 11.1:
env LANG=C date -j -f '%b %d %T %Z %Y' 'Dec 24 02:12:21 CET 2016' '+%Y-%m-%d'

date: illegal option -- d, Find difference between two dates

I am trying to convert timestamps read from a file from string to date format so that I can find the difference of 2 dates/timestamps. most of the threads/discussions on web show usage of date argument '-d' to convert the string to epoch or to find the difference of two timestamps Find difference between two dates in bash
But it looks like my environment/OS doesn't support -d date argument. Below are the details of my env:
bash --version
GNU bash, version 3.2.52(1)-release (i386-pc-solaris2.10)
Copyright (C) 2007 Free Software Foundation, Inc.
uname -a
SunOS s01***** 5.10 Generic_147148-26 i86pc i386 i86pc
Sample dates read from file:
START_TIME="09/03/16 - 01:04:56"
END_TIME="09/03/16 - 05:10:44"
Code that I have tried
I have tried to mimic the below code from Find difference between two dates in bash
!# /usr/bin/sh
date1="Sat Dec 28 03:22:19 2013"
date2="Sun Dec 29 02:22:19 2013"
date -d #$(( $(date -d "$date2" +%s) - $(date -d "$date1" +%s) )) -u +'%H:%M:%S'
bash test.sh
date: illegal option -- d
usage: date [-u] mmddHHMM[[cc]yy][.SS]
date [-u] [+format]
date -a [-]sss[.fff]
date: illegal option -- d
usage: date [-u] mmddHHMM[[cc]yy][.SS]
date [-u] [+format]
date -a [-]sss[.fff]
test.sh: line 5: - : syntax error: operand expected (error token is " ")
I don't think syntax error on line 5 is the main culprit cause I didnot find option -d in my date's man page.
In response to comments:
>>> date --version
date: illegal option -- version
usage: date [-u] mmddHHMM[[cc]yy][.SS]
date [-u] [+format]
date -a [-]sss[.fff]
>>> date --help
date: illegal option -- help
usage: date [-u] mmddHHMM[[cc]yy][.SS]
date [-u] [+format]
date -a [-]sss[.fff]
>>> echo $0
bash
Even these arguments are not supported. Apologies if I am committing any silly mistake.
Could someone please give me the equivalent of -d for the env details shared above or a way to find the difference between two dates without using -d.
Thanks in advance
awk mktime has a decent chance of existing on your system:
#!/bin/bash
START_TIME="09/03/16 - 01:04:56"
END_TIME="09/03/16 - 05:10:44"
echo -e "$START_TIME\n$END_TIME" |
tr '/:-' ' ' |
awk '{print "20"$3" "$2" "$1" "$4" "$5" "$6}' |
awk '{printf "%s ", mktime($0)}' |
awk '{print $2 - $1}'
explanation:
echo both time strings
tr converts 09/03/16 - 01:04:56 to 09 03 16 01:04:56
first awk changes 09 03 16 01 04 56 to 2016 03 09 01 04 56
second awk converts 2016 03 09 01 04 56 to epoch time: 1457514296 and prints both on one line: 1457514296 1457529044
third awk subtracts first from second, giving difference in seconds: 14748
the awks could also easily be merged, but here i kept each separate for clarity.
According to the POSIX standard, date does not do date and time math for you. It gets or sets the system date and time, possibly with timezone adjustments. See date(1) and note the lack of a -d option (or indeed, any interesting options!).
The question becomes "How do we do date and time math without date?" The timestamps you provided do not have time zone information, so the usual behavior is to assume local time. Local time is bad. Seriously. Some time zones have crazy discontinuities or didn't meaningfully exist hundreds of years ago (e.g. most American time zones). So while you might be able to hack together a custom solution that works in your particular part of the world during the recent past, it simply will not be robust.
If you can get your timestamps into Unix time, you can just subtract them, and that will give you a mostly but not entirely correct answer. Unfortunately, to the best of my knowledge, that can't be done at the command line. Unix provides strptime(3) to do this from C (and from there you go on to mktime(3), as shown in this answer), but I don't believe there is any fully standard utility which provides a command-line interface for this. You may have to write and compile your own.
Correcting for leap seconds is difficult in the extreme because, to the best of my knowledge, POSIX has never provided a standard interface for finding out when leap seconds have happened in the past. Such an interface would require internet connectivity in order to remain up-to-date, which is likely a non-starter for a number of implementations. Without knowing more about your system and its capabilities, I simply cannot begin to guess at what will or will not work for your use case.

getting a previous date in bash/unix

I am looking to get previous date in unix / shell script .
I am using the following code
date -d ’1 day ago’ +’%Y/%m/%d’
But I am getting the following error.
date: illegal option -- d
As far as I've read on the inetrnet , it basically means I am using a older version of GNU. Can anyone please help with this.
Further Info
unix> uname -a
SunOS Server 5.10 Generic_147440-19 sun4v sparc SUNW,Sun-Fire-T200
Also The below command gives an error.
unix> date --version
date: illegal option -- version
usage: date [-u] mmddHHMM[[cc]yy][.SS]
date [-u] [+format]
date -a [-]sss[.fff]
try this:
date --date="yesterday" +%Y/%m/%d
dtd="2015-06-19"
yesterday=$( date -d "${dtd} -1 days" +'%Y_%m_%d' )
echo $yesterday;
you can use
date -d "30 days ago" +"%d/%m/%Y"
to get the date from 30 days ago, similarly you can replace 30 with x amount of days
In order to get 1 day back date using date command:
date -v -1d It will give (current date -1) means 1 day before .
date -v +1d
This will give (current date +1) means 1 day after.
Similarly below written code can be used in place of d to find out year,month etc
y-Year,
m-Month
w-Week
d-Day
H-Hour
M-Minute
S-Second
Several solutions suggested here assume GNU coreutils being present on the system. The following should work on Solaris:
TZ=GMT+24 date +’%Y/%m/%d’
SunOS ships with legacy BSD userland tools which often lack the expected modern options. See if you can get the XPG add-on (it's something like /usr/xpg4/bin/date) or install the GNU coreutils package if you can.
In the meantime, you might need to write your own simple date handling script. There are many examples on the net e.g. in Perl. E.g. this one:
vnix$ perl -MPOSIX=strftime -le 'print strftime("%Y%m", localtime(time-86400))'
201304
(Slightly adapted, if you compare to the one behind the link.)
the following script prints the previous date to the targetDate (specified Date or given date)
targetDate=2014-06-30
count=1
startDate=$( echo `date -d "${targetDate} -${count} days" +"%Y-%m-%d"`)
echo $startDate
I have used the following workaround to get to the required solution .
timeA=$(date +%Y%m)
sysD=$(date +%d)
print "Initial sysD $sysD">>LogPrint.log
sysD=$((sysD-1))
print "Final sysD $sysD">>LogPrint.log
finalTime=$timeA$sysD
I hope this is useful for people who are facing the same issue as me.
$ date '+%m/%d/%Y' --- current date
$ TZ=Etc/GMT+24 date '+%m/%d/%Y' -- one dayprevious date
Use time zone appropriately
Problem
You are using backticks, rather than single quotes, for your arguments. You may also not be using GNU date, or a version of date that supports the flag you are using.
Solution
Quote your arguments properly. For example:
$ date -d '1 day ago' +'%Y/%m/%d'
2013/04/14
Try This:
gdate -d "1 day ago" +"%Y/%m/%d"
date -d "yesterday" '+%Y-%m-%d'

Convert a date in Shell

This is a hart one, how do I convert a date like
12-23-11 13:37
In something like(seconds should always be 00)
Fri Dec 23 13:18:58 CET 2011
?
With gnu date 5.97, you can do:
$ date -d '11-12-23 13:37'
to get what you want, so all you need to do is massage your input.
Since gnu date is not ubiquitous, here's a quick perl script that does what you want:
$ echo 12-23-11 13:37 |
perl -MTime::Local -wnE '
y/-:/ /;
#F=split;
say scalar localtime timelocal( 0, $F[4], $F[3], $F[1], $F[0] - 1,$F[2]);
'
Fri Dec 23 13:37:00 2011
(Requires perl 5.10 for -E and say, but should work in older perl using -e and print.)
If this is a script for yourself and not something that will have to run in a million different environments, then depending on what version of date you have available, you should be able to use it.
Read the man page for your particular version of date. For example, if it's the version documented at http://ss64.com/bash/date.html, you can use --date for the input string, etc.
On Mac OS X, use the -f option to specify the input format, the -j option so that it doesn't try to set the date, and with specifying the output format on the command line.

shell-script: parse seconds with date

I want to get the date +%m/%d/%Y a different number of days ago.
$(( $(date +%s)- 259200)) gives me the seconds of 3 days ago. The -d parameter doesn't accept the seconds to parse it in the format I want 05/06/2011 (error message: date: invalid date '1307284916').
Is there a way to get date to work?
To get date on linux to accept a simple timestamp for -d, prefix the number with the # sign!
~% date +%s
1307548153
~% date -d #1307548153
Wed Jun 8 16:49:13 IST 2011
On MacOS X, you can use date -r 1307284916 +%m/%d/%Y to get the result you want. If you are not on a BSD-derived system like MacOS X (e.g. if you are using Linux), there doesn't seem to be a simple analogue of date -r. And traditional versions of Unix usually don't even provide the facilities of GNU's date.
If you get really stuck, contact me (see my profile) for a program timestamp:
$ timestamp -T '%m/%d/%Y' 1307284916
1307284916 = 06/05/2011
$ timestamp -n -T '%m/%d/%Y' 1307284916
06/05/2011
$ timestamp -T '%m/%d/%Y' 1307284916 $(( $(date +%s)- 259200))
1307284916 = 06/05/2011
1307288704 = 06/05/2011
$

Resources