Gnu Date and Custom Formats

GNU date and custom formats

per the man page:

The --date=STRING is a mostly free format human readable date
string such as "Sun, 29 Feb 2004 16:21:42 -0800" or "2004-02-29
16:21:42" or even "next Thursday". A date string may contain items
indicating calendar date, time of day, time zone, day of week,
relative time, relative date, and numbers. An empty string indicates
the beginning of the day. The date string format is more complex than
is easily documented here but is fully described in the info
documentation.

The "T" seems to confuse it. This works:

$ date --date="2013-12-02 18:20:52" +%Y%m%dT%H%M%S
20131202T182052

The output format has nothing to do with the input format.

How to convert a custom date format to an alternate format with the gnu 'date' command?

I finally figured this out with the aid of the coreutils mailing list. However, the example they give there uses perl. They specifically rely on the POSIX::strptime module, which does not come with a standard installation of perl. Therefore, I solved this with python, which has the time module. This module should be available in most installations of python2 and python3.

Here's how to use it programmatically:

Python solution:

$ timestamp='2013年1月8日 20時19分'
$ time_format='%Y年%m月%d日 %H時%M分'
$ gdate -u -R -d "$(python -c 'import sys; from time import strptime; t=strptime(sys.argv[-1],"'$time_format'"); print("%d-%d-%d %d:%d"%(t.tm_year,t.tm_mon,t.tm_mday,t.tm_hour,t.tm_min))' $timestamp)"
Tue, 08 Jan 2013 20:19:00 +0000

This works with both python2 and python3. You can substitute any timestamp and format as you like.

Perl solution

To document the answer given to me on coreutils, the perl solution is this (requires POSIX::strptime)

$ gdate -u -R -d "$(perl -MPOSIX::strptime -le 'my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday) = POSIX::strptime("$ARGV[0]","%Y年%m月%d日 %H時%M分");$year+=1900;$mon+=1;printf("%04d-%02d-%02d %0d:%02d\n",$year,$mon,$mday,$hour,$min);' "2013年1月8日 20時19分")"

What are valid input DATE formats for the (Linux) date command?

A workaround:

x="2015_06_15"
date -d "${x//_/} 12:00 +1 day" +%Y%m%d

Output:


20150616

Parse non standard date format

Here is what the man date page says about format for the --date option:

The --date=STRING is a mostly free format human readable date string such as
"Sun, 29 Feb 2004 16:21:42 -0800" or "2004-02-29 16:21:42" or even "next
Thursday". A date string may contain items indicating calendar date, time of day,
time zone, day of week, relative time, relative date, and numbers. An empty
string indicates the beginning of the day. The date string format is more
complex than is easily documented here but is fully described in the info
documentation.

Hence you can use, for example:

date --date "2014-06-12 09:03 UTC" --utc +%d.%m.%Y,\ %H:%M\ UTC
# Output: 12.06.2014, 09:03 UTC

to get what you desire.

You could get this second form easily from your first output with a sed line as follows:

sed 's/\([0-9]\{2\}\)\.\([0-9]\{2\}\)\.\([0-9]\{4\}\), \(.*\)/\3-\2-\1 \4/'
<<< '12.06.2014, 09:03 UTC'
# Output: 2014-06-12 09:03 UTC

Note that it would probably be faster to output date at ISO 8601 format in the first time for reuse, e.g. with:

date --utc +%F\ %H:%M\ UTC
# Output: 2014-06-12 10:12 UTC

linux bash - Parse date in custom format

Why don't you store the time as unixtime (ie milliseconds since 1st of january 1970) Like 1388198714?

The requested exercise in trying to parse all date formats from all around the world as a one shot bash script without reasonable dependecies is slightly ridiculous.

YYYY-MM-DD format date in shell script

In bash (>=4.2) it is preferable to use printf's built-in date formatter (part of bash) rather than the external date (usually GNU date).

As such:

# put current date as yyyy-mm-dd in $date
# -1 -> explicit current date, bash >=4.3 defaults to current time if not provided
# -2 -> start time for shell
printf -v date '%(%Y-%m-%d)T\n' -1

# put current date as yyyy-mm-dd HH:MM:SS in $date
printf -v date '%(%Y-%m-%d %H:%M:%S)T\n' -1

# to print directly remove -v flag, as such:
printf '%(%Y-%m-%d)T\n' -1
# -> current date printed to terminal

In bash (<4.2):

# put current date as yyyy-mm-dd in $date
date=$(date '+%Y-%m-%d')

# put current date as yyyy-mm-dd HH:MM:SS in $date
date=$(date '+%Y-%m-%d %H:%M:%S')

# print current date directly
echo $(date '+%Y-%m-%d')

Other available date formats can be viewed from the date man pages (for external non-bash specific command):

man date

How can I change the format of a date from the command line?

$ date -d '2005-06-30' +'%a %F'
Thu 2005-06-30

See man date for other format options.

This option is available on Linux, but not on Darwin. In Darwin, you can use the following syntax instead:

date -j -f "%Y-%m-%d" 2006-06-30 +"%a %F"

The -f argument specifies the input format and the + argument specifies the output format.

As pointed out by another poster below, you would be wise to use %u (numeric day of week) rather than %a to avoid localization issues.

equivalent date from GNU to solaris

Tcl has a good free-form date scanner, if you have Tcl installed (try which tclsh). A shell function:

tcldate() {
d=${1:-now} # the date string
f=${2:-%c} # the output format
echo "puts [clock format [clock scan {$d}] -format {$f}]" | tclsh
}

In action on an ancient Solaris 8 box with bash 2.03 and tcl 8.3.3

$ tcldate
Tue Jul 23 13:27:17 2013
$ i=4
$ tcldate "$i days"
Sat Jul 27 13:27:34 2013
$ tcldate "$i days" "%Y-%m-%d"
2013-07-27
$ tcldate "20130101 + $i days" "%Y-%m-%d"
2013-01-05

This even handles daylight savings transitions:

$ tcldate "2014-03-09 00:30 + 1 hour" "%D %T %Z"
03/09/14 01:30:00 EST
$ tcldate "2014-03-09 00:30 + 2 hour" "%D %T %Z"
03/09/14 03:30:00 EDT
$ tcldate "2013-11-03 00:30 + 1 hour" "%D %T %Z"
11/03/13 01:30:00 EDT
$ tcldate "2013-11-03 00:30 + 2 hour" "%D %T %Z"
11/03/13 01:30:00 EST


Related Topics



Leave a reply



Submit