Subtract time using date and bash












15















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?










share|improve this question




















  • 1





    Also: serverfault.com/questions/952279/…

    – B Layer
    Mar 7 at 19:16
















15















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?










share|improve this question




















  • 1





    Also: serverfault.com/questions/952279/…

    – B Layer
    Mar 7 at 19:16














15












15








15


2






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?










share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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














  • 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










5 Answers
5






active

oldest

votes


















18














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. ¯(ツ)/¯






share|improve this answer





















  • 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






  • 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






  • 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



















6














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





share|improve this answer
























  • 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'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 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



















6

















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





share|improve this answer





















  • 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














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.






share|improve this answer





















  • 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













  • 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



















2














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"





share|improve this answer


























    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
    });


    }
    });














    draft saved

    draft discarded


















    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









    18














    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. ¯(ツ)/¯






    share|improve this answer





















    • 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






    • 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






    • 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
















    18














    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. ¯(ツ)/¯






    share|improve this answer





















    • 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






    • 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






    • 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














    18












    18








    18







    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. ¯(ツ)/¯






    share|improve this answer















    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. ¯(ツ)/¯







    share|improve this answer














    share|improve this answer



    share|improve this answer








    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 (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





      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





      @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





      @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





      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





      @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













    6














    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





    share|improve this answer
























    • 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'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 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
















    6














    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





    share|improve this answer
























    • 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'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 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














    6












    6








    6







    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





    share|improve this answer













    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






    share|improve this answer












    share|improve this answer



    share|improve this answer










    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 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'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 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



















    • 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'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 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

















    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











    6

















    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





    share|improve this answer





















    • 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


















    6

















    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





    share|improve this answer





















    • 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
















    6












    6








    6










    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





    share|improve this answer


















    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






    share|improve this answer














    share|improve this answer



    share|improve this answer








    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
















    • 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













    3














    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.






    share|improve this answer





















    • 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













    • 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
















    3














    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.






    share|improve this answer





















    • 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













    • 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














    3












    3








    3







    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.






    share|improve this answer















    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.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    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, 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














    • 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













    • 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











    2














    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"





    share|improve this answer






























      2














      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"





      share|improve this answer




























        2












        2








        2







        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"





        share|improve this answer















        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"






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Jan 30 at 14:29

























        answered Jan 30 at 13:53









        sudodussudodus

        1,72349




        1,72349






























            draft saved

            draft discarded




















































            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.




            draft saved


            draft discarded














            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





















































            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







            Popular posts from this blog

            MongoDB - Not Authorized To Execute Command

            How to fix TextFormField cause rebuild widget in Flutter

            Npm cannot find a required file even through it is in the searched directory