How can I calculate and format a date duration using GNU tools, not a result date?

Pysis

All of the tons of articles I have found so far all seemed to be focused on obtaining a resulting date, which is still useful, but not what I want in this case.

Example link: Unix & Linux SE - Quickly calculate date differences.

With datediff in that other Q&A, this is more of what I want referring to a date/time duration result, and it essentially uses Unix timestamp math with those preceding conversions, but I want my granularity down to the second, which is why I don't divide by 86400.

With the duration of seconds available, I now want to format it to something like using the GNU date command this way: date -d "@69600" "+ %Y years %m months %e days %H:%M:%S"

I realize everything is essentially a date/time duration from the Unix epoch, but now I have the problem with the day, month, and year numbers not starting from 0, which would not correctly represent the duration value I want.

I could get into cutting this format and applying more expr commands to essentially subtract 1 or 1970 from each value, but I'm wondering if there is any other easier and simpler way to deal with date/time calculation to achieve a duration result besides chaining math and formatting steps together. Maybe there is some other option in GNU date that I could take advantage of, or another tool that would accept 2 date/time arguments and immediately give me the result I am looking for.

Having it be available in Homebrew for Macs would be a plus :).

Simple date math link: Walker News - Date Arithmetic In Linux Shell Scripts

Random date formatting links:

Stéphane Chazelas

With dateutils's datediff (not GNU sorry), (formerly ddiff, dateutils.ddiff on Debian):

$ dateutils.ddiff -f '%Y years, %m months, %d days, %H:%0M:%0S' \
    '2012-01-23 15:23:01' '2017-06-01 09:24:00'
5 years, 4 months, 8 days, 18:00:59

(dates taken as UTC, add something like --from-zone=Europe/London for the dates to be taken as local time in the corresponding time zone. --from-zone=localtime may work for the default timezone in the system; --from-zone="${TZ#:}" would work as long as $TZ specifies the path of a IANA timezone file (like TZ=:Europe/London, not TZ=GMT0BST,M3.5.0/1:00:00,M10.5.0/2:00:00 POSIX-style TZ specification)).

With ast-open date, so still not with GNU tools sorry (if using ksh93 as your shell, that date may be available as a builtin though) you can use date -E to get the difference between two dates in a format that gives 2 numbers with units:

$ date -E 1970-01-01 2017-06-01
47Y04M
$ date -E 2017-01-01 2017-06-01
4M29d
$ date -E 12:12:01 23:01:43
10h49m

Note that anything above hour is ambiguous, as days have a varying number of hours in locales with DST (23, 24 or 25) and months and years have a varying number of days, so it may not make much sense to have more precision than those two units above.

For instance, there's exactly one year in between 2015-01-01 00:00:00 and 2016-01-01 00:00:00 or between 2016-01-01 00:00:00 and 2017-01-01 00:00:00, but that's not the same duration (365*24 hours in one case, 366*24 hours in the other)

There's exactly one day between 2017-03-24 12:00:00 and 2017-03-25 12:00:00 or between 2017-03-25 12:00:00 and 2017-03-26 12:00:00, but when those are local time in European countries (that switched to summer time on 2017-03-26), that one day is 24 hours in one case and 23 hours in the other.

In other words a duration that mentions years, months, weeks or days is only meaningful when associated to one of the boundaries it's meant to be applied to (and the timezone). So you cannot convert a number of seconds to such a duration without knowing what time (from or until) it's meant to be applied to (unless you want to use approximate definitions of day (24 hour), month (30*24 hours) or year (365*24 hours)).

To some extent, even a duration in seconds is ambiguous. For simplification, the seconds in the Unix epoch time are defined as the 86400th part of a given Earth day1. Those seconds are getting longer and longer as Earth spins down.

So something like (with GNU date):

d1='2016-01-01 00:00:00' d2='2017-01-01 00:00:00'
eval "$(date -d "@$(($(date -d "$d2" +%s) - $(date -d "$d1" +%s)))" +'
  delta="$((%-Y - 1970)) years, $((%-m - 1)) months, $((%-d - 1)) days, %T"')"
echo "$delta"

Or in fish:

date -d@(expr (date -d $d2 +%s) - (date -d $d1 +%s)) +'%Y %-m %-d %T' | \
  awk '{printf "%s years, %s months, %s days, %s\n", $1-1970, $2-1, $3-1, $4, $5}'

Would generally not give you something that is correct as the time delta is applied to 1970 instead of the actual start date 2016.

For instance, above, that gives me (in a Europe/London timezone):

1 years, 0 months, 1 days, 01:00:00

instead of

1 years, 0 months, 0 days, 00:00:00

(that may still be a good enough approximation for you).


1 Technically, while a day is 86400 Unix seconds long, network-connected systems typically synchronise their clock to atomic clocks using SI seconds. When an atomic clock says 12:00:00.00, those Unix systems also say 12:00:00.00. The exception is only upon the introduction of leap seconds, where either there's one Unix second that lasts 2 seconds or a few seconds that last a bit longer to smear that extra second upon a longer period.

So, it is possible to know the exact duration (in terms of atomic seconds) in between two Unix time stamps (issued by systems synchronised to atomic clock): get the difference of Unix epoch time between the two timestamps and add the number of leap seconds that have been added in between.

datediff also has a -f %rS to get the number of real seconds in between two dates:

$ dateutils.ddiff -f %S '1990-01-01 00:00:00' '2010-01-01 00:00:00'
631152000
$ dateutils.ddiff -f %rS '1990-01-01 00:00:00' '2010-01-01 00:00:00'
631152009

The difference is for the 9 leap seconds that have been added in between 1990 and 2010.

Now, that number of real seconds is not going to help you to calculate the number of days as days don't have a constant number of real seconds. There are exactly 20 years between those 2 dates and those 9 leaps seconds rather get in the way to get to that value. Also note that ddiff's %rS only works when not combined with other format specifiers. Also, future leap seconds are not known long in advance, but also information about recent leap seconds may not be available. For instance, my system doesn't know about the ones after 2012-07-01.

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

How do I calculate age using the date format in android studio?

分類Dev

Can I convert a date in the format YYYYMMDDHHMM using date?

分類Dev

Date computations without GNU tools

分類Dev

How can I format date_space_hour to a time format

分類Dev

How can I calculate how many working days are to a determined date?

分類Dev

How to calculate average result for certain date?

分類Dev

How can I convert a date into another format with moment.js?

分類Dev

How can i format the date with Momentjs to look like this?

分類Dev

How do I replace date format using TextPad?

分類Dev

ReactJS - How can I change date format from MongoDB Date.now

分類Dev

How can I convert YYWW to date format based on day[Ex: Monday's date in given YYWW ] in SqlServer?

分類Dev

How to format date without year using Simple Date Format?

分類Dev

How can I convert date time format string used by C# to the format used by moment.js?

分類Dev

How to change date format using jQuery/Javascript?

分類Dev

How can I get a date into this format, 2013-08-09T19:08:28Z?

分類Dev

How to format a Date with Luxon?

分類Dev

How to format this date?

分類Dev

pandas from date as string to format that I can shift in a loop with shift()

分類Dev

How can I check date and time on javascript?

分類Dev

How can i split date and time separate?

分類Dev

How can I order this MySQL Date?

分類Dev

Can't format date in <input>

分類Dev

How can I calculate network measures for each account only considering the last 6 month period prior to the transaction date in r?

分類Dev

How to Define date format from a given date

分類Dev

How do I get the current date and time in the format given Below

分類Dev

how does the gnu coreutils `date` work?

分類Dev

How can I retrieve only the record related to the last value of a date field in this specific case using SQL?

分類Dev

How can I create a DateTime String using a date String and time String?

分類Dev

How to replicate a 'new Date()' format?

Related 関連記事

  1. 1

    How do I calculate age using the date format in android studio?

  2. 2

    Can I convert a date in the format YYYYMMDDHHMM using date?

  3. 3

    Date computations without GNU tools

  4. 4

    How can I format date_space_hour to a time format

  5. 5

    How can I calculate how many working days are to a determined date?

  6. 6

    How to calculate average result for certain date?

  7. 7

    How can I convert a date into another format with moment.js?

  8. 8

    How can i format the date with Momentjs to look like this?

  9. 9

    How do I replace date format using TextPad?

  10. 10

    ReactJS - How can I change date format from MongoDB Date.now

  11. 11

    How can I convert YYWW to date format based on day[Ex: Monday's date in given YYWW ] in SqlServer?

  12. 12

    How to format date without year using Simple Date Format?

  13. 13

    How can I convert date time format string used by C# to the format used by moment.js?

  14. 14

    How to change date format using jQuery/Javascript?

  15. 15

    How can I get a date into this format, 2013-08-09T19:08:28Z?

  16. 16

    How to format a Date with Luxon?

  17. 17

    How to format this date?

  18. 18

    pandas from date as string to format that I can shift in a loop with shift()

  19. 19

    How can I check date and time on javascript?

  20. 20

    How can i split date and time separate?

  21. 21

    How can I order this MySQL Date?

  22. 22

    Can't format date in <input>

  23. 23

    How can I calculate network measures for each account only considering the last 6 month period prior to the transaction date in r?

  24. 24

    How to Define date format from a given date

  25. 25

    How do I get the current date and time in the format given Below

  26. 26

    how does the gnu coreutils `date` work?

  27. 27

    How can I retrieve only the record related to the last value of a date field in this specific case using SQL?

  28. 28

    How can I create a DateTime String using a date String and time String?

  29. 29

    How to replicate a 'new Date()' format?

ホットタグ

アーカイブ