Na verdade, existe também um pacote chamado coreutils-date
! Não sabia disso! Existe toda a funcionalidade padrão incluída!
Estou usando o OpenWRT no Arduino YUN e estou tentando obter a data exata em milissegundos (DD / MM / AAAA h: min: seg: ms) obtendo a hora em um servidor de horário.
Infelizmente date +%N
apenas retorna %N
, mas não os nanossegundos. Ouvi +%N
não está incluído na data do OpenWRT.
Então, há alguma maneira de obter a data (incluindo milissegundos) como eu quero?
No OpenWRT, date
é busybox
, que possui limitações, mas isso não é estritamente uma delas. O problema subjacente é que a libc (uClibc) não suporta esta extensão GNU strftime . (Embora nem o glibc, mais sobre isso abaixo.)
Você deve ter lua
por padrão, mas não ajudará sem alguns outros módulos não padrão.
hwclock
chamadas gettimeofday()
para comparar / definir o RTC (relógio de hardware), mas não produzirá resolução de sub-segundo (acessar RTCs pode ser lento o suficiente para não ser útil de qualquer maneira). Além disso, o OpenWRT fornece apenas o antigo rdate
, que tem apenas resolução de segundo inteiro.
Parece não haver nenhuma maneira direta de obter um registro de tempo exato diretamente de /proc
, o carimbo de data mais útil é em /proc/timer_list
(terceira linha), que é o tempo de atividade em nanossegundos (a resolução dependerá da plataforma ).
Se o seu busybox foi construído com CONFIG_BUSYBOX_CONFIG_ADJTIMEX
set, então você poderá usar adjtimex
para ler o relógio do kernel (embora note que a versão do busybox tem ambos argumentos diferentes e saída diferente para o adjtimex padrão.
Versão normal, adjtimex -p
, última linha de saída:
raw time: 1416419719s 146628us = 1416419719.146628
Versão do Busybox, adjtimex
(sem -p
!), últimas 3 linhas:
[...]
time.tv_sec: 1416420386
time.tv_usec: 732653
return value: 0 (clock synchronized)
Cachinhos Dourados é uma ótima solução, supondo que você tenha sua configuração de construção cruzada do OpenWRT (altamente recomendada!).
Sua solução coreutils-date funciona porque, embora o coreutils esteja ciente, ele não é exclusivo da glibc. Ele vem com sua própria implementação independente de strftime
(derivada da glibc), e usa isso para finalizar (via strftime_case()
) o strftime
subjacente de modo a suportar várias extensões (e voltar para a versão uClibc) .
Mesmo o glibc (até o atual 2.23) não suporta %N
, o coreutils strftime()
derivado da versão glibc canônica adiciona %N
e %:z
e algumas outras alterações. Variações e versões corrigidas de strftime()
são abundantes (incluindo versões no bash e gawk).
Se você tiver um compilador C e não conseguir encontrar mais nada, isso informará, por exemplo,
> millitime && sleep 1 && millitime
14/11/2014 9:39:49:364
14/11/2014 9:39:50:368
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
int main (void) {
struct timeval now;
struct tm *parsed;
if (gettimeofday(&now, NULL) == -1) {
fprintf (
stderr,
"gettimeofday() failed: %s\n",
strerror(errno)
);
return 1;
}
parsed = localtime((const time_t*)&now.tv_sec);
if (!parsed) {
fprintf (
stderr,
"localtime() failed: %s\n",
strerror(errno)
);
return 1;
}
printf (
"%d/%d/%d %d:%02d:%02d:%03d\n",
parsed->tm_mday,
parsed->tm_mon + 1,
parsed->tm_year + 1900,
parsed->tm_hour,
parsed->tm_min,
parsed->tm_sec,
now.tv_usec / 1000
);
return 0;
}
Com o gcc, apenas compile gcc whatever.c -o millitime
. Se houver um erro (o que seria muito estranho), ele será reportado para stderr e sairá com um status de 1. Caso contrário, ele será reportado como stdout e sairá de 0.
Os milissegundos são arredondados para baixo em microssegundos.
#include <stdio.h>
#include <time.h>
void main (void){
long ms;
time_t s;
struct timespec spec;
clock_gettime(CLOCK_REALTIME, &spec);
s = spec.tv_sec;
ms = (spec.tv_nsec / 1.0e6);
printf("%d%03d\n", s, ms);
return 0;
}
Isso na linguagem C e funciona como coreutils-date date +%s%3N
. É compilado para o roteador OpenWrt com o OpenWrt-SDK.
A solução adjtimex
não funcionou para mim porque recebo adjtimex: Operation not permitted
(estou usando um contêiner docker alpino). Mas eu encontrei outra solução bizarra, mas livre de dependência, usando nmeter
, que pode exibir até microssegundos.
#-d0 means print every 0 seconds ie immediately
# head -n1 makes sure it only does it once
nmeter -d0 '%3t' | head -n1
Combinando isso com o comando date:
date -u +%FT$(nmeter -d0 '%3t' | head -n1)Z
# 2017-05-03T04:10:57.863Z
Obtemos uma string de data e hora UTC rfc3339 com milissegundos!