简体   繁体   English

Bash - 给定日期的小时数

[英]Bash - number of hours in given day

Using Bash shell on Linux, and given a datetime, how can I determine how many hours there are on that particular day?在 Linux 上使用 Bash shell,并给定日期时间,我如何确定那一天有多少小时?

The datetime pertains to some time zone with daylight saving, eg MET.日期时间与某些具有夏令时的时区有关,例如 MET。

In order to completely account for all scenarios, you need to consider a few things:为了完全考虑所有场景,您需要考虑以下几点:

  • Not every local day has a midnight, and the date command will fail if you pass a date on one of these days, unless you also pass a time and an offset from UTC.并非每个本地日都有午夜,如果您在这些日子之一传递日期,则date命令将失败,除非您还传递了时间和与 UTC 的偏移量。 This primarily occurs on the spring-forward transition days.这主要发生在春季向前的过渡日。 For example:例如:

     $ TZ=America/Sao_Paulo date -d '2016-10-16' date: invalid date '2016-10-16'
  • Not every DST transition is 1 hour.并非每个 DST 过渡都是 1 小时。 America/Lord_Howe switches by 30 minutes. America/Lord_Howe切换 30 分钟。 Bash only performs integer division, so you have to use one of these techniques if you want decimals. Bash 只执行整数除法,所以如果你想要小数,你必须使用这些技术之一

Here is a function that accounts for these:这是一个解释这些的函数:

seconds_in_day() {
  # Copy input date to local variable
  date=$1

  # Start with the offset at noon on the given date.
  # Noon will almost always exist (except Samoa on 2011-12-30)
  offset1=$(date -d "$date 12:00" +%z)

  # Next get the offset for midnight.  If it doesn't exist, the time will jump back to 23:00 and we'll get a different offset.
  offset1=$(date -d "$date 00:00 $offset1" +%z)

  # Next get the offset for the next day at midnight.  Again, if it doesn't exist, it will jump back an hour.
  offset2=$(date -d "$date 00:00 $offset1 + 1 day" +%z)

  # Get the unix timestamps for both the current date and the next one, at midnight with their respective offsets.
  unixtime1=$(date -d "$date 00:00 $offset1" +%s)
  unixtime2=$(date -d "$date 00:00 $offset2 + 1 day" +%s)

  # Calculate the difference in seconds and hours.  Use awk for decimal math.
  seconds=$((unixtime2 - unixtime1))
  hours=$(awk -v seconds=$seconds 'BEGIN { print seconds / 3600 }')

  # Print the output
  echo "$date had $seconds secs in $TZ, or $hours hours."
}

Examples:例子:

$ TZ=America/Los_Angeles seconds_in_day 2016-03-12
2016-03-12 had 86400 secs in America/Los_Angeles, or 24 hours.
$ TZ=America/Los_Angeles seconds_in_day 2016-03-13
2016-03-13 had 82800 secs in America/Los_Angeles, or 23 hours.
$ TZ=America/Los_Angeles seconds_in_day 2016-03-14
2016-03-14 had 86400 secs in America/Los_Angeles, or 24 hours.

$ TZ=America/Los_Angeles seconds_in_day 2016-11-05
2016-11-05 had 86400 secs in America/Los_Angeles, or 24 hours.
$ TZ=America/Los_Angeles seconds_in_day 2016-11-06
2016-11-06 had 90000 secs in America/Los_Angeles, or 25 hours.
$ TZ=America/Los_Angeles seconds_in_day 2016-11-07
2016-11-07 had 86400 secs in America/Los_Angeles, or 24 hours.

$ TZ=America/Sao_Paulo seconds_in_day 2016-02-19
2016-02-19 had 86400 secs in America/Sao_Paulo, or 24 hours.
$ TZ=America/Sao_Paulo seconds_in_day 2016-02-20
2016-02-20 had 90000 secs in America/Sao_Paulo, or 25 hours.
$ TZ=America/Sao_Paulo seconds_in_day 2016-02-21
2016-02-21 had 86400 secs in America/Sao_Paulo, or 24 hours.

$ TZ=America/Sao_Paulo seconds_in_day 2016-10-15
2016-10-15 had 86400 secs in America/Sao_Paulo, or 24 hours.
$ TZ=America/Sao_Paulo seconds_in_day 2016-10-16
2016-10-16 had 82800 secs in America/Sao_Paulo, or 23 hours.
$ TZ=America/Sao_Paulo seconds_in_day 2016-10-17
2016-10-17 had 86400 secs in America/Sao_Paulo, or 24 hours.

$ TZ=Australia/Lord_Howe seconds_in_day 2016-04-02
2016-04-02 had 86400 secs in Australia/Lord_Howe, or 24 hours.
$ TZ=Australia/Lord_Howe seconds_in_day 2016-04-03
2016-04-03 had 88200 secs in Australia/Lord_Howe, or 24.5 hours.
$ TZ=Australia/Lord_Howe seconds_in_day 2016-04-04
2016-04-04 had 86400 secs in Australia/Lord_Howe, or 24 hours.

$ TZ=Australia/Lord_Howe seconds_in_day 2016-10-01
2016-10-01 had 86400 secs in Australia/Lord_Howe, or 24 hours.
$ TZ=Australia/Lord_Howe seconds_in_day 2016-10-02
2016-10-02 had 84600 secs in Australia/Lord_Howe, or 23.5 hours.
$ TZ=Australia/Lord_Howe seconds_in_day 2016-10-03
2016-10-03 had 86400 secs in Australia/Lord_Howe, or 24 hours.

Oct 30 was the last summer time change here in Britain. 10 月 30 日是英国最后一个夏令时。 I can get 25 hours for that day from the shell in this way:我可以通过这种方式从 shell 获得那天的 25 小时:

t1=$(TZ='Europe/London' date --date='20161030' +%s)
t2=$(TZ='Europe/London' date --date='20161031' +%s)
echo $((($t2 - $t1) / 3600))

I am not totally sure this will work in every bash shell and may need to be adjusted a little bit.我不完全确定这会在每个 bash shell 中工作,并且可能需要稍微调整一下。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM