Subtract time using date and bash
All the other questions on the SE network deal with scenarios where either the date is assumed to be now
(Q) or where only a date is specified (Q).
What I want to do is supply a date and time, and then subtract a time from that.
Here is what I tried first:
date -d "2018-12-10 00:00:00 - 5 hours - 20 minutes - 5 seconds"
This results in 2018-12-10 06:39:55
- It added 7 hours. Then subtracted 20:05 minutes.
After reading the man
and info
page of date
, I thought I have it fixed with this:
date -d "2018-12-10T00:00:00 - 5 hours - 20 minutes - 5 seconds"
But, same result. Where does it even get the 7 hours from?
I tried other dates as well because I thought maybe we had 7200 leap seconds on that day, who knows lol. But same results.
A few more examples:
$ date -d "2018-12-16T00:00:00 - 24 hours" +%Y-%m-%d_%H:%M:%S
2018-12-17_02:00:00
$ date -d "2019-01-19T05:00:00 - 2 hours - 5 minutes" +%Y-%m-%d_%H:%M:%S
2019-01-19_08:55:00
But here it becomes interesting. If I omit the time on input, it works fine:
$ date -d "2018-12-16 - 24 hours" +%Y-%m-%d_%H:%M:%S
2018-12-15_00:00:00
$ date -d "2019-01-19 - 2 hours - 5 minutes" +%Y-%m-%d_%H:%M:%S
2019-01-18_21:55:00
$ date --version
date (GNU coreutils) 8.30
What am I missing?
Update: I've added a Z
at the end, and it changed the behaviour:
$ date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_04:00:00
I'm still confused though. There is not much about this in the GNU info page about date.
I'm guessing this is a timezone issue, but quoting The Calendar Wiki on ISO 8601:
If no UTC relation information is given with a time representation,
the time is assumed to be in local time.
Which is what I want. My local time is set correctly too. I'm not sure why date would mess with the timezone at all in this simple case of me supplying a datetime and wanting to subtract something off of it. Shouldn't it subtract the hours from the date string first? Even if it does convert it to a date first and then does the subtraction, if I leave out any subtractions I get exactly what I want:
$ date -d "2019-01-19T05:00:00" +%Y-%m-%d_%H:%M:%S
2019-01-19_05:00:00
So IF this truly is a timezone issue, where does that madness come from?
date gnu
add a comment |
All the other questions on the SE network deal with scenarios where either the date is assumed to be now
(Q) or where only a date is specified (Q).
What I want to do is supply a date and time, and then subtract a time from that.
Here is what I tried first:
date -d "2018-12-10 00:00:00 - 5 hours - 20 minutes - 5 seconds"
This results in 2018-12-10 06:39:55
- It added 7 hours. Then subtracted 20:05 minutes.
After reading the man
and info
page of date
, I thought I have it fixed with this:
date -d "2018-12-10T00:00:00 - 5 hours - 20 minutes - 5 seconds"
But, same result. Where does it even get the 7 hours from?
I tried other dates as well because I thought maybe we had 7200 leap seconds on that day, who knows lol. But same results.
A few more examples:
$ date -d "2018-12-16T00:00:00 - 24 hours" +%Y-%m-%d_%H:%M:%S
2018-12-17_02:00:00
$ date -d "2019-01-19T05:00:00 - 2 hours - 5 minutes" +%Y-%m-%d_%H:%M:%S
2019-01-19_08:55:00
But here it becomes interesting. If I omit the time on input, it works fine:
$ date -d "2018-12-16 - 24 hours" +%Y-%m-%d_%H:%M:%S
2018-12-15_00:00:00
$ date -d "2019-01-19 - 2 hours - 5 minutes" +%Y-%m-%d_%H:%M:%S
2019-01-18_21:55:00
$ date --version
date (GNU coreutils) 8.30
What am I missing?
Update: I've added a Z
at the end, and it changed the behaviour:
$ date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_04:00:00
I'm still confused though. There is not much about this in the GNU info page about date.
I'm guessing this is a timezone issue, but quoting The Calendar Wiki on ISO 8601:
If no UTC relation information is given with a time representation,
the time is assumed to be in local time.
Which is what I want. My local time is set correctly too. I'm not sure why date would mess with the timezone at all in this simple case of me supplying a datetime and wanting to subtract something off of it. Shouldn't it subtract the hours from the date string first? Even if it does convert it to a date first and then does the subtraction, if I leave out any subtractions I get exactly what I want:
$ date -d "2019-01-19T05:00:00" +%Y-%m-%d_%H:%M:%S
2019-01-19_05:00:00
So IF this truly is a timezone issue, where does that madness come from?
date gnu
1
Also: serverfault.com/questions/952279/…
– B Layer
Mar 7 at 19:16
add a comment |
All the other questions on the SE network deal with scenarios where either the date is assumed to be now
(Q) or where only a date is specified (Q).
What I want to do is supply a date and time, and then subtract a time from that.
Here is what I tried first:
date -d "2018-12-10 00:00:00 - 5 hours - 20 minutes - 5 seconds"
This results in 2018-12-10 06:39:55
- It added 7 hours. Then subtracted 20:05 minutes.
After reading the man
and info
page of date
, I thought I have it fixed with this:
date -d "2018-12-10T00:00:00 - 5 hours - 20 minutes - 5 seconds"
But, same result. Where does it even get the 7 hours from?
I tried other dates as well because I thought maybe we had 7200 leap seconds on that day, who knows lol. But same results.
A few more examples:
$ date -d "2018-12-16T00:00:00 - 24 hours" +%Y-%m-%d_%H:%M:%S
2018-12-17_02:00:00
$ date -d "2019-01-19T05:00:00 - 2 hours - 5 minutes" +%Y-%m-%d_%H:%M:%S
2019-01-19_08:55:00
But here it becomes interesting. If I omit the time on input, it works fine:
$ date -d "2018-12-16 - 24 hours" +%Y-%m-%d_%H:%M:%S
2018-12-15_00:00:00
$ date -d "2019-01-19 - 2 hours - 5 minutes" +%Y-%m-%d_%H:%M:%S
2019-01-18_21:55:00
$ date --version
date (GNU coreutils) 8.30
What am I missing?
Update: I've added a Z
at the end, and it changed the behaviour:
$ date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_04:00:00
I'm still confused though. There is not much about this in the GNU info page about date.
I'm guessing this is a timezone issue, but quoting The Calendar Wiki on ISO 8601:
If no UTC relation information is given with a time representation,
the time is assumed to be in local time.
Which is what I want. My local time is set correctly too. I'm not sure why date would mess with the timezone at all in this simple case of me supplying a datetime and wanting to subtract something off of it. Shouldn't it subtract the hours from the date string first? Even if it does convert it to a date first and then does the subtraction, if I leave out any subtractions I get exactly what I want:
$ date -d "2019-01-19T05:00:00" +%Y-%m-%d_%H:%M:%S
2019-01-19_05:00:00
So IF this truly is a timezone issue, where does that madness come from?
date gnu
All the other questions on the SE network deal with scenarios where either the date is assumed to be now
(Q) or where only a date is specified (Q).
What I want to do is supply a date and time, and then subtract a time from that.
Here is what I tried first:
date -d "2018-12-10 00:00:00 - 5 hours - 20 minutes - 5 seconds"
This results in 2018-12-10 06:39:55
- It added 7 hours. Then subtracted 20:05 minutes.
After reading the man
and info
page of date
, I thought I have it fixed with this:
date -d "2018-12-10T00:00:00 - 5 hours - 20 minutes - 5 seconds"
But, same result. Where does it even get the 7 hours from?
I tried other dates as well because I thought maybe we had 7200 leap seconds on that day, who knows lol. But same results.
A few more examples:
$ date -d "2018-12-16T00:00:00 - 24 hours" +%Y-%m-%d_%H:%M:%S
2018-12-17_02:00:00
$ date -d "2019-01-19T05:00:00 - 2 hours - 5 minutes" +%Y-%m-%d_%H:%M:%S
2019-01-19_08:55:00
But here it becomes interesting. If I omit the time on input, it works fine:
$ date -d "2018-12-16 - 24 hours" +%Y-%m-%d_%H:%M:%S
2018-12-15_00:00:00
$ date -d "2019-01-19 - 2 hours - 5 minutes" +%Y-%m-%d_%H:%M:%S
2019-01-18_21:55:00
$ date --version
date (GNU coreutils) 8.30
What am I missing?
Update: I've added a Z
at the end, and it changed the behaviour:
$ date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_04:00:00
I'm still confused though. There is not much about this in the GNU info page about date.
I'm guessing this is a timezone issue, but quoting The Calendar Wiki on ISO 8601:
If no UTC relation information is given with a time representation,
the time is assumed to be in local time.
Which is what I want. My local time is set correctly too. I'm not sure why date would mess with the timezone at all in this simple case of me supplying a datetime and wanting to subtract something off of it. Shouldn't it subtract the hours from the date string first? Even if it does convert it to a date first and then does the subtraction, if I leave out any subtractions I get exactly what I want:
$ date -d "2019-01-19T05:00:00" +%Y-%m-%d_%H:%M:%S
2019-01-19_05:00:00
So IF this truly is a timezone issue, where does that madness come from?
date gnu
date gnu
edited Jan 30 at 10:22


Jeff Schaller♦
44.6k1162143
44.6k1162143
asked Jan 30 at 8:30


confetticonfetti
556221
556221
1
Also: serverfault.com/questions/952279/…
– B Layer
Mar 7 at 19:16
add a comment |
1
Also: serverfault.com/questions/952279/…
– B Layer
Mar 7 at 19:16
1
1
Also: serverfault.com/questions/952279/…
– B Layer
Mar 7 at 19:16
Also: serverfault.com/questions/952279/…
– B Layer
Mar 7 at 19:16
add a comment |
5 Answers
5
active
oldest
votes
That last example should have clarified things for you: timezones.
$ TZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_03:00:00
$ TZ=Asia/Colombo date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_08:30:00
As the output clearly varies by the timezone, I'd suspect some non-obvious default taken for a time string without a timezone specified. Testing a couple of values, it seems to be UTC-05:00, though I'm not sure what that is.
$ TZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S%Z
2019-01-19_08:00:00UTC
$ TZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S%Z
2019-01-19_03:00:00UTC
$ TZ=UTC date -d "2019-01-19T05:00:00" +%Y-%m-%d_%H:%M:%S%Z
2019-01-19_05:00:00UTC
It's only used when performing date arithmetic.
It seems the issue here is that - 2 hours
is not taken as arithmetic, but as a timezone specifier:
# TZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S%Z --debug
date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC-02
date: parsed relative part: +1 hour(s)
date: input timezone: parsed date/time string (-02)
date: using specified time as starting value: '05:00:00'
date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02'
date: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02' = 1547881200 epoch-seconds
date: after time adjustment (+1 hours, +0 minutes, +0 seconds, +0 ns),
date: new time = 1547884800 epoch-seconds
date: timezone: TZ="UTC" environment value
date: final: 1547884800.000000000 (epoch-seconds)
date: final: (Y-M-D) 2019-01-19 08:00:00 (UTC)
date: final: (Y-M-D) 2019-01-19 08:00:00 (UTC+00)
2019-01-19_08:00:00UTC
So, not only is no arithmetic being done, there seems to be a daylight savings 1 hour adjustment on the time, leading to a somewhat nonsensical time for us.
This also holds for addition:
# TZ=UTC date -d "2019-01-19T05:00:00 + 5:30 hours" +%Y-%m-%d_%H:%M:%S%Z --debug
date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC+05:30
date: parsed relative part: +1 hour(s)
date: input timezone: parsed date/time string (+05:30)
date: using specified time as starting value: '05:00:00'
date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=+05:30'
date: '(Y-M-D) 2019-01-19 05:00:00 TZ=+05:30' = 1547854200 epoch-seconds
date: after time adjustment (+1 hours, +0 minutes, +0 seconds, +0 ns),
date: new time = 1547857800 epoch-seconds
date: timezone: TZ="UTC" environment value
date: final: 1547857800.000000000 (epoch-seconds)
date: final: (Y-M-D) 2019-01-19 00:30:00 (UTC)
date: final: (Y-M-D) 2019-01-19 00:30:00 (UTC+00)
2019-01-19_00:30:00UTC
Debugging a bit more, the parsing seems to be: 2019-01-19T05:00:00 - 2
(-2
being the timezone), and hours
(= 1 hour), with an implied addition. It becomes easier to see if you use minutes instead:
# TZ=UTC date -d "2019-01-19T05:00:00 - 2 minutes" +%Y-%m-%d_%H:%M:%S%Z --debug
date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC-02
date: parsed relative part: +1 minutes
date: input timezone: parsed date/time string (-02)
date: using specified time as starting value: '05:00:00'
date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02'
date: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02' = 1547881200 epoch-seconds
date: after time adjustment (+0 hours, +1 minutes, +0 seconds, +0 ns),
date: new time = 1547881260 epoch-seconds
date: timezone: TZ="UTC" environment value
date: final: 1547881260.000000000 (epoch-seconds)
date: final: (Y-M-D) 2019-01-19 07:01:00 (UTC)
date: final: (Y-M-D) 2019-01-19 07:01:00 (UTC+00)
2019-01-19_07:01:00UTC
So, well, date arithmetic is being done, just not the one that we asked for. ¯(ツ)/¯
1
@confetti it does indeed; I think this default timezone is used only when adding/subtracting (comparingTZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
vsTZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S
)
– Olorin
Jan 30 at 8:54
2
Could be a possible bug indate
, as per the ISO 8601 standard, if no timezone is supplied, local time(zone) should be assumed, which in case of an arithmetic operation, it is not. Very strange issue to me though.
– confetti
Jan 30 at 8:57
1
@confetti found the problem:- 2 hours
is taken as the timezone specifier here.
– Olorin
Jan 30 at 9:17
2
Wow. Now that somehow makes sense. Well, at least it explains it. Thank you a lot for figuring that out. To me it sounds like their parser needs an update though, as clearly with a format and whitespace like this you do not want to specify the timezone by the ` - 2 hours` and it's surely causing confusion. If they don't want to update the parser, at least the manual should get a note about this.
– confetti
Jan 30 at 9:19
1
Today I learned about date's--debug
option! Great explanation.
– Jeff Schaller♦
Jan 30 at 17:26
|
show 1 more comment
It works correctly when you convert the input date to ISO 8601 first:
$ date -d "$(date -Iseconds -d "2018-12-10 00:00:00") - 5 hours - 20 minutes - 5 seconds"
So 9. Dez 18:39:55 CET 2018
Thank you, that does work indeed, but is there any explanation for this? I've added some more info about the ISO 8601 thing to my question, and I really don't see wheredate
would mess this up as without any subtractions supplied, the timezone is left untouched and everything is as expected too without having to supply any timezone information or conversion.
– confetti
Jan 30 at 8:49
I cannot tell, sorry. If someone else could answer this I'd be happy because I was wondering too.
– RoVo
Jan 30 at 8:50
I'd be glad too but I'll accept this for now because it does fix my issue!
– confetti
Jan 30 at 8:54
3
This works becausedate -I
also outputs the timezone specifier (e.g.2018-12-10T00:00:00+02:00
) which fixes the issue described in Olorin's answer
– ilkkachu
Jan 30 at 19:22
add a comment |
TLDR: This is not a bug. You've just found one of the subtle but documented behaviours of date
. When performing time arithmetic with date
, use a timezone-independent format (like Unix time) or read very carefully the documentation to know how to properly use this command.
GNU date
uses your system settings (the TZ
environment variable or, if unset, the system defaults) to determine the timezone of both the date feeded with the -d
/--date
option and the date reported by the +format
argument. The --date
option also let you override the timezone for its own option-argument but it doesn't override the timezone of +format
. That's the root of the confusion, IMHO.
Considering that my timezone is UTC-6, compare the following commands:
$ date -d '1970-01-01 00:00:00' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-01 00:00:00 -06:00
Unix: 21600
$ date -d '1970-01-01 00:00:00 UTC' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1969-12-31 18:00:00 -06:00
Unix: 0
$ TZ='UTC0' date -d '1970-01-01 00:00:00 UTC' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-01 00:00:00 +00:00
Unix: 0
The first one uses my timezone for both -d
and +format
. The second one uses UTC for -d
but my timezone for +format
. The third one uses UTC for both.
Now, compare the following simple operations:
$ date -d '1970-01-01 00:00:00 UTC +1 day' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-01 18:00:00 -06:00
Unix: 86400
$ TZ='UTC0' date -d '1970-01-01 00:00:00 UTC +1 day' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-02 00:00:00 +00:00
Unix: 86400
Even if the Unix time is telling me the same thing, the "Normal" time differs because of my own timezone.
If I wanted to do the same operation but using exclusively my timezone:
$ TZ='CST+6' date -d '1970-01-01 00:00:00 -06:00 +1 day' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-02 00:00:00 -06:00
Unix: 108000
3
Upvoted for mentioning epoch/Unix time, which imo is the only sane way to do time arithmetic
– Rui F Ribeiro
Jan 30 at 9:58
1
TL;DR If you just know your local time offset from Zulu time (e.g. west coast USA is -8 hours or-08:00
), simply append that to input date-time...nothing else to fiddle with. Example:date -d '2019-02-28 14:05:36-08:00 +2 days 4 hours 3 seconds' +'local: %F %T'
gives local: 2019-03-02 18:05:36
– B Layer
Feb 28 at 22:52
@BLayer You're right, it works as expected in that scenario. But imagine the situation where a given script using that approach is executed in a place with a different timezone. The output, while technically correct, may look wrong depending on the information provided by the+format
argument. For instance, on my system, the same command outputs:local: 2019-03-02 20:05:39
(if I add%:z
to+format
, it becomes obvious that the info is correct and the discrepancy is due to the timezones).
– nxnev
Mar 1 at 1:45
@BLayer IMHO, a better general approach would be to use the same timezone for both-d
and+format
or Unix time, as I said in the answer, to avoid unexpected results.
– nxnev
Mar 1 at 1:45
1
@nxnev Agreed, if you're writing a script to be published/shared. The opening words "if you know your own timezone", besides having a literal meaning, are supposed to imply casual/personal use. Someone publishing a script relying on something as flimsy as knowing just their own system's tz probably shouldn't be in the script sharing game. :) On the other hand I do/would use my own command on all my personal environments.
– B Layer
Mar 1 at 2:17
add a comment |
GNU date
does support simple date arithmetic, though epoch time calculations as shown in @sudodus' answer are sometimes clearer (and more portable).
The use of +/- when there is no timezone specified in the timestamp triggers an attempt to match a timezone next, before anything else is parsed.
Here's one way to do it, use "ago" instead of "-":
$ date -d "2018-12-10 00:00:00 5 hours ago 20 minutes ago 5 seconds ago"
Sun Dec 9 18:39:55 GMT 2018
or
$ date -d "2018-12-10 00:00:00Z -5 hours -20 minutes -5 seconds"
Sun Dec 9 18:39:55 GMT 2018
(Though you cannot arbitrarily use "Z", it works in my zone, but that makes it a UTC/GMT zone timestamp - use your own zone, or %z/%Z by appending ${TZ:-$(date +%z)}
to the timestamp instead.)
Adding extra time terms of these forms adjust time:
- "5 hours ago" subtract 5 hours
- "4 hours" add (implicit) 4 hours
- "3 hours hence" add (explicit) 3 hours (not supported in older versions)
Many complex adjustments, in any order, can be used (though relative and variable terms like "14 weeks hence last monday" are asking for trouble ;-)
(There's another small beartrap here too, date
will always give a valid date, so date -d "2019-01-31 1 month"
gives 2019-03-03, as does "next month")
Given the wide variety of time and date formats that are supported, timezone parsing is necessarily sloppy: it can be a single or multi-letter suffix, an hour or hour:minute offset, a name "America/Denver" (or even a filename in the case of the TZ
variable).
Your 2018-12-10T00:00:00
version doesn't work because "T" is just a delimiter, not a timezone, adding "Z" at the end makes that work (subject to correctness of chosen zone) as expected too.
See:
https://www.gnu.org/software/tar/manual/html_node/Date-input-formats.html
and in particular section 7.7.
1
Other options include:date -d "2018-12-10 00:00:00 now -5 hours
, ortoday
or0 hour
instead ofnow
, anything that tellsdate
that the token after the time is not a timezone offset.
– Stéphane Chazelas
Jan 31 at 14:03
Or, for the sake of thoroughness, leave nothing after the date-time by reordering args: date -d "-5 hours 2018-12-10 00:00:00"`
– B Layer
Mar 7 at 19:21
add a comment |
This solution is easy to understand, but a little more complicated, so I show it as a shellscript.
- convert to 'seconds since 1970-01-01 00:00:00 UTC'
- add or subtract the difference
- convert back to a human readable format with a final
date
command line
Shellscript:
#!/bin/bash
startdate="2018-12-10 00:00:00"
ddif="0" # days
diff="-5:-20:-5" # hours:minutes:seconds
#-----------------------------------------------------------------------------
ss1970in=$(date -d "$startdate" "+%s") # seconds since 1970-01-01 00:00:00 UTC
printf "%11sn" "$ss1970in"
h=${diff%%:*}
m=${diff#*:}
m=${m%:*}
s=${diff##*:}
difs=$(( (((ddif*24+h)*60)+m)*60+s ))
printf "%11sn" "$difs"
ss1970ut=$((ss1970in + difs)) # add/subtract the time difference
printf "%11sn" "$ss1970ut"
date -d "@$ss1970ut" "+%Y-%m-%d %H:%M:%S"
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "106"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f497639%2fsubtract-time-using-date-and-bash%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
That last example should have clarified things for you: timezones.
$ TZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_03:00:00
$ TZ=Asia/Colombo date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_08:30:00
As the output clearly varies by the timezone, I'd suspect some non-obvious default taken for a time string without a timezone specified. Testing a couple of values, it seems to be UTC-05:00, though I'm not sure what that is.
$ TZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S%Z
2019-01-19_08:00:00UTC
$ TZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S%Z
2019-01-19_03:00:00UTC
$ TZ=UTC date -d "2019-01-19T05:00:00" +%Y-%m-%d_%H:%M:%S%Z
2019-01-19_05:00:00UTC
It's only used when performing date arithmetic.
It seems the issue here is that - 2 hours
is not taken as arithmetic, but as a timezone specifier:
# TZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S%Z --debug
date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC-02
date: parsed relative part: +1 hour(s)
date: input timezone: parsed date/time string (-02)
date: using specified time as starting value: '05:00:00'
date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02'
date: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02' = 1547881200 epoch-seconds
date: after time adjustment (+1 hours, +0 minutes, +0 seconds, +0 ns),
date: new time = 1547884800 epoch-seconds
date: timezone: TZ="UTC" environment value
date: final: 1547884800.000000000 (epoch-seconds)
date: final: (Y-M-D) 2019-01-19 08:00:00 (UTC)
date: final: (Y-M-D) 2019-01-19 08:00:00 (UTC+00)
2019-01-19_08:00:00UTC
So, not only is no arithmetic being done, there seems to be a daylight savings 1 hour adjustment on the time, leading to a somewhat nonsensical time for us.
This also holds for addition:
# TZ=UTC date -d "2019-01-19T05:00:00 + 5:30 hours" +%Y-%m-%d_%H:%M:%S%Z --debug
date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC+05:30
date: parsed relative part: +1 hour(s)
date: input timezone: parsed date/time string (+05:30)
date: using specified time as starting value: '05:00:00'
date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=+05:30'
date: '(Y-M-D) 2019-01-19 05:00:00 TZ=+05:30' = 1547854200 epoch-seconds
date: after time adjustment (+1 hours, +0 minutes, +0 seconds, +0 ns),
date: new time = 1547857800 epoch-seconds
date: timezone: TZ="UTC" environment value
date: final: 1547857800.000000000 (epoch-seconds)
date: final: (Y-M-D) 2019-01-19 00:30:00 (UTC)
date: final: (Y-M-D) 2019-01-19 00:30:00 (UTC+00)
2019-01-19_00:30:00UTC
Debugging a bit more, the parsing seems to be: 2019-01-19T05:00:00 - 2
(-2
being the timezone), and hours
(= 1 hour), with an implied addition. It becomes easier to see if you use minutes instead:
# TZ=UTC date -d "2019-01-19T05:00:00 - 2 minutes" +%Y-%m-%d_%H:%M:%S%Z --debug
date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC-02
date: parsed relative part: +1 minutes
date: input timezone: parsed date/time string (-02)
date: using specified time as starting value: '05:00:00'
date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02'
date: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02' = 1547881200 epoch-seconds
date: after time adjustment (+0 hours, +1 minutes, +0 seconds, +0 ns),
date: new time = 1547881260 epoch-seconds
date: timezone: TZ="UTC" environment value
date: final: 1547881260.000000000 (epoch-seconds)
date: final: (Y-M-D) 2019-01-19 07:01:00 (UTC)
date: final: (Y-M-D) 2019-01-19 07:01:00 (UTC+00)
2019-01-19_07:01:00UTC
So, well, date arithmetic is being done, just not the one that we asked for. ¯(ツ)/¯
1
@confetti it does indeed; I think this default timezone is used only when adding/subtracting (comparingTZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
vsTZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S
)
– Olorin
Jan 30 at 8:54
2
Could be a possible bug indate
, as per the ISO 8601 standard, if no timezone is supplied, local time(zone) should be assumed, which in case of an arithmetic operation, it is not. Very strange issue to me though.
– confetti
Jan 30 at 8:57
1
@confetti found the problem:- 2 hours
is taken as the timezone specifier here.
– Olorin
Jan 30 at 9:17
2
Wow. Now that somehow makes sense. Well, at least it explains it. Thank you a lot for figuring that out. To me it sounds like their parser needs an update though, as clearly with a format and whitespace like this you do not want to specify the timezone by the ` - 2 hours` and it's surely causing confusion. If they don't want to update the parser, at least the manual should get a note about this.
– confetti
Jan 30 at 9:19
1
Today I learned about date's--debug
option! Great explanation.
– Jeff Schaller♦
Jan 30 at 17:26
|
show 1 more comment
That last example should have clarified things for you: timezones.
$ TZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_03:00:00
$ TZ=Asia/Colombo date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_08:30:00
As the output clearly varies by the timezone, I'd suspect some non-obvious default taken for a time string without a timezone specified. Testing a couple of values, it seems to be UTC-05:00, though I'm not sure what that is.
$ TZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S%Z
2019-01-19_08:00:00UTC
$ TZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S%Z
2019-01-19_03:00:00UTC
$ TZ=UTC date -d "2019-01-19T05:00:00" +%Y-%m-%d_%H:%M:%S%Z
2019-01-19_05:00:00UTC
It's only used when performing date arithmetic.
It seems the issue here is that - 2 hours
is not taken as arithmetic, but as a timezone specifier:
# TZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S%Z --debug
date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC-02
date: parsed relative part: +1 hour(s)
date: input timezone: parsed date/time string (-02)
date: using specified time as starting value: '05:00:00'
date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02'
date: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02' = 1547881200 epoch-seconds
date: after time adjustment (+1 hours, +0 minutes, +0 seconds, +0 ns),
date: new time = 1547884800 epoch-seconds
date: timezone: TZ="UTC" environment value
date: final: 1547884800.000000000 (epoch-seconds)
date: final: (Y-M-D) 2019-01-19 08:00:00 (UTC)
date: final: (Y-M-D) 2019-01-19 08:00:00 (UTC+00)
2019-01-19_08:00:00UTC
So, not only is no arithmetic being done, there seems to be a daylight savings 1 hour adjustment on the time, leading to a somewhat nonsensical time for us.
This also holds for addition:
# TZ=UTC date -d "2019-01-19T05:00:00 + 5:30 hours" +%Y-%m-%d_%H:%M:%S%Z --debug
date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC+05:30
date: parsed relative part: +1 hour(s)
date: input timezone: parsed date/time string (+05:30)
date: using specified time as starting value: '05:00:00'
date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=+05:30'
date: '(Y-M-D) 2019-01-19 05:00:00 TZ=+05:30' = 1547854200 epoch-seconds
date: after time adjustment (+1 hours, +0 minutes, +0 seconds, +0 ns),
date: new time = 1547857800 epoch-seconds
date: timezone: TZ="UTC" environment value
date: final: 1547857800.000000000 (epoch-seconds)
date: final: (Y-M-D) 2019-01-19 00:30:00 (UTC)
date: final: (Y-M-D) 2019-01-19 00:30:00 (UTC+00)
2019-01-19_00:30:00UTC
Debugging a bit more, the parsing seems to be: 2019-01-19T05:00:00 - 2
(-2
being the timezone), and hours
(= 1 hour), with an implied addition. It becomes easier to see if you use minutes instead:
# TZ=UTC date -d "2019-01-19T05:00:00 - 2 minutes" +%Y-%m-%d_%H:%M:%S%Z --debug
date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC-02
date: parsed relative part: +1 minutes
date: input timezone: parsed date/time string (-02)
date: using specified time as starting value: '05:00:00'
date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02'
date: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02' = 1547881200 epoch-seconds
date: after time adjustment (+0 hours, +1 minutes, +0 seconds, +0 ns),
date: new time = 1547881260 epoch-seconds
date: timezone: TZ="UTC" environment value
date: final: 1547881260.000000000 (epoch-seconds)
date: final: (Y-M-D) 2019-01-19 07:01:00 (UTC)
date: final: (Y-M-D) 2019-01-19 07:01:00 (UTC+00)
2019-01-19_07:01:00UTC
So, well, date arithmetic is being done, just not the one that we asked for. ¯(ツ)/¯
1
@confetti it does indeed; I think this default timezone is used only when adding/subtracting (comparingTZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
vsTZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S
)
– Olorin
Jan 30 at 8:54
2
Could be a possible bug indate
, as per the ISO 8601 standard, if no timezone is supplied, local time(zone) should be assumed, which in case of an arithmetic operation, it is not. Very strange issue to me though.
– confetti
Jan 30 at 8:57
1
@confetti found the problem:- 2 hours
is taken as the timezone specifier here.
– Olorin
Jan 30 at 9:17
2
Wow. Now that somehow makes sense. Well, at least it explains it. Thank you a lot for figuring that out. To me it sounds like their parser needs an update though, as clearly with a format and whitespace like this you do not want to specify the timezone by the ` - 2 hours` and it's surely causing confusion. If they don't want to update the parser, at least the manual should get a note about this.
– confetti
Jan 30 at 9:19
1
Today I learned about date's--debug
option! Great explanation.
– Jeff Schaller♦
Jan 30 at 17:26
|
show 1 more comment
That last example should have clarified things for you: timezones.
$ TZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_03:00:00
$ TZ=Asia/Colombo date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_08:30:00
As the output clearly varies by the timezone, I'd suspect some non-obvious default taken for a time string without a timezone specified. Testing a couple of values, it seems to be UTC-05:00, though I'm not sure what that is.
$ TZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S%Z
2019-01-19_08:00:00UTC
$ TZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S%Z
2019-01-19_03:00:00UTC
$ TZ=UTC date -d "2019-01-19T05:00:00" +%Y-%m-%d_%H:%M:%S%Z
2019-01-19_05:00:00UTC
It's only used when performing date arithmetic.
It seems the issue here is that - 2 hours
is not taken as arithmetic, but as a timezone specifier:
# TZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S%Z --debug
date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC-02
date: parsed relative part: +1 hour(s)
date: input timezone: parsed date/time string (-02)
date: using specified time as starting value: '05:00:00'
date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02'
date: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02' = 1547881200 epoch-seconds
date: after time adjustment (+1 hours, +0 minutes, +0 seconds, +0 ns),
date: new time = 1547884800 epoch-seconds
date: timezone: TZ="UTC" environment value
date: final: 1547884800.000000000 (epoch-seconds)
date: final: (Y-M-D) 2019-01-19 08:00:00 (UTC)
date: final: (Y-M-D) 2019-01-19 08:00:00 (UTC+00)
2019-01-19_08:00:00UTC
So, not only is no arithmetic being done, there seems to be a daylight savings 1 hour adjustment on the time, leading to a somewhat nonsensical time for us.
This also holds for addition:
# TZ=UTC date -d "2019-01-19T05:00:00 + 5:30 hours" +%Y-%m-%d_%H:%M:%S%Z --debug
date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC+05:30
date: parsed relative part: +1 hour(s)
date: input timezone: parsed date/time string (+05:30)
date: using specified time as starting value: '05:00:00'
date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=+05:30'
date: '(Y-M-D) 2019-01-19 05:00:00 TZ=+05:30' = 1547854200 epoch-seconds
date: after time adjustment (+1 hours, +0 minutes, +0 seconds, +0 ns),
date: new time = 1547857800 epoch-seconds
date: timezone: TZ="UTC" environment value
date: final: 1547857800.000000000 (epoch-seconds)
date: final: (Y-M-D) 2019-01-19 00:30:00 (UTC)
date: final: (Y-M-D) 2019-01-19 00:30:00 (UTC+00)
2019-01-19_00:30:00UTC
Debugging a bit more, the parsing seems to be: 2019-01-19T05:00:00 - 2
(-2
being the timezone), and hours
(= 1 hour), with an implied addition. It becomes easier to see if you use minutes instead:
# TZ=UTC date -d "2019-01-19T05:00:00 - 2 minutes" +%Y-%m-%d_%H:%M:%S%Z --debug
date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC-02
date: parsed relative part: +1 minutes
date: input timezone: parsed date/time string (-02)
date: using specified time as starting value: '05:00:00'
date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02'
date: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02' = 1547881200 epoch-seconds
date: after time adjustment (+0 hours, +1 minutes, +0 seconds, +0 ns),
date: new time = 1547881260 epoch-seconds
date: timezone: TZ="UTC" environment value
date: final: 1547881260.000000000 (epoch-seconds)
date: final: (Y-M-D) 2019-01-19 07:01:00 (UTC)
date: final: (Y-M-D) 2019-01-19 07:01:00 (UTC+00)
2019-01-19_07:01:00UTC
So, well, date arithmetic is being done, just not the one that we asked for. ¯(ツ)/¯
That last example should have clarified things for you: timezones.
$ TZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_03:00:00
$ TZ=Asia/Colombo date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_08:30:00
As the output clearly varies by the timezone, I'd suspect some non-obvious default taken for a time string without a timezone specified. Testing a couple of values, it seems to be UTC-05:00, though I'm not sure what that is.
$ TZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S%Z
2019-01-19_08:00:00UTC
$ TZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S%Z
2019-01-19_03:00:00UTC
$ TZ=UTC date -d "2019-01-19T05:00:00" +%Y-%m-%d_%H:%M:%S%Z
2019-01-19_05:00:00UTC
It's only used when performing date arithmetic.
It seems the issue here is that - 2 hours
is not taken as arithmetic, but as a timezone specifier:
# TZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S%Z --debug
date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC-02
date: parsed relative part: +1 hour(s)
date: input timezone: parsed date/time string (-02)
date: using specified time as starting value: '05:00:00'
date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02'
date: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02' = 1547881200 epoch-seconds
date: after time adjustment (+1 hours, +0 minutes, +0 seconds, +0 ns),
date: new time = 1547884800 epoch-seconds
date: timezone: TZ="UTC" environment value
date: final: 1547884800.000000000 (epoch-seconds)
date: final: (Y-M-D) 2019-01-19 08:00:00 (UTC)
date: final: (Y-M-D) 2019-01-19 08:00:00 (UTC+00)
2019-01-19_08:00:00UTC
So, not only is no arithmetic being done, there seems to be a daylight savings 1 hour adjustment on the time, leading to a somewhat nonsensical time for us.
This also holds for addition:
# TZ=UTC date -d "2019-01-19T05:00:00 + 5:30 hours" +%Y-%m-%d_%H:%M:%S%Z --debug
date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC+05:30
date: parsed relative part: +1 hour(s)
date: input timezone: parsed date/time string (+05:30)
date: using specified time as starting value: '05:00:00'
date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=+05:30'
date: '(Y-M-D) 2019-01-19 05:00:00 TZ=+05:30' = 1547854200 epoch-seconds
date: after time adjustment (+1 hours, +0 minutes, +0 seconds, +0 ns),
date: new time = 1547857800 epoch-seconds
date: timezone: TZ="UTC" environment value
date: final: 1547857800.000000000 (epoch-seconds)
date: final: (Y-M-D) 2019-01-19 00:30:00 (UTC)
date: final: (Y-M-D) 2019-01-19 00:30:00 (UTC+00)
2019-01-19_00:30:00UTC
Debugging a bit more, the parsing seems to be: 2019-01-19T05:00:00 - 2
(-2
being the timezone), and hours
(= 1 hour), with an implied addition. It becomes easier to see if you use minutes instead:
# TZ=UTC date -d "2019-01-19T05:00:00 - 2 minutes" +%Y-%m-%d_%H:%M:%S%Z --debug
date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC-02
date: parsed relative part: +1 minutes
date: input timezone: parsed date/time string (-02)
date: using specified time as starting value: '05:00:00'
date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02'
date: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02' = 1547881200 epoch-seconds
date: after time adjustment (+0 hours, +1 minutes, +0 seconds, +0 ns),
date: new time = 1547881260 epoch-seconds
date: timezone: TZ="UTC" environment value
date: final: 1547881260.000000000 (epoch-seconds)
date: final: (Y-M-D) 2019-01-19 07:01:00 (UTC)
date: final: (Y-M-D) 2019-01-19 07:01:00 (UTC+00)
2019-01-19_07:01:00UTC
So, well, date arithmetic is being done, just not the one that we asked for. ¯(ツ)/¯
edited Jan 30 at 9:23
answered Jan 30 at 8:51


OlorinOlorin
3,9481723
3,9481723
1
@confetti it does indeed; I think this default timezone is used only when adding/subtracting (comparingTZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
vsTZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S
)
– Olorin
Jan 30 at 8:54
2
Could be a possible bug indate
, as per the ISO 8601 standard, if no timezone is supplied, local time(zone) should be assumed, which in case of an arithmetic operation, it is not. Very strange issue to me though.
– confetti
Jan 30 at 8:57
1
@confetti found the problem:- 2 hours
is taken as the timezone specifier here.
– Olorin
Jan 30 at 9:17
2
Wow. Now that somehow makes sense. Well, at least it explains it. Thank you a lot for figuring that out. To me it sounds like their parser needs an update though, as clearly with a format and whitespace like this you do not want to specify the timezone by the ` - 2 hours` and it's surely causing confusion. If they don't want to update the parser, at least the manual should get a note about this.
– confetti
Jan 30 at 9:19
1
Today I learned about date's--debug
option! Great explanation.
– Jeff Schaller♦
Jan 30 at 17:26
|
show 1 more comment
1
@confetti it does indeed; I think this default timezone is used only when adding/subtracting (comparingTZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
vsTZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S
)
– Olorin
Jan 30 at 8:54
2
Could be a possible bug indate
, as per the ISO 8601 standard, if no timezone is supplied, local time(zone) should be assumed, which in case of an arithmetic operation, it is not. Very strange issue to me though.
– confetti
Jan 30 at 8:57
1
@confetti found the problem:- 2 hours
is taken as the timezone specifier here.
– Olorin
Jan 30 at 9:17
2
Wow. Now that somehow makes sense. Well, at least it explains it. Thank you a lot for figuring that out. To me it sounds like their parser needs an update though, as clearly with a format and whitespace like this you do not want to specify the timezone by the ` - 2 hours` and it's surely causing confusion. If they don't want to update the parser, at least the manual should get a note about this.
– confetti
Jan 30 at 9:19
1
Today I learned about date's--debug
option! Great explanation.
– Jeff Schaller♦
Jan 30 at 17:26
1
1
@confetti it does indeed; I think this default timezone is used only when adding/subtracting (comparing
TZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
vs TZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S
)– Olorin
Jan 30 at 8:54
@confetti it does indeed; I think this default timezone is used only when adding/subtracting (comparing
TZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
vs TZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S
)– Olorin
Jan 30 at 8:54
2
2
Could be a possible bug in
date
, as per the ISO 8601 standard, if no timezone is supplied, local time(zone) should be assumed, which in case of an arithmetic operation, it is not. Very strange issue to me though.– confetti
Jan 30 at 8:57
Could be a possible bug in
date
, as per the ISO 8601 standard, if no timezone is supplied, local time(zone) should be assumed, which in case of an arithmetic operation, it is not. Very strange issue to me though.– confetti
Jan 30 at 8:57
1
1
@confetti found the problem:
- 2 hours
is taken as the timezone specifier here.– Olorin
Jan 30 at 9:17
@confetti found the problem:
- 2 hours
is taken as the timezone specifier here.– Olorin
Jan 30 at 9:17
2
2
Wow. Now that somehow makes sense. Well, at least it explains it. Thank you a lot for figuring that out. To me it sounds like their parser needs an update though, as clearly with a format and whitespace like this you do not want to specify the timezone by the ` - 2 hours` and it's surely causing confusion. If they don't want to update the parser, at least the manual should get a note about this.
– confetti
Jan 30 at 9:19
Wow. Now that somehow makes sense. Well, at least it explains it. Thank you a lot for figuring that out. To me it sounds like their parser needs an update though, as clearly with a format and whitespace like this you do not want to specify the timezone by the ` - 2 hours` and it's surely causing confusion. If they don't want to update the parser, at least the manual should get a note about this.
– confetti
Jan 30 at 9:19
1
1
Today I learned about date's
--debug
option! Great explanation.– Jeff Schaller♦
Jan 30 at 17:26
Today I learned about date's
--debug
option! Great explanation.– Jeff Schaller♦
Jan 30 at 17:26
|
show 1 more comment
It works correctly when you convert the input date to ISO 8601 first:
$ date -d "$(date -Iseconds -d "2018-12-10 00:00:00") - 5 hours - 20 minutes - 5 seconds"
So 9. Dez 18:39:55 CET 2018
Thank you, that does work indeed, but is there any explanation for this? I've added some more info about the ISO 8601 thing to my question, and I really don't see wheredate
would mess this up as without any subtractions supplied, the timezone is left untouched and everything is as expected too without having to supply any timezone information or conversion.
– confetti
Jan 30 at 8:49
I cannot tell, sorry. If someone else could answer this I'd be happy because I was wondering too.
– RoVo
Jan 30 at 8:50
I'd be glad too but I'll accept this for now because it does fix my issue!
– confetti
Jan 30 at 8:54
3
This works becausedate -I
also outputs the timezone specifier (e.g.2018-12-10T00:00:00+02:00
) which fixes the issue described in Olorin's answer
– ilkkachu
Jan 30 at 19:22
add a comment |
It works correctly when you convert the input date to ISO 8601 first:
$ date -d "$(date -Iseconds -d "2018-12-10 00:00:00") - 5 hours - 20 minutes - 5 seconds"
So 9. Dez 18:39:55 CET 2018
Thank you, that does work indeed, but is there any explanation for this? I've added some more info about the ISO 8601 thing to my question, and I really don't see wheredate
would mess this up as without any subtractions supplied, the timezone is left untouched and everything is as expected too without having to supply any timezone information or conversion.
– confetti
Jan 30 at 8:49
I cannot tell, sorry. If someone else could answer this I'd be happy because I was wondering too.
– RoVo
Jan 30 at 8:50
I'd be glad too but I'll accept this for now because it does fix my issue!
– confetti
Jan 30 at 8:54
3
This works becausedate -I
also outputs the timezone specifier (e.g.2018-12-10T00:00:00+02:00
) which fixes the issue described in Olorin's answer
– ilkkachu
Jan 30 at 19:22
add a comment |
It works correctly when you convert the input date to ISO 8601 first:
$ date -d "$(date -Iseconds -d "2018-12-10 00:00:00") - 5 hours - 20 minutes - 5 seconds"
So 9. Dez 18:39:55 CET 2018
It works correctly when you convert the input date to ISO 8601 first:
$ date -d "$(date -Iseconds -d "2018-12-10 00:00:00") - 5 hours - 20 minutes - 5 seconds"
So 9. Dez 18:39:55 CET 2018
answered Jan 30 at 8:47
RoVoRoVo
3,442317
3,442317
Thank you, that does work indeed, but is there any explanation for this? I've added some more info about the ISO 8601 thing to my question, and I really don't see wheredate
would mess this up as without any subtractions supplied, the timezone is left untouched and everything is as expected too without having to supply any timezone information or conversion.
– confetti
Jan 30 at 8:49
I cannot tell, sorry. If someone else could answer this I'd be happy because I was wondering too.
– RoVo
Jan 30 at 8:50
I'd be glad too but I'll accept this for now because it does fix my issue!
– confetti
Jan 30 at 8:54
3
This works becausedate -I
also outputs the timezone specifier (e.g.2018-12-10T00:00:00+02:00
) which fixes the issue described in Olorin's answer
– ilkkachu
Jan 30 at 19:22
add a comment |
Thank you, that does work indeed, but is there any explanation for this? I've added some more info about the ISO 8601 thing to my question, and I really don't see wheredate
would mess this up as without any subtractions supplied, the timezone is left untouched and everything is as expected too without having to supply any timezone information or conversion.
– confetti
Jan 30 at 8:49
I cannot tell, sorry. If someone else could answer this I'd be happy because I was wondering too.
– RoVo
Jan 30 at 8:50
I'd be glad too but I'll accept this for now because it does fix my issue!
– confetti
Jan 30 at 8:54
3
This works becausedate -I
also outputs the timezone specifier (e.g.2018-12-10T00:00:00+02:00
) which fixes the issue described in Olorin's answer
– ilkkachu
Jan 30 at 19:22
Thank you, that does work indeed, but is there any explanation for this? I've added some more info about the ISO 8601 thing to my question, and I really don't see where
date
would mess this up as without any subtractions supplied, the timezone is left untouched and everything is as expected too without having to supply any timezone information or conversion.– confetti
Jan 30 at 8:49
Thank you, that does work indeed, but is there any explanation for this? I've added some more info about the ISO 8601 thing to my question, and I really don't see where
date
would mess this up as without any subtractions supplied, the timezone is left untouched and everything is as expected too without having to supply any timezone information or conversion.– confetti
Jan 30 at 8:49
I cannot tell, sorry. If someone else could answer this I'd be happy because I was wondering too.
– RoVo
Jan 30 at 8:50
I cannot tell, sorry. If someone else could answer this I'd be happy because I was wondering too.
– RoVo
Jan 30 at 8:50
I'd be glad too but I'll accept this for now because it does fix my issue!
– confetti
Jan 30 at 8:54
I'd be glad too but I'll accept this for now because it does fix my issue!
– confetti
Jan 30 at 8:54
3
3
This works because
date -I
also outputs the timezone specifier (e.g. 2018-12-10T00:00:00+02:00
) which fixes the issue described in Olorin's answer– ilkkachu
Jan 30 at 19:22
This works because
date -I
also outputs the timezone specifier (e.g. 2018-12-10T00:00:00+02:00
) which fixes the issue described in Olorin's answer– ilkkachu
Jan 30 at 19:22
add a comment |
TLDR: This is not a bug. You've just found one of the subtle but documented behaviours of date
. When performing time arithmetic with date
, use a timezone-independent format (like Unix time) or read very carefully the documentation to know how to properly use this command.
GNU date
uses your system settings (the TZ
environment variable or, if unset, the system defaults) to determine the timezone of both the date feeded with the -d
/--date
option and the date reported by the +format
argument. The --date
option also let you override the timezone for its own option-argument but it doesn't override the timezone of +format
. That's the root of the confusion, IMHO.
Considering that my timezone is UTC-6, compare the following commands:
$ date -d '1970-01-01 00:00:00' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-01 00:00:00 -06:00
Unix: 21600
$ date -d '1970-01-01 00:00:00 UTC' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1969-12-31 18:00:00 -06:00
Unix: 0
$ TZ='UTC0' date -d '1970-01-01 00:00:00 UTC' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-01 00:00:00 +00:00
Unix: 0
The first one uses my timezone for both -d
and +format
. The second one uses UTC for -d
but my timezone for +format
. The third one uses UTC for both.
Now, compare the following simple operations:
$ date -d '1970-01-01 00:00:00 UTC +1 day' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-01 18:00:00 -06:00
Unix: 86400
$ TZ='UTC0' date -d '1970-01-01 00:00:00 UTC +1 day' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-02 00:00:00 +00:00
Unix: 86400
Even if the Unix time is telling me the same thing, the "Normal" time differs because of my own timezone.
If I wanted to do the same operation but using exclusively my timezone:
$ TZ='CST+6' date -d '1970-01-01 00:00:00 -06:00 +1 day' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-02 00:00:00 -06:00
Unix: 108000
3
Upvoted for mentioning epoch/Unix time, which imo is the only sane way to do time arithmetic
– Rui F Ribeiro
Jan 30 at 9:58
1
TL;DR If you just know your local time offset from Zulu time (e.g. west coast USA is -8 hours or-08:00
), simply append that to input date-time...nothing else to fiddle with. Example:date -d '2019-02-28 14:05:36-08:00 +2 days 4 hours 3 seconds' +'local: %F %T'
gives local: 2019-03-02 18:05:36
– B Layer
Feb 28 at 22:52
@BLayer You're right, it works as expected in that scenario. But imagine the situation where a given script using that approach is executed in a place with a different timezone. The output, while technically correct, may look wrong depending on the information provided by the+format
argument. For instance, on my system, the same command outputs:local: 2019-03-02 20:05:39
(if I add%:z
to+format
, it becomes obvious that the info is correct and the discrepancy is due to the timezones).
– nxnev
Mar 1 at 1:45
@BLayer IMHO, a better general approach would be to use the same timezone for both-d
and+format
or Unix time, as I said in the answer, to avoid unexpected results.
– nxnev
Mar 1 at 1:45
1
@nxnev Agreed, if you're writing a script to be published/shared. The opening words "if you know your own timezone", besides having a literal meaning, are supposed to imply casual/personal use. Someone publishing a script relying on something as flimsy as knowing just their own system's tz probably shouldn't be in the script sharing game. :) On the other hand I do/would use my own command on all my personal environments.
– B Layer
Mar 1 at 2:17
add a comment |
TLDR: This is not a bug. You've just found one of the subtle but documented behaviours of date
. When performing time arithmetic with date
, use a timezone-independent format (like Unix time) or read very carefully the documentation to know how to properly use this command.
GNU date
uses your system settings (the TZ
environment variable or, if unset, the system defaults) to determine the timezone of both the date feeded with the -d
/--date
option and the date reported by the +format
argument. The --date
option also let you override the timezone for its own option-argument but it doesn't override the timezone of +format
. That's the root of the confusion, IMHO.
Considering that my timezone is UTC-6, compare the following commands:
$ date -d '1970-01-01 00:00:00' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-01 00:00:00 -06:00
Unix: 21600
$ date -d '1970-01-01 00:00:00 UTC' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1969-12-31 18:00:00 -06:00
Unix: 0
$ TZ='UTC0' date -d '1970-01-01 00:00:00 UTC' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-01 00:00:00 +00:00
Unix: 0
The first one uses my timezone for both -d
and +format
. The second one uses UTC for -d
but my timezone for +format
. The third one uses UTC for both.
Now, compare the following simple operations:
$ date -d '1970-01-01 00:00:00 UTC +1 day' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-01 18:00:00 -06:00
Unix: 86400
$ TZ='UTC0' date -d '1970-01-01 00:00:00 UTC +1 day' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-02 00:00:00 +00:00
Unix: 86400
Even if the Unix time is telling me the same thing, the "Normal" time differs because of my own timezone.
If I wanted to do the same operation but using exclusively my timezone:
$ TZ='CST+6' date -d '1970-01-01 00:00:00 -06:00 +1 day' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-02 00:00:00 -06:00
Unix: 108000
3
Upvoted for mentioning epoch/Unix time, which imo is the only sane way to do time arithmetic
– Rui F Ribeiro
Jan 30 at 9:58
1
TL;DR If you just know your local time offset from Zulu time (e.g. west coast USA is -8 hours or-08:00
), simply append that to input date-time...nothing else to fiddle with. Example:date -d '2019-02-28 14:05:36-08:00 +2 days 4 hours 3 seconds' +'local: %F %T'
gives local: 2019-03-02 18:05:36
– B Layer
Feb 28 at 22:52
@BLayer You're right, it works as expected in that scenario. But imagine the situation where a given script using that approach is executed in a place with a different timezone. The output, while technically correct, may look wrong depending on the information provided by the+format
argument. For instance, on my system, the same command outputs:local: 2019-03-02 20:05:39
(if I add%:z
to+format
, it becomes obvious that the info is correct and the discrepancy is due to the timezones).
– nxnev
Mar 1 at 1:45
@BLayer IMHO, a better general approach would be to use the same timezone for both-d
and+format
or Unix time, as I said in the answer, to avoid unexpected results.
– nxnev
Mar 1 at 1:45
1
@nxnev Agreed, if you're writing a script to be published/shared. The opening words "if you know your own timezone", besides having a literal meaning, are supposed to imply casual/personal use. Someone publishing a script relying on something as flimsy as knowing just their own system's tz probably shouldn't be in the script sharing game. :) On the other hand I do/would use my own command on all my personal environments.
– B Layer
Mar 1 at 2:17
add a comment |
TLDR: This is not a bug. You've just found one of the subtle but documented behaviours of date
. When performing time arithmetic with date
, use a timezone-independent format (like Unix time) or read very carefully the documentation to know how to properly use this command.
GNU date
uses your system settings (the TZ
environment variable or, if unset, the system defaults) to determine the timezone of both the date feeded with the -d
/--date
option and the date reported by the +format
argument. The --date
option also let you override the timezone for its own option-argument but it doesn't override the timezone of +format
. That's the root of the confusion, IMHO.
Considering that my timezone is UTC-6, compare the following commands:
$ date -d '1970-01-01 00:00:00' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-01 00:00:00 -06:00
Unix: 21600
$ date -d '1970-01-01 00:00:00 UTC' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1969-12-31 18:00:00 -06:00
Unix: 0
$ TZ='UTC0' date -d '1970-01-01 00:00:00 UTC' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-01 00:00:00 +00:00
Unix: 0
The first one uses my timezone for both -d
and +format
. The second one uses UTC for -d
but my timezone for +format
. The third one uses UTC for both.
Now, compare the following simple operations:
$ date -d '1970-01-01 00:00:00 UTC +1 day' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-01 18:00:00 -06:00
Unix: 86400
$ TZ='UTC0' date -d '1970-01-01 00:00:00 UTC +1 day' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-02 00:00:00 +00:00
Unix: 86400
Even if the Unix time is telling me the same thing, the "Normal" time differs because of my own timezone.
If I wanted to do the same operation but using exclusively my timezone:
$ TZ='CST+6' date -d '1970-01-01 00:00:00 -06:00 +1 day' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-02 00:00:00 -06:00
Unix: 108000
TLDR: This is not a bug. You've just found one of the subtle but documented behaviours of date
. When performing time arithmetic with date
, use a timezone-independent format (like Unix time) or read very carefully the documentation to know how to properly use this command.
GNU date
uses your system settings (the TZ
environment variable or, if unset, the system defaults) to determine the timezone of both the date feeded with the -d
/--date
option and the date reported by the +format
argument. The --date
option also let you override the timezone for its own option-argument but it doesn't override the timezone of +format
. That's the root of the confusion, IMHO.
Considering that my timezone is UTC-6, compare the following commands:
$ date -d '1970-01-01 00:00:00' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-01 00:00:00 -06:00
Unix: 21600
$ date -d '1970-01-01 00:00:00 UTC' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1969-12-31 18:00:00 -06:00
Unix: 0
$ TZ='UTC0' date -d '1970-01-01 00:00:00 UTC' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-01 00:00:00 +00:00
Unix: 0
The first one uses my timezone for both -d
and +format
. The second one uses UTC for -d
but my timezone for +format
. The third one uses UTC for both.
Now, compare the following simple operations:
$ date -d '1970-01-01 00:00:00 UTC +1 day' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-01 18:00:00 -06:00
Unix: 86400
$ TZ='UTC0' date -d '1970-01-01 00:00:00 UTC +1 day' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-02 00:00:00 +00:00
Unix: 86400
Even if the Unix time is telling me the same thing, the "Normal" time differs because of my own timezone.
If I wanted to do the same operation but using exclusively my timezone:
$ TZ='CST+6' date -d '1970-01-01 00:00:00 -06:00 +1 day' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-02 00:00:00 -06:00
Unix: 108000
edited Jan 30 at 13:59
answered Jan 30 at 9:47


nxnevnxnev
2,9262524
2,9262524
3
Upvoted for mentioning epoch/Unix time, which imo is the only sane way to do time arithmetic
– Rui F Ribeiro
Jan 30 at 9:58
1
TL;DR If you just know your local time offset from Zulu time (e.g. west coast USA is -8 hours or-08:00
), simply append that to input date-time...nothing else to fiddle with. Example:date -d '2019-02-28 14:05:36-08:00 +2 days 4 hours 3 seconds' +'local: %F %T'
gives local: 2019-03-02 18:05:36
– B Layer
Feb 28 at 22:52
@BLayer You're right, it works as expected in that scenario. But imagine the situation where a given script using that approach is executed in a place with a different timezone. The output, while technically correct, may look wrong depending on the information provided by the+format
argument. For instance, on my system, the same command outputs:local: 2019-03-02 20:05:39
(if I add%:z
to+format
, it becomes obvious that the info is correct and the discrepancy is due to the timezones).
– nxnev
Mar 1 at 1:45
@BLayer IMHO, a better general approach would be to use the same timezone for both-d
and+format
or Unix time, as I said in the answer, to avoid unexpected results.
– nxnev
Mar 1 at 1:45
1
@nxnev Agreed, if you're writing a script to be published/shared. The opening words "if you know your own timezone", besides having a literal meaning, are supposed to imply casual/personal use. Someone publishing a script relying on something as flimsy as knowing just their own system's tz probably shouldn't be in the script sharing game. :) On the other hand I do/would use my own command on all my personal environments.
– B Layer
Mar 1 at 2:17
add a comment |
3
Upvoted for mentioning epoch/Unix time, which imo is the only sane way to do time arithmetic
– Rui F Ribeiro
Jan 30 at 9:58
1
TL;DR If you just know your local time offset from Zulu time (e.g. west coast USA is -8 hours or-08:00
), simply append that to input date-time...nothing else to fiddle with. Example:date -d '2019-02-28 14:05:36-08:00 +2 days 4 hours 3 seconds' +'local: %F %T'
gives local: 2019-03-02 18:05:36
– B Layer
Feb 28 at 22:52
@BLayer You're right, it works as expected in that scenario. But imagine the situation where a given script using that approach is executed in a place with a different timezone. The output, while technically correct, may look wrong depending on the information provided by the+format
argument. For instance, on my system, the same command outputs:local: 2019-03-02 20:05:39
(if I add%:z
to+format
, it becomes obvious that the info is correct and the discrepancy is due to the timezones).
– nxnev
Mar 1 at 1:45
@BLayer IMHO, a better general approach would be to use the same timezone for both-d
and+format
or Unix time, as I said in the answer, to avoid unexpected results.
– nxnev
Mar 1 at 1:45
1
@nxnev Agreed, if you're writing a script to be published/shared. The opening words "if you know your own timezone", besides having a literal meaning, are supposed to imply casual/personal use. Someone publishing a script relying on something as flimsy as knowing just their own system's tz probably shouldn't be in the script sharing game. :) On the other hand I do/would use my own command on all my personal environments.
– B Layer
Mar 1 at 2:17
3
3
Upvoted for mentioning epoch/Unix time, which imo is the only sane way to do time arithmetic
– Rui F Ribeiro
Jan 30 at 9:58
Upvoted for mentioning epoch/Unix time, which imo is the only sane way to do time arithmetic
– Rui F Ribeiro
Jan 30 at 9:58
1
1
TL;DR If you just know your local time offset from Zulu time (e.g. west coast USA is -8 hours or
-08:00
), simply append that to input date-time...nothing else to fiddle with. Example: date -d '2019-02-28 14:05:36-08:00 +2 days 4 hours 3 seconds' +'local: %F %T'
gives local: 2019-03-02 18:05:36– B Layer
Feb 28 at 22:52
TL;DR If you just know your local time offset from Zulu time (e.g. west coast USA is -8 hours or
-08:00
), simply append that to input date-time...nothing else to fiddle with. Example: date -d '2019-02-28 14:05:36-08:00 +2 days 4 hours 3 seconds' +'local: %F %T'
gives local: 2019-03-02 18:05:36– B Layer
Feb 28 at 22:52
@BLayer You're right, it works as expected in that scenario. But imagine the situation where a given script using that approach is executed in a place with a different timezone. The output, while technically correct, may look wrong depending on the information provided by the
+format
argument. For instance, on my system, the same command outputs: local: 2019-03-02 20:05:39
(if I add %:z
to +format
, it becomes obvious that the info is correct and the discrepancy is due to the timezones).– nxnev
Mar 1 at 1:45
@BLayer You're right, it works as expected in that scenario. But imagine the situation where a given script using that approach is executed in a place with a different timezone. The output, while technically correct, may look wrong depending on the information provided by the
+format
argument. For instance, on my system, the same command outputs: local: 2019-03-02 20:05:39
(if I add %:z
to +format
, it becomes obvious that the info is correct and the discrepancy is due to the timezones).– nxnev
Mar 1 at 1:45
@BLayer IMHO, a better general approach would be to use the same timezone for both
-d
and +format
or Unix time, as I said in the answer, to avoid unexpected results.– nxnev
Mar 1 at 1:45
@BLayer IMHO, a better general approach would be to use the same timezone for both
-d
and +format
or Unix time, as I said in the answer, to avoid unexpected results.– nxnev
Mar 1 at 1:45
1
1
@nxnev Agreed, if you're writing a script to be published/shared. The opening words "if you know your own timezone", besides having a literal meaning, are supposed to imply casual/personal use. Someone publishing a script relying on something as flimsy as knowing just their own system's tz probably shouldn't be in the script sharing game. :) On the other hand I do/would use my own command on all my personal environments.
– B Layer
Mar 1 at 2:17
@nxnev Agreed, if you're writing a script to be published/shared. The opening words "if you know your own timezone", besides having a literal meaning, are supposed to imply casual/personal use. Someone publishing a script relying on something as flimsy as knowing just their own system's tz probably shouldn't be in the script sharing game. :) On the other hand I do/would use my own command on all my personal environments.
– B Layer
Mar 1 at 2:17
add a comment |
GNU date
does support simple date arithmetic, though epoch time calculations as shown in @sudodus' answer are sometimes clearer (and more portable).
The use of +/- when there is no timezone specified in the timestamp triggers an attempt to match a timezone next, before anything else is parsed.
Here's one way to do it, use "ago" instead of "-":
$ date -d "2018-12-10 00:00:00 5 hours ago 20 minutes ago 5 seconds ago"
Sun Dec 9 18:39:55 GMT 2018
or
$ date -d "2018-12-10 00:00:00Z -5 hours -20 minutes -5 seconds"
Sun Dec 9 18:39:55 GMT 2018
(Though you cannot arbitrarily use "Z", it works in my zone, but that makes it a UTC/GMT zone timestamp - use your own zone, or %z/%Z by appending ${TZ:-$(date +%z)}
to the timestamp instead.)
Adding extra time terms of these forms adjust time:
- "5 hours ago" subtract 5 hours
- "4 hours" add (implicit) 4 hours
- "3 hours hence" add (explicit) 3 hours (not supported in older versions)
Many complex adjustments, in any order, can be used (though relative and variable terms like "14 weeks hence last monday" are asking for trouble ;-)
(There's another small beartrap here too, date
will always give a valid date, so date -d "2019-01-31 1 month"
gives 2019-03-03, as does "next month")
Given the wide variety of time and date formats that are supported, timezone parsing is necessarily sloppy: it can be a single or multi-letter suffix, an hour or hour:minute offset, a name "America/Denver" (or even a filename in the case of the TZ
variable).
Your 2018-12-10T00:00:00
version doesn't work because "T" is just a delimiter, not a timezone, adding "Z" at the end makes that work (subject to correctness of chosen zone) as expected too.
See:
https://www.gnu.org/software/tar/manual/html_node/Date-input-formats.html
and in particular section 7.7.
1
Other options include:date -d "2018-12-10 00:00:00 now -5 hours
, ortoday
or0 hour
instead ofnow
, anything that tellsdate
that the token after the time is not a timezone offset.
– Stéphane Chazelas
Jan 31 at 14:03
Or, for the sake of thoroughness, leave nothing after the date-time by reordering args: date -d "-5 hours 2018-12-10 00:00:00"`
– B Layer
Mar 7 at 19:21
add a comment |
GNU date
does support simple date arithmetic, though epoch time calculations as shown in @sudodus' answer are sometimes clearer (and more portable).
The use of +/- when there is no timezone specified in the timestamp triggers an attempt to match a timezone next, before anything else is parsed.
Here's one way to do it, use "ago" instead of "-":
$ date -d "2018-12-10 00:00:00 5 hours ago 20 minutes ago 5 seconds ago"
Sun Dec 9 18:39:55 GMT 2018
or
$ date -d "2018-12-10 00:00:00Z -5 hours -20 minutes -5 seconds"
Sun Dec 9 18:39:55 GMT 2018
(Though you cannot arbitrarily use "Z", it works in my zone, but that makes it a UTC/GMT zone timestamp - use your own zone, or %z/%Z by appending ${TZ:-$(date +%z)}
to the timestamp instead.)
Adding extra time terms of these forms adjust time:
- "5 hours ago" subtract 5 hours
- "4 hours" add (implicit) 4 hours
- "3 hours hence" add (explicit) 3 hours (not supported in older versions)
Many complex adjustments, in any order, can be used (though relative and variable terms like "14 weeks hence last monday" are asking for trouble ;-)
(There's another small beartrap here too, date
will always give a valid date, so date -d "2019-01-31 1 month"
gives 2019-03-03, as does "next month")
Given the wide variety of time and date formats that are supported, timezone parsing is necessarily sloppy: it can be a single or multi-letter suffix, an hour or hour:minute offset, a name "America/Denver" (or even a filename in the case of the TZ
variable).
Your 2018-12-10T00:00:00
version doesn't work because "T" is just a delimiter, not a timezone, adding "Z" at the end makes that work (subject to correctness of chosen zone) as expected too.
See:
https://www.gnu.org/software/tar/manual/html_node/Date-input-formats.html
and in particular section 7.7.
1
Other options include:date -d "2018-12-10 00:00:00 now -5 hours
, ortoday
or0 hour
instead ofnow
, anything that tellsdate
that the token after the time is not a timezone offset.
– Stéphane Chazelas
Jan 31 at 14:03
Or, for the sake of thoroughness, leave nothing after the date-time by reordering args: date -d "-5 hours 2018-12-10 00:00:00"`
– B Layer
Mar 7 at 19:21
add a comment |
GNU date
does support simple date arithmetic, though epoch time calculations as shown in @sudodus' answer are sometimes clearer (and more portable).
The use of +/- when there is no timezone specified in the timestamp triggers an attempt to match a timezone next, before anything else is parsed.
Here's one way to do it, use "ago" instead of "-":
$ date -d "2018-12-10 00:00:00 5 hours ago 20 minutes ago 5 seconds ago"
Sun Dec 9 18:39:55 GMT 2018
or
$ date -d "2018-12-10 00:00:00Z -5 hours -20 minutes -5 seconds"
Sun Dec 9 18:39:55 GMT 2018
(Though you cannot arbitrarily use "Z", it works in my zone, but that makes it a UTC/GMT zone timestamp - use your own zone, or %z/%Z by appending ${TZ:-$(date +%z)}
to the timestamp instead.)
Adding extra time terms of these forms adjust time:
- "5 hours ago" subtract 5 hours
- "4 hours" add (implicit) 4 hours
- "3 hours hence" add (explicit) 3 hours (not supported in older versions)
Many complex adjustments, in any order, can be used (though relative and variable terms like "14 weeks hence last monday" are asking for trouble ;-)
(There's another small beartrap here too, date
will always give a valid date, so date -d "2019-01-31 1 month"
gives 2019-03-03, as does "next month")
Given the wide variety of time and date formats that are supported, timezone parsing is necessarily sloppy: it can be a single or multi-letter suffix, an hour or hour:minute offset, a name "America/Denver" (or even a filename in the case of the TZ
variable).
Your 2018-12-10T00:00:00
version doesn't work because "T" is just a delimiter, not a timezone, adding "Z" at the end makes that work (subject to correctness of chosen zone) as expected too.
See:
https://www.gnu.org/software/tar/manual/html_node/Date-input-formats.html
and in particular section 7.7.
GNU date
does support simple date arithmetic, though epoch time calculations as shown in @sudodus' answer are sometimes clearer (and more portable).
The use of +/- when there is no timezone specified in the timestamp triggers an attempt to match a timezone next, before anything else is parsed.
Here's one way to do it, use "ago" instead of "-":
$ date -d "2018-12-10 00:00:00 5 hours ago 20 minutes ago 5 seconds ago"
Sun Dec 9 18:39:55 GMT 2018
or
$ date -d "2018-12-10 00:00:00Z -5 hours -20 minutes -5 seconds"
Sun Dec 9 18:39:55 GMT 2018
(Though you cannot arbitrarily use "Z", it works in my zone, but that makes it a UTC/GMT zone timestamp - use your own zone, or %z/%Z by appending ${TZ:-$(date +%z)}
to the timestamp instead.)
Adding extra time terms of these forms adjust time:
- "5 hours ago" subtract 5 hours
- "4 hours" add (implicit) 4 hours
- "3 hours hence" add (explicit) 3 hours (not supported in older versions)
Many complex adjustments, in any order, can be used (though relative and variable terms like "14 weeks hence last monday" are asking for trouble ;-)
(There's another small beartrap here too, date
will always give a valid date, so date -d "2019-01-31 1 month"
gives 2019-03-03, as does "next month")
Given the wide variety of time and date formats that are supported, timezone parsing is necessarily sloppy: it can be a single or multi-letter suffix, an hour or hour:minute offset, a name "America/Denver" (or even a filename in the case of the TZ
variable).
Your 2018-12-10T00:00:00
version doesn't work because "T" is just a delimiter, not a timezone, adding "Z" at the end makes that work (subject to correctness of chosen zone) as expected too.
See:
https://www.gnu.org/software/tar/manual/html_node/Date-input-formats.html
and in particular section 7.7.
edited Jan 31 at 17:28
answered Jan 31 at 12:26
mr.spuraticmr.spuratic
7,0311128
7,0311128
1
Other options include:date -d "2018-12-10 00:00:00 now -5 hours
, ortoday
or0 hour
instead ofnow
, anything that tellsdate
that the token after the time is not a timezone offset.
– Stéphane Chazelas
Jan 31 at 14:03
Or, for the sake of thoroughness, leave nothing after the date-time by reordering args: date -d "-5 hours 2018-12-10 00:00:00"`
– B Layer
Mar 7 at 19:21
add a comment |
1
Other options include:date -d "2018-12-10 00:00:00 now -5 hours
, ortoday
or0 hour
instead ofnow
, anything that tellsdate
that the token after the time is not a timezone offset.
– Stéphane Chazelas
Jan 31 at 14:03
Or, for the sake of thoroughness, leave nothing after the date-time by reordering args: date -d "-5 hours 2018-12-10 00:00:00"`
– B Layer
Mar 7 at 19:21
1
1
Other options include:
date -d "2018-12-10 00:00:00 now -5 hours
, or today
or 0 hour
instead of now
, anything that tells date
that the token after the time is not a timezone offset.– Stéphane Chazelas
Jan 31 at 14:03
Other options include:
date -d "2018-12-10 00:00:00 now -5 hours
, or today
or 0 hour
instead of now
, anything that tells date
that the token after the time is not a timezone offset.– Stéphane Chazelas
Jan 31 at 14:03
Or, for the sake of thoroughness, leave nothing after the date-time by reordering args: date -d "-5 hours 2018-12-10 00:00:00"`
– B Layer
Mar 7 at 19:21
Or, for the sake of thoroughness, leave nothing after the date-time by reordering args: date -d "-5 hours 2018-12-10 00:00:00"`
– B Layer
Mar 7 at 19:21
add a comment |
This solution is easy to understand, but a little more complicated, so I show it as a shellscript.
- convert to 'seconds since 1970-01-01 00:00:00 UTC'
- add or subtract the difference
- convert back to a human readable format with a final
date
command line
Shellscript:
#!/bin/bash
startdate="2018-12-10 00:00:00"
ddif="0" # days
diff="-5:-20:-5" # hours:minutes:seconds
#-----------------------------------------------------------------------------
ss1970in=$(date -d "$startdate" "+%s") # seconds since 1970-01-01 00:00:00 UTC
printf "%11sn" "$ss1970in"
h=${diff%%:*}
m=${diff#*:}
m=${m%:*}
s=${diff##*:}
difs=$(( (((ddif*24+h)*60)+m)*60+s ))
printf "%11sn" "$difs"
ss1970ut=$((ss1970in + difs)) # add/subtract the time difference
printf "%11sn" "$ss1970ut"
date -d "@$ss1970ut" "+%Y-%m-%d %H:%M:%S"
add a comment |
This solution is easy to understand, but a little more complicated, so I show it as a shellscript.
- convert to 'seconds since 1970-01-01 00:00:00 UTC'
- add or subtract the difference
- convert back to a human readable format with a final
date
command line
Shellscript:
#!/bin/bash
startdate="2018-12-10 00:00:00"
ddif="0" # days
diff="-5:-20:-5" # hours:minutes:seconds
#-----------------------------------------------------------------------------
ss1970in=$(date -d "$startdate" "+%s") # seconds since 1970-01-01 00:00:00 UTC
printf "%11sn" "$ss1970in"
h=${diff%%:*}
m=${diff#*:}
m=${m%:*}
s=${diff##*:}
difs=$(( (((ddif*24+h)*60)+m)*60+s ))
printf "%11sn" "$difs"
ss1970ut=$((ss1970in + difs)) # add/subtract the time difference
printf "%11sn" "$ss1970ut"
date -d "@$ss1970ut" "+%Y-%m-%d %H:%M:%S"
add a comment |
This solution is easy to understand, but a little more complicated, so I show it as a shellscript.
- convert to 'seconds since 1970-01-01 00:00:00 UTC'
- add or subtract the difference
- convert back to a human readable format with a final
date
command line
Shellscript:
#!/bin/bash
startdate="2018-12-10 00:00:00"
ddif="0" # days
diff="-5:-20:-5" # hours:minutes:seconds
#-----------------------------------------------------------------------------
ss1970in=$(date -d "$startdate" "+%s") # seconds since 1970-01-01 00:00:00 UTC
printf "%11sn" "$ss1970in"
h=${diff%%:*}
m=${diff#*:}
m=${m%:*}
s=${diff##*:}
difs=$(( (((ddif*24+h)*60)+m)*60+s ))
printf "%11sn" "$difs"
ss1970ut=$((ss1970in + difs)) # add/subtract the time difference
printf "%11sn" "$ss1970ut"
date -d "@$ss1970ut" "+%Y-%m-%d %H:%M:%S"
This solution is easy to understand, but a little more complicated, so I show it as a shellscript.
- convert to 'seconds since 1970-01-01 00:00:00 UTC'
- add or subtract the difference
- convert back to a human readable format with a final
date
command line
Shellscript:
#!/bin/bash
startdate="2018-12-10 00:00:00"
ddif="0" # days
diff="-5:-20:-5" # hours:minutes:seconds
#-----------------------------------------------------------------------------
ss1970in=$(date -d "$startdate" "+%s") # seconds since 1970-01-01 00:00:00 UTC
printf "%11sn" "$ss1970in"
h=${diff%%:*}
m=${diff#*:}
m=${m%:*}
s=${diff##*:}
difs=$(( (((ddif*24+h)*60)+m)*60+s ))
printf "%11sn" "$difs"
ss1970ut=$((ss1970in + difs)) # add/subtract the time difference
printf "%11sn" "$ss1970ut"
date -d "@$ss1970ut" "+%Y-%m-%d %H:%M:%S"
edited Jan 30 at 14:29
answered Jan 30 at 13:53


sudodussudodus
1,72349
1,72349
add a comment |
add a comment |
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f497639%2fsubtract-time-using-date-and-bash%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
Also: serverfault.com/questions/952279/…
– B Layer
Mar 7 at 19:16