Toutes les autres questions sur le réseau SE traitent de scénarios où soit la date est supposée être now
( Q ), soit où seule une date est spécifiée ( Q ).
Ce que je veux faire, c'est fournir une date et une heure, puis soustraire une heure à cela.
Voici ce que j'ai essayé en premier:
date -d "2018-12-10 00:00:00 - 5 hours - 20 minutes - 5 seconds"
Il en résulte 2018-12-10 06:39:55
- Il a ajouté 7 heures. Puis soustrait 20:05 minutes.
Après avoir lu la page man
et info
de date
, je pensais l'avoir corrigé avec ceci:
date -d "2018-12-10T00:00:00 - 5 hours - 20 minutes - 5 seconds"
Mais, même résultat. D'où vient-il même les 7 heures?
J'ai également essayé d'autres dates parce que je pensais que nous avions peut-être 7200 secondes intercalaires ce jour-là, qui sait lol. Mais mêmes résultats.
Quelques exemples supplémentaires:
$ 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
Mais ici, cela devient intéressant. Si j'omets le temps en entrée, cela fonctionne très bien:
$ 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
Qu'est-ce que je rate?
Mise à jour: j'ai ajouté un Z
à la fin, et cela a changé le comportement:
$ date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_04:00:00
Je suis toujours confus cependant. Il n'y a pas grand-chose à ce sujet dans la page d'informations GNU sur la date.
Je suppose que c'est un problème de fuseau horaire, mais en citant le calendrier Wiki sur ISO 8601 :
Si aucune information de relation UTC n'est donnée avec une représentation temporelle, l'heure est supposée être en heure locale.
C'est ce que je veux. Mon heure locale est également réglée correctement. Je ne sais pas pourquoi la date dérangerait le fuseau horaire dans ce cas simple de moi fournissant une date et voulant en soustraire quelque chose. Ne devrait-il pas soustraire les heures de la chaîne de date en premier? Même s'il la convertit d'abord en date, puis effectue la soustraction, si je laisse de côté toutes les soustractions, j'obtiens exactement ce que je veux:
$ date -d "2019-01-19T05:00:00" +%Y-%m-%d_%H:%M:%S
2019-01-19_05:00:00
Donc , SI c'est vraiment un problème de fuseau horaire, où est - ce que la folie vient?
Réponses:
Ce dernier exemple aurait dû clarifier les choses pour vous: les fuseaux horaires .
Comme la sortie varie clairement selon le fuseau horaire, je soupçonne une valeur par défaut non évidente prise pour une chaîne de temps sans fuseau horaire spécifié. En testant quelques valeurs, cela semble être UTC-05: 00 , bien que je ne sois pas sûr de ce que c'est.
Il n'est utilisé que lors de l'exécution de l'arithmétique des dates.
Il semble que le problème ici ne
- 2 hours
soit pas pris comme arithmétique, mais comme spécificateur de fuseau horaire :Donc, non seulement pas être arithmétique fait, il semble y avoir une
heure d'étéajustement de 1 heure sur le temps, ce qui conduit à un temps un peu de sens pour nous.Cela vaut également pour l'addition:
Débogage un peu plus, l'analyse semble être:
2019-01-19T05:00:00 - 2
(-2
étant le fuseau horaire), ethours
(= 1 heure), avec un ajout implicite. Il devient plus facile de voir si vous utilisez des minutes à la place:Donc, bien, l'arithmétique des dates est en cours, mais pas celle que nous avons demandée. ¯ \ (ツ) / ¯
la source
TZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
vsTZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S
)date
la norme ISO 8601, si aucun fuseau horaire n'est fourni, l'heure locale (fuseau) doit être supposée, ce qui n'est pas le cas en cas d'opération arithmétique. Un problème très étrange pour moi.- 2 hours
est pris ici comme spécificateur de fuseau horaire.--debug
option de la date ! Grande explication.Cela fonctionne correctement lorsque vous convertissez d'abord la date d'entrée en ISO 8601:
la source
date
cela gâcherait car sans aucune soustraction fournie, le fuseau horaire reste intact et tout est comme prévu sans avoir à fournir de informations sur le fuseau horaire ou conversion.date -I
2018-12-10T00:00:00+02:00
TLDR: Ce n'est pas un bug. Vous venez de découvrir l'un des comportements subtils mais documentés de
date
. Lorsque vous effectuez l'arithmétique temporelle avecdate
, utilisez un format indépendant du fuseau horaire (comme l'heure Unix) ou lisez très attentivement la documentation pour savoir comment utiliser correctement cette commande.GNU
date
utilise vos paramètres système (laTZ
variable d'environnement ou, s'il n'est pas défini, les paramètres système par défaut) pour déterminer le fuseau horaire de la date alimentée avec l' option-d
/--date
et la date signalée par l'+format
argument. L'--date
option vous permet également de remplacer le fuseau horaire pour son propre argument d'option, mais elle ne remplace pas le fuseau horaire de+format
. C'est la racine de la confusion, à mon humble avis.Étant donné que mon fuseau horaire est UTC-6, comparez les commandes suivantes:
Le premier utilise mon fuseau horaire pour les deux
-d
et+format
. Le second utilise UTC pour-d
mais mon fuseau horaire pour+format
. Le troisième utilise UTC pour les deux.Maintenant, comparez les opérations simples suivantes:
Même si l'heure Unix me dit la même chose, l'heure "Normal" diffère en raison de mon propre fuseau horaire.
Si je voulais faire la même opération mais en utilisant exclusivement mon fuseau horaire:
la source
-08:00
), ajoutez simplement cela pour entrer la date-heure ... rien d'autre à manipuler. Exemple:date -d '2019-02-28 14:05:36-08:00 +2 days 4 hours 3 seconds' +'local: %F %T'
donne local: 2019-03-02 18:05:36+format
argument. Par exemple, sur mon système, la même commande affiche:local: 2019-03-02 20:05:39
(si j'ajoute%:z
à+format
, il devient évident que les informations sont correctes et que l'écart est dû aux fuseaux horaires).-d
et+format
ou le temps Unix, comme je l'ai dit dans la réponse, pour éviter des résultats inattendus.GNU
date
prend en charge l'arithmétique simple des dates, bien que les calculs d'époque comme indiqué dans la réponse de @sudodus soient parfois plus clairs (et plus portables).L'utilisation de +/- quand aucun fuseau horaire n'est spécifié dans l'horodatage déclenche une tentative de correspondance avec un fuseau horaire avant, avant toute autre analyse.
Voici une façon de le faire, utilisez "il y a" au lieu de "-":
ou
(Bien que vous ne puissiez pas utiliser arbitrairement "Z", cela fonctionne dans ma zone, mais cela en fait un horodatage de zone UTC / GMT - utilisez votre propre zone, ou% z /% Z en l'ajoutant
${TZ:-$(date +%z)}
à l'horodatage à la place.)L'ajout de termes de temps supplémentaires à ces formulaires ajuste le temps:
De nombreux ajustements complexes, dans n'importe quel ordre, peuvent être utilisés (bien que des termes relatifs et variables comme "14 semaines donc lundi dernier" demandent des ennuis ;-)
(Il y a un autre petit ourson ici aussi,
date
donnera toujours une date valide, doncdate -d "2019-01-31 1 month"
donne 2019-03-03, comme le "mois prochain")Compte tenu de la grande variété de formats d'heure et de date pris en charge, l'analyse du fuseau horaire est nécessairement bâclée: il peut s'agir d'un suffixe à une ou plusieurs lettres, d'un décalage d'une heure ou d'une heure: minute, d'un nom "America / Denver" (ou même d'un nom de fichier dans le cas de la
TZ
variable).Votre
2018-12-10T00:00:00
version ne fonctionne pas parce que "T" est juste un délimiteur, pas un fuseau horaire, l'ajout de "Z" à la fin rend ce travail (sous réserve de l'exactitude de la zone choisie) comme prévu aussi.Voir: https://www.gnu.org/software/tar/manual/html_node/Date-input-formats.html et en particulier la section 7.7.
la source
date -d "2018-12-10 00:00:00 now -5 hours
outoday
ou0 hour
au lieu denow
, tout ce qui indiquedate
que le jeton après l'heure n'est pas un décalage de fuseau horaire.Cette solution est facile à comprendre, mais un peu plus compliquée, je la présente donc sous forme de script shell.
date
ligne de commande finaleShellscript:
la source