Interpreting date strings with correct locale (Bash, date) [duplicate] - linux

I have a date in a the %c format (could be any other) and I need to use it in the date command. %c is NOT the American format. It is the German one because it's a German server. This also did not work properly on an American server. (Locales set to German or American)
This does not work (error included):
user#server:~$ NOW=$(date +%c); echo $NOW
Do 19 Dez 2013 22:33:28 CET
user#server:~$ date --date="$NOW" +%d/%m/%Y
date: ungültiges Datum „Do 19 Dez 2013 22:33:28 CET“
(date: ungültiges Datum „Do 19 Dez 2013 22:33:28 CET“ = date: invalid date „Do 19 Dez 2013 22:33:28 CET“)
The difficulty is that I don't know which locale or even whci dateformat will be used later since the user can set their own format. So a simple specific parsing solution ist not really going to work!
But how do I do it?
To gerneralize the issue:
If I have a date format format1 (which could be any or at least one that can be reversed) I can use date to get a formatted date. But if I want to format it to another date (format2) how do I do it?
Any solution using anything else than the coreutils is pointless since I am trying to develop a bash script for as many unix machines as possible.
DATE=$(date "+$format1")
date --date="$DATE" "+$format2" # Error in most cases!
This is needed because I have a command which the user can give a date format. This date string is going to be displayed. But in a later step I need to convert this date string into another fixed one. I can manipulate the whcih format the command will get and I can maniplulate the output (or what the user will see).
I cannot run the command twice because it is very time consuming.
Update:
I have found something like a solution:
# Modify $user_format so it can be parsed later
user_format="$user_format %s"
# Time consuming command which will print a date in the given format
output=$(time_consuming_command params "$user_format" more params)
# This will only display what $user_format used to be
echo ${output% *}
# A simple unix timestamp parsing ("${output##* }" will only return the timestamp)
new_formated_date=$(date -d "1970-01-01 ${output##* } sec UTC" "+$new_format")
This is working and might be helpful to others. So I will share this with you.

Not possible with --date as of GNU coreutils 8.22. From the date manual:
‘-d datestr’
‘--date=datestr’
Display the date and time specified in datestr instead of the current
date and time. datestr can be in almost any common format. It can
contain month names, time zones, ‘am’ and ‘pm’, ‘yesterday’, etc. For
example, --date="2004-02-27 14:19:13.489392193 +0530" specifies the
instant of time that is 489,392,193 nanoseconds after February 27,
2004 at 2:19:13 PM in a time zone that is 5 hours and 30 minutes east
of UTC.
Note: input currently must be in locale independent format. E.g., the
LC_TIME=C below is needed to print back the correct date in many
locales:
date -d "$(LC_TIME=C date)"
http://www.gnu.org/software/coreutils/manual/html_node/Options-for-date.html#Options-for-date
Note it says that the input format cannot be in a locale-specific format.
There may be other libraries or programs that would recognize more date formats, but for a given date format it would not be difficult to write a short program to convert it to something date recognizes (for example, with Perl or awk).

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.

You may use libdatetime-format-flexible-perl.
#!/usr/bin/perl
use DateTime::Format::Flexible;
my $date_str = "So 22 Dez 2013 07:29:35 CET";
$parser = DateTime::Format::Flexible->new;
my $date = $parser->parse_datetime($date_str);
print $date
Default output will be 2013-12-22T07:29:35, but since $date is not a regular string but object, you can do something like this:
printf '%02d.%02d.%d', $date->day, $date->month, $date->year;
Also date behavior probably should be considered as a bug. I think so, because date in the same format but in russian is parsed correctly.
$ export LC_TIME=ru_RU.UTF-8
$ NOW="$(date "+%c")"
$ date --date="$NOW" '+%d.%m.%Y'
22.12.2013

If you meant the formatting is wrong, I think what you want is:
NOW=$(date +%c)
date --date="$NOW" +%d/%m/%Y
note the lowercase %d and %m.
Locally, this is what I get:
root#server2:~# NOW=$(date +%c)
root#server2:~# date --date="$NOW" +%d/%m/%Y
19/12/2013

Related

Changing the change timestamp on a file Linux

So I am trying to alter the change timestamp on a file using a script I got from here: Setting/changing the ctime or "Change time" attribute on a file
#!/bin/sh
now=$(date)
echo $now
sudo date --set="qui nov 7 21:05:56 WET 2018"
chmod 777 $1
sudo date --set="$now"
This is the output:
qui nov 8 18:19:39 WET 2018
date: invalid date ‘qui nov 7 21:05:56 WET 2018’
date: invalid date ‘qui nov 8 18:19:39 WET 2018’
What is the matter? The output from date is not a valid date? I tried the fix suggested in the comment to the answer I linked, but it also doesn't work.
AFAIK The reason why the arguments are different:
$ info date
Invoking 'date' with no FORMAT argument is equivalent to invoking it
with a default format that depends on the 'LC_TIME' locale category.
While under Setting the time:
If given an argument that does not start with '+', 'date' sets the
system clock to the date and time specified by that argument (as
described below). You must have appropriate privileges to set the
system clock. Note for changes to persist across a reboot, the hardware
clock may need to be updated from the system clock, which might not
happen automatically on your system.
The argument must consist entirely of digits, which have the
following meaning:
'MM'
month
'DD'
day within month
'hh'
hour
'mm'
minute
'CC'
first two digits of year (optional)
'YY'
last two digits of year (optional)
'ss'
second (optional)
Note, the '--date' and '--set' options may not be used with an
argument in the above format. The '--universal' option may be used with
such an argument to indicate that the specified date and time are
relative to Coordinated Universal Time rather than to the local time
zone.

convert Linux date to yyyy-MM-dd'T'HH:mm:ss'Z' format

I need to parameter-ize a datetime value with an objective of passing to a constructed URI to make a Smartsheet API call to get data (i.e. sheets) changed in last 24 hours.
I want to use Linux date command as I can do something like date -d '1 day ago' %F to get the output of a day before today. How can I use the date command to convert the value to yyyy-MM-dd'T'HH:mm:ss'Z' format to get something like 2018-01-01T00:00:00-07:00?
If the value is not in this particular format, then Smartsheet API complains:
HTTP_01 - Error fetching resource. Status: 400 Reason:
Bad Request : { "errorCode" : 1018, "message" : "The value '/home/my/path/to/param_file/Sysdate' was not valid for the parameter modifiedSince.", "refId" : "1xqawd3s94f4y" }
Thanks,
To output date in ISO 8601 format, you'll probably want to use -I[FMT]/--iso-8601[=FMT] option, if your date supports it (GNU/Linux version does). The FMT is basically a resolution, and in your case you'll want to use s for seconds:
$ date -Is
2018-03-09T09:28:14+01:00
The alternative (for POSIX date, including BSD/OSX date) is to explicitly specify the format and output the time in UTC time zone (-u flag):
$ date -u +"%Y-%m-%dT%H:%M:%SZ"
2018-03-09T08:28:14Z
Note the importance of -u and the explicit Z we can append in that case. Without -u, we would need to output the exact time zone in +hh:mm format, but POSIX date provides support only for time zone name output (%Z). GNU date extends the format set with %:z which outputs the numeric time zone, but if already using GNU date, the first approach with -Is is simpler.
When calling date in your shell use the following format
date +"%Y-%m-%dT%H-%M-%SZ"
2018-03-09T07-44-39Z
To be shortest as possible :
date -u +"%FT%TZ" for UTC
date +"%FT%TZ" for locale's time
Use this alias in the bash_profile:
alias utc='date -u +"%Y-%m-%dT%H:%M:%SZ"'
Then, you can run it like:
$ utc
The output will be:
$ 2021-04-15T01:36:31Z

Convert an ISO date to seconds since epoch in linux bash

I have a date in the ISO format YYYY-MM-DDTHH:SS (e.g. 2014-02-14T12:30). I'd like to convert it in seconds since epoch using only the date command in linux bash.
All the dates refer to UTC locale.
I know that this question is easily eligible for duplicate... there are billions of questions about converting dates from one format to another but I can't find my particular scenario
thank you...
With GNU date (from the GNU coreutils package), specify the date to parse with -d and seconds since epoch with %s
$ date -d"2014-02-14T12:30" +%s
1392381000
Note that this will interpret the date to be parsed as being in your local time zone. If you want date to use a specific time zone, you must specify that, either via the variable TZ (which changes the default time zone for date), or in the date string. For UTC:
$ TZ=UTC date -d"2014-02-14T12:30" +%s
1392381000
or in the string, according to ISO 8601:
$ date -d"2014-02-14T12:30Z" +%s
1392381000
See ISO 8601 on Wikipedia for how to specify other time zones in the date string.
It is easier if you install gdate to deal with date strings that have timezones with nano second precision
install coreutils and you will get gdate along
on mac brew install coreutils
gdate --date="2010-10-02T09:35:58.203Z" +%s%N
This is particularly useful when inserting the time series value into influxdb
in a shell script variable = $(gdate --date="2010-10-02T09:35:58.203Z" +%s%N)
echo $variable

linux bash - Parse date in custom format

I have a date in a the %c format (could be any other) and I need to use it in the date command. %c is NOT the American format. It is the German one because it's a German server. This also did not work properly on an American server. (Locales set to German or American)
This does not work (error included):
user#server:~$ NOW=$(date +%c); echo $NOW
Do 19 Dez 2013 22:33:28 CET
user#server:~$ date --date="$NOW" +%d/%m/%Y
date: ungültiges Datum „Do 19 Dez 2013 22:33:28 CET“
(date: ungültiges Datum „Do 19 Dez 2013 22:33:28 CET“ = date: invalid date „Do 19 Dez 2013 22:33:28 CET“)
The difficulty is that I don't know which locale or even whci dateformat will be used later since the user can set their own format. So a simple specific parsing solution ist not really going to work!
But how do I do it?
To gerneralize the issue:
If I have a date format format1 (which could be any or at least one that can be reversed) I can use date to get a formatted date. But if I want to format it to another date (format2) how do I do it?
Any solution using anything else than the coreutils is pointless since I am trying to develop a bash script for as many unix machines as possible.
DATE=$(date "+$format1")
date --date="$DATE" "+$format2" # Error in most cases!
This is needed because I have a command which the user can give a date format. This date string is going to be displayed. But in a later step I need to convert this date string into another fixed one. I can manipulate the whcih format the command will get and I can maniplulate the output (or what the user will see).
I cannot run the command twice because it is very time consuming.
Update:
I have found something like a solution:
# Modify $user_format so it can be parsed later
user_format="$user_format %s"
# Time consuming command which will print a date in the given format
output=$(time_consuming_command params "$user_format" more params)
# This will only display what $user_format used to be
echo ${output% *}
# A simple unix timestamp parsing ("${output##* }" will only return the timestamp)
new_formated_date=$(date -d "1970-01-01 ${output##* } sec UTC" "+$new_format")
This is working and might be helpful to others. So I will share this with you.
Not possible with --date as of GNU coreutils 8.22. From the date manual:
‘-d datestr’
‘--date=datestr’
Display the date and time specified in datestr instead of the current
date and time. datestr can be in almost any common format. It can
contain month names, time zones, ‘am’ and ‘pm’, ‘yesterday’, etc. For
example, --date="2004-02-27 14:19:13.489392193 +0530" specifies the
instant of time that is 489,392,193 nanoseconds after February 27,
2004 at 2:19:13 PM in a time zone that is 5 hours and 30 minutes east
of UTC.
Note: input currently must be in locale independent format. E.g., the
LC_TIME=C below is needed to print back the correct date in many
locales:
date -d "$(LC_TIME=C date)"
http://www.gnu.org/software/coreutils/manual/html_node/Options-for-date.html#Options-for-date
Note it says that the input format cannot be in a locale-specific format.
There may be other libraries or programs that would recognize more date formats, but for a given date format it would not be difficult to write a short program to convert it to something date recognizes (for example, with Perl or awk).
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.
You may use libdatetime-format-flexible-perl.
#!/usr/bin/perl
use DateTime::Format::Flexible;
my $date_str = "So 22 Dez 2013 07:29:35 CET";
$parser = DateTime::Format::Flexible->new;
my $date = $parser->parse_datetime($date_str);
print $date
Default output will be 2013-12-22T07:29:35, but since $date is not a regular string but object, you can do something like this:
printf '%02d.%02d.%d', $date->day, $date->month, $date->year;
Also date behavior probably should be considered as a bug. I think so, because date in the same format but in russian is parsed correctly.
$ export LC_TIME=ru_RU.UTF-8
$ NOW="$(date "+%c")"
$ date --date="$NOW" '+%d.%m.%Y'
22.12.2013
If you meant the formatting is wrong, I think what you want is:
NOW=$(date +%c)
date --date="$NOW" +%d/%m/%Y
note the lowercase %d and %m.
Locally, this is what I get:
root#server2:~# NOW=$(date +%c)
root#server2:~# date --date="$NOW" +%d/%m/%Y
19/12/2013

How to convert UTC to local time in a shell script on linux

I have a string of the format
20110724T080000Z
and I want to convert that to local time in a shell script on linux. I thought I simply could give it as input to date, but I don't seem to be able to tell date what format my input date has.
this
date -d "20110724T080000Z" -u
would make date complain
date: invalid date `20110724T080000Z'
Also, what is the format of the form "20110724T080000Z" called? I have had little success trying to google for it.
That's ISO8601 "basic format" for a combined date and time. date does not seem to be able to parse 20110724T080000Z, but if you are prepared to do a few string substitutions it parses 20110724 08:00:00Z correctly.
The date program recognizes yyyy-mm-ddTHH:MM:SS (as well as yyyy-mm-dd HH:MM:SS), so:
a=20110724T080000Z
b=${a:0:4}-${a:4:2}-${a:6:5}:${a:11:2}:${a:13:2}
date +%F_%T -d "${b} +0"
Would print 2011-07-24_12:30:00 in my locale.
its called Zulu time. Its the same as UCT, which used to be referred to as GMT. It's used with the military to specify UCT so there is no confusion on correspondance.
http://en.wikipedia.org/wiki/Date_(Unix)
this command should work according to wikipedia:
date [-u|--utc|--universal] [mmddHHMM[[cc]yy][[.SS]] The only valid option for this form specifies Coordinated Universal Time.
You might try taking advantage of perl:
perl -e 'print scalar localtime(shift), "\n"' 20110724T080000Z
Though u might have to tweak this a little to get it to work correctly. Ok, I don't know exactly why the perl version doesn't do it well, but here is a Ruby version I've tried, though I can't pick the time out well:
ruby -e "require 'date';print Date.strptime('20110724T080000Z','%Y%m%dT%H%M%SZ').ctime"
gives:
Sun Jul 24 00:00:00 2011

Resources