Obtenha a data de ontem no bash no Linux, seguro para horário de verão

158

Eu tenho um script de shell que roda no Linux e usa essa chamada para obter a data de ontem no YYYY-MM-DDformato:

date -d "1 day ago" '+%Y-%m-%d'

Funciona na maioria das vezes, mas quando o script foi executado ontem de manhã 2013-03-11 0:35 CDT, retornou em "2013-03-09"vez de "2013-03-10".

Presumivelmente, o horário de verão (que começou ontem) é o culpado. Eu estou supondo que a maneira como "1 day ago"é implementada subtraiu 24 horas, e 24 horas antes 2013-03-11 0:35 CDTera 2013-03-09 23:35 CST, o que levou ao resultado de "2013-03-09".

Então, qual é uma boa maneira segura de horário de verão para obter a data de ontem no bash no Linux?

Ike Walker
fonte
Você está sempre executando isso ao mesmo tempo, está executando repetidamente?
tink
@tink é executado diariamente às 00:35
Ike Walker

Respostas:

267

Eu acho que isso deve funcionar, independentemente de quantas vezes e quando você o executa ...

date -d "yesterday 13:00" '+%Y-%m-%d'
consertar
fonte
1
Como você atribuiria isso a uma variável para uso posterior?
null
6
@ null - da mesma maneira que você atribuiria a saída de qualquer outro comando do shell. variável = $ (data-d "ontem 13:00" '+% Y-% m-% d') ...
toque em
Para GNU-date:date -d yesterday 13:00 -I
gogstad 6/17/17
Isso se baseia no fato de que a alternância entre o verão e o inverno é sempre feita à noite, se eu entendi corretamente?
Nicolas Raoul
2
@NicolasRaoul: Não é garantido; mas é uma convenção amplamente seguida para agendar isso no início da manhã. Por outro lado, não há IIRC em nenhum lugar onde a troca aconteça perto do meio-dia local. Portanto, "1300J nunca está no limite do horário de verão" é uma suposição razoável .
Piskvor saiu do prédio 28/03
56

A data no Mac OSX é um pouco diferente.

Para ontem

date -v-1d +%F

Na semana passada

date -v-1w +%F
Áries
fonte
8
Se estiver interessado em usar o estilo GNU no OSX, você também pode usá-lo gdate, disponível no coreutilspacote homebrew .
User456584
11
Você quer dizer que dateé diferente.
Augurar 25/03
12

Isso também deve funcionar, mas talvez seja demais:

date -d @$(( $(date +"%s") - 86400)) +"%Y-%m-%d"
perreal
fonte
Material como este é necessário se você precisa lidar com Mac OS X dateque não suporta yesterdaya sintaxe ...
Mikko Rantalainen
7

Se você tem certeza de que o script é executado nas primeiras horas do dia, você pode simplesmente fazer

  date -d "12 hours ago" '+%Y-%m-%d'

BTW, se o script for executado diariamente às 00:35 (via crontab?), Você deve se perguntar o que acontecerá se uma alteração no horário de verão cair nessa hora; o script não pôde ser executado ou executado duas vezes em alguns casos. As implementações modernas de cronsão bastante inteligentes nesse sentido, no entanto.

leonbloy
fonte
5

você pode usar

date -d "30 days ago" +"%d/%m/%Y"

para obter a data de 30 dias atrás, da mesma forma, você pode substituir 30 pela quantidade de dias x

Dan Pickard
fonte
Você deve alterar seu formato %Y%m%dpara corresponder à pergunta. Eu votei de qualquer maneira, pois funcionou corretamente.
Isapir
4

Aqui está uma solução que também funcionará com Solaris e AIX.

É possível manipular o fuso horário para alterar o relógio algumas horas. Devido ao horário de verão, 24 horas atrás pode ser hoje ou antes de ontem.

Você tem certeza que ontem é 20 ou 30 horas atrás. Qual? Bem, o mais recente que não é hoje.

echo -e "$(TZ=GMT+30 date +%Y-%m-%d)\n$(TZ=GMT+20 date +%Y-%m-%d)" | grep -v $(date +%Y-%m-%d) | tail -1

O parâmetro -e usado no comando echo é necessário com o bash, mas não funcionará com o ksh. No ksh, você pode usar o mesmo comando sem o sinalizador -e.

Quando seu script será usado em ambientes diferentes, você poderá iniciar o script com #! / Bin / ksh ou #! / Bin / bash. Você também pode substituir o \ n por uma nova linha:

echo "$(TZ=GMT+30 date +%Y-%m-%d)
$(TZ=GMT+20 date +%Y-%m-%d)" | grep -v $(date +%Y-%m-%d) | tail -1
Walter A
fonte
0

Basta usar datee segundos confiáveis:

Como você corretamente aponta, muitos detalhes sobre o cálculo subjacente ficam ocultos se você confiar na aritmética do tempo em inglês. Por exemplo -d yesterday, e -d 1 day agoterá um comportamento diferente.

Em vez disso, você pode confiar de forma confiável nos segundos (documentados com precisão) desde a época UTC do unix, e na aritmética do bash para obter o momento que deseja:

date -d @$(( $(date +"%s") - 24*3600)) +"%Y-%m-%d"

Isso foi apontado em outra resposta . Esse formulário é mais portátil em plataformas com diferentes datesinalizadores de linha de comando, é independente do idioma (por exemplo, "ontem" vs "hier" na localidade francesa) e, francamente (a longo prazo), será mais fácil lembrar, porque, bem, você já sabe disso. Caso contrário, você pode continuar se perguntando: "Foi -d 2 hours agoou de -d 2 hour agonovo?" ou "É -d yesterdayou -d 1 day agoeu quero?"). A única parte complicada aqui é a@ .

Armado com bash e nada mais:

Bash apenas no bash, você também pode obter o horário de ontem, através do printf incorporado:

 %(datefmt)T
     causes printf to output the date-time string resulting from using
     datefmt as a format string for strftime(3).  The  corresponding  argu
     ment  is an integer representing the number of seconds since the
     epoch.  Two special argument values may be used: -1 represents the
     current time, and -2 represents the time the shell was invoked.
     If no argument is specified, conversion behaves as if -1 had
     been  given.
     This is an exception to the usual printf behavior.

Assim,

# inner printf gets you the current unix time in seconds
# outer printf spits it out according to the format
printf "%(%Y-%m-%d)T\n" $(( $(printf "%(%s)T" -1) - 24*3600 ))

ou, de forma equivalente a uma variável temp (subshell externo opcional, mas mantém os vars do ambiente limpos).

(
  now=$(printf "%(%s)T" -1);
  printf "%(%Y-%m-%d)T\n" $((now - 24*3600));
)

Nota: apesar da página de manual declarando que nenhum argumento para o %()Tformatador assumirá um padrão -1, parece que recebo um 0 (obrigado, versão manual do bash 4.3.48)

init_js
fonte
0
date -d "yesterday" '+%Y-%m-%d'

Para usar isso mais tarde:

date=$(date -d "yesterday" '+%Y-%m-%d')
suresh Palemoni
fonte
2
Embora esse código possa resolver o problema do OP, é melhor incluir uma explicação sobre como o código soluciona o problema do OP. Dessa forma, futuros visitantes podem aprender com sua postagem e aplicá-la ao próprio código. O SO não é um serviço de codificação, mas um recurso para o conhecimento. Respostas completas e de alta qualidade reforçam essa idéia e são mais propensas a serem votadas. Esses recursos, além do requisito de que todas as postagens sejam independentes, são alguns dos pontos fortes do SO como uma plataforma que nos diferencia dos fóruns. Você pode editar para adicionar informações adicionais e / ou complementar suas explicações com a documentação de origem.
SherylHohman 16/06
0

Você pode usar:

date -d "yesterday 13:55" '+%Y-%m-%d'

Ou a hora que você deseja recuperar será recuperada pelo bash.

Por mês:

date -d "30 days ago" '+%Y-%m-%d'
Daremitsu
fonte
0

Como esta pergunta está marcada "DST safe"

E usando o fork para datecomandar o atraso implie, existe uma maneira simples e mais eficiente de usar o bash puro incorporado:

printf -v tznow '%(%z %s)T' -1
TZ=${tznow% *} printf -v yesterday '%(%Y-%m-%d)T' $(( ${tznow#* } - 86400 ))
echo $yesterday

Isto é muito mais rápido em mais sistema amigável do que ter que desembolsar para date.

De V> = 5.0 , há uma nova variável$EPOCHSECONDS

printf -v tz '%(%z)T' -1
TZ=$tz printf -v yesterday '%(%Y-%m-%d)T' $(( EPOCHSECONDS - 86400 ))
echo $yesterday
F. Hauri
fonte