简体   繁体   English

循环遍历日期的 bash 脚本卡住了吗?

[英]bash script looping through dates gets stuck?

I'm using the bash script below to kick off a python program.我正在使用下面的 bash 脚本来启动一个 python 程序。 It loops through date/time exactly as I would expect.它完全按照我的预期循环遍历日期/时间。 But, then, it get's stuck at "2018-11-04 01:45:00".但是,然后,它被困在“2018-11-04 01:45:00”。 Adding 15 minutes to "2018-11-04 01:45:00" returns "2018-11-04 01:00:00", not "2018-11-04 02:00:00".将 15 分钟添加到“2018-11-04 01:45:00”返回“2018-11-04 01:00:00”,而不是“2018-11-04 02:00:00”。 Has anyone experienced this?有没有人经历过这个?

    #!/bin/bash

    dEND=$(date +"%F %T" -d "2020-03-15 00:00:00")
    dCUR=$(date +"%F %T" -d "2018-11-04 01:00:00")
    echo $dCUR $dEND

    typeset -i sEND=1
    typeset -i sCUR=0
    echo $sCUR $sEND

    while( (( $sCUR < $sEND )) );do
       dCUR=$(date +"%F %T" -d "$dCUR 15 minutes")

       typeset -i sEND=$(date +%s -d "$dEND")
       typeset -i sCUR=$(date +%s -d "$dCUR")
       echo $dCUR $dEND $sCUR
    done
    echo done
    $ dCUR=$(date +"%F %T" -d "2018-11-04 00:00:00")
    $ echo $dCUR
    2018-11-04 00:00:00
    $ dCUR=$(date +"%F %T" -d "$dCUR 15 minutes");echo $dCUR
    2018-11-04 00:15:00
    $ dCUR=$(date +"%F %T" -d "$dCUR 15 minutes");echo $dCUR
    2018-11-04 00:30:00
    $ dCUR=$(date +"%F %T" -d "$dCUR 15 minutes");echo $dCUR
    2018-11-04 00:45:00
    $ dCUR=$(date +"%F %T" -d "$dCUR 15 minutes");echo $dCUR
    2018-11-04 01:00:00
    $ dCUR=$(date +"%F %T" -d "$dCUR 15 minutes");echo $dCUR
    2018-11-04 01:15:00
    $ dCUR=$(date +"%F %T" -d "$dCUR 15 minutes");echo $dCUR
    2018-11-04 01:30:00
    $ dCUR=$(date +"%F %T" -d "$dCUR 15 minutes");echo $dCUR
    2018-11-04 01:45:00
    $ dCUR=$(date +"%F %T" -d "$dCUR 15 minutes");echo $dCUR
    2018-11-04 01:00:00

I suspect you (or, more correctly, your machine ) may be located (or, more correctly, be configured as if it's located) in the Bahamas, Bermuda, Brazil, Canada, Cuba, Fiji, Greenland, Haiti, Mexico, Saint Pierre and Miquelon, Turks and Caicos islands, and the USA.我怀疑您(或更准确地说,您的机器)可能位于(或更准确地说,配置为好像它位于)巴哈马、百慕大、巴西、加拿大、古巴、斐济、格陵兰、海地、墨西哥、圣皮埃尔密克隆、特克斯和凯科斯群岛以及美国。

I can't tell for sure since your profile has no information on your location, but I'd be curious to know how close I am to reality.我不能确定,因为您的个人资料没有关于您所在位置的信息,但我很想知道我离现实有多近。


That code of yours works fine on my system but my geographical region does not do daylight savings.你的代码在我的系统上运行良好,但我的地理区域不做夏令时。

That changeover tends to happen around 2-3am in many places so it may just be an artefact of the date you've chosen.在许多地方,这种转换往往发生在凌晨 2 点到 3 点左右,因此它可能只是您选择的日期的产物。 From this page here , it appears a few places did indeed do a switch on November 4 (hence my list of locations in the first paragraph of this answer).这里的这个页面来看,似乎有几个地方确实在 11 月 4 日进行了切换(因此我在此答案的第一段中列出了位置列表)。

You can probably confirm this by running the exact same experiment but using November 5 rather than the date you've chosen.您可以通过运行完全相同的实验来确认这一点,但使用 11 月 5 日而不是您选择的日期。 You can also add the %z format specifier and you should see it change over from (for example) +08 to +07 .您还可以添加%z格式说明符,您应该会看到它从(例如) +08更改为+07


As with most problems with world times, the best solution is convert all local times into UTC as quickly as possible, and turn them back into local times as late as possible.与世界时间的大多数问题一样,最好的解决方案是尽快将所有本地时间转换为 UTC,并尽可能晚地将它们转换回本地时间。 That way, you mostly have a consistent time base except where you're interacting with end users (who generally think in terms of local time).这样,除了与最终用户(通常以当地时间考虑)进行交互的地方,您大多拥有一致的时基。

As an example, here's a script that runs from 1am to 5am, in a region that had a timezone switch in the range.例如,这里有一个从凌晨 1 点到凌晨 5 点运行的脚本,在该范围内有一个时区切换的区域。

#!/bin/bash

# My region doesn't do DST but New York does, so fake it.

export TZ=America/New_York

# Helper functions for UTC/local conversion.

utcFmt="%F %T %z"
localFmt="%F %T"

utcToLocal() {
    echo "$(date +"${localFmt}" -d "$(date +"${utcFmt}" -d "$1")")"
}

localToUtc() {
    echo "$(date -u +"${utcFmt}" -d "$(date +"${utcFmt}" -d "$1")")"
}

# Init UTC values based on local time.

utcCur="$(localToUtc "2018-11-04 01:00:00")"
utcEnd="$(localToUtc "2018-11-04 05:00:00")"

echo "Going from ${utcCur} to ${utcEnd}"

while [[ "${utcCur}" < "${utcEnd}" ]] ; do
    # Display local time, but adjust UTC time.

    echo "At $(utcToLocal "${utcCur}")"
    utcCur="$(date -u +"${utcFmt}" -d "$utcCur 15 minutes")"
done

As you can see from the output, there is one rolling back to an earlier time because that's what happens when you turn the clock back (see * markers):正如您从输出中看到的那样,有一个回滚到更早的时间,因为这就是您将时钟倒转时会发生的情况(请参阅*标记):

Going from 2018-11-04 01:00:00 to 2018-11-04 05:00:00
At 2018-11-04 01:00:00
At 2018-11-04 01:15:00
At 2018-11-04 01:30:00
At 2018-11-04 01:45:00
At 2018-11-04 01:00:00 * Roll back one hour (once).
At 2018-11-04 01:15:00
At 2018-11-04 01:30:00
At 2018-11-04 01:45:00
At 2018-11-04 02:00:00 * Keep going.
At 2018-11-04 02:15:00
At 2018-11-04 02:30:00
At 2018-11-04 02:45:00
At 2018-11-04 03:00:00
At 2018-11-04 03:15:00
At 2018-11-04 03:30:00
At 2018-11-04 03:45:00
At 2018-11-04 04:00:00
At 2018-11-04 04:15:00
At 2018-11-04 04:30:00
At 2018-11-04 04:45:00

And, if you go to the other end of the daylight savings (where an hour disappears), you can see that as well (again, watch the * markers):而且,如果您转到夏令时的另一端(一个小时消失的地方),您也可以看到(再次注意*标记):

utcCur="$(localToUtc "2018-03-11 01:00:00")"
utcEnd="$(localToUtc "2018-03-11 05:00:00")"

Going from 2018-03-11 01:00:00 to 2018-03-11 05:00:00
At 2018-03-11 01:00:00
At 2018-03-11 01:15:00
At 2018-03-11 01:30:00
At 2018-03-11 01:45:00
At 2018-03-11 03:00:00 * Put clock foward one hour.
At 2018-03-11 03:15:00
At 2018-03-11 03:30:00
At 2018-03-11 03:45:00
At 2018-03-11 04:00:00
At 2018-03-11 04:15:00
At 2018-03-11 04:30:00
At 2018-03-11 04:45:00

2018-11-04 was the first Sunday in November. 2018-11-04 是十一月的第一个星期天。 The regions of North America and nearby territories which switch between daylight saving and standard time currently do so on the first Sunday in November (and on the second Sunday in March for the other transition).在夏令时和标准时间之间切换的北美地区和附近地区目前在 11 月的第一个星期日(以及其他过渡的 3 月的第二个星期日)进行。 That means that in November, the time goes from 01:59:59 xDT to 01:00:00 xST (spring forward; fall back).这意味着在 11 月,时间从 01:59:59 xDT 到 01:00:00 xST(春天向前;后退)。 The addition and result is correct — even though it wasn't what you expected.添加和结果是正确的——即使它不是你所期望的。

Places in Europe that switch currently spring forward on the last Sunday in March and fall back on the last Sunday in October, thus changing 2 or 3 weeks later in the spring and 1 week earlier in the autumn than the USA changes.欧洲的地方目前在 3 月的最后一个星期天向前转换,在 10 月的最后一个星期日回落,因此比美国的变化在春季晚 2 或 3 周,在秋季早 1 周。 If the 1st of March falls on Monday through Thursday, the gap is 2 weeks;如果 3 月 1 日是周一至周四,则间隔为 2 周; Friday through Sunday, 3 weeks.周五至周日,3 周。

Other countries have different rules still, sometimes influenced by the lunar calendar and religious observations.其他国家仍然有不同的规则,有时会受到农历和宗教观察的影响。

GNU date format string is very flexible, but in the long run is not reliable. GNU 日期格式字符串非常灵活,但从长远来看是不可靠的。

To do what you want, convert the date to number of seconds since epoch, add 15*60 seconds and then convert back to the format you want.要执行您想要的操作,请将日期转换为自纪元以来的秒数,添加15*60秒,然后转换回您想要的格式。

That would be:那将是:

dCUR=$(date -d "@$(($(date --date="$dCUR" +%s) + 15 * 60))" +"%F %T"); echo $dCUR

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

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