Comando date

O comando date permite exibir e alterar a data/hora do sistema em diferentes formatos, e até mesmo efetuar cálculos de tempo. Veja alguns parâmetros que podem ser utilizados para formatação de datas:

  • %Y : ano
  • %y : os dois últimos dígitos do ano
  • %j : dia ano (1 a 366)
  • %m : mês (1 a 12)
  • %A : dia da semana (domingo,…, sábado)
  • %a : dia da semana abreviado (dom,…, sab)
  • %w : dia da semana, onde 0 = domingo, 1 = segunda,…, 6 = sábado
  • %B : nome do mês (janeiro,…, dezembro)
  • %b : nome do mês abreviado (jan,…, dez)
  • %c : dia da semana, data e hora
  • %d : dia do mês (00-31)
  • %T : hora no formato hh:mm:ss
  • %H : hora do dia (0 a 23)
  • %M : minuto (0 a 59)
  • %S : segundos (0 a 61)
  • %s : número de segundos desde das zero horas de 01/01/1970

Veja esse exemplo que converte dia do ano (vide tabela mais acima) em data “ANO-MÊS-DIA” (inclusive considerando os anos bissextos):

date -d "$(($dia_do_ano-1)) days $ano-01-01" +"%Y-%m-%d"

Dica: o recurso ‘2016-03-31 +1 month’ pode resultar na data ‘2016-05-01’, porque ‘2016-04-31’ é uma data inválida. Para determinar o mês seguinte de forma mais confiável, pode-se pedir para o mês do dia 15 do mês seguinte ao atual, como no exemplo abaixo.

date +"%B %Y" --date="$(date "+%Y-%m-15") next month"

Caso apareça um erro do tipo “date: data inválida” (principalmente após começar um período de horário de verão), experimente colocar um horário qualquer depois da data, ainda dentro das aspas duplas (” 12:00″, por exemplo).

Para mais opções do comando date e para ver como acertar data, hora e fuso horário, clique nos respectivos links.

Convertendo uma data escrita em hexadecimal para calendário “normal”

O número de segundos do início da data UNIX (iniciada à meia noite de 1 de janeiro de 1970) até a data GPS (iniciada à meia noite de 6 de janeiro de 1980) pode ser obtido através do seguinte comando:

date -u -d "1980-01-06 00:00:00" +%s

Para ver mais detalhes sobre os conceitos de Era Linux, GPS time e leap secondes, veja o post Formas alternativas de medir o tempo. Segue um comando para converter hexadecimal (3FC29A80, por exemplo) em “time stamp” no formato YYYY-MM-DD HH:MM:SS no sistema GPS (ou seja, descontando 16 leap seconds):

date -u --date @$((`printf '%d\n' 0x3FC29A80`+315964800-16)) '+%Y-%m-%d %T'

O parâmetro ‘-u’ converte para UTC e o “@” serve para indicar que é uma time stamp. As operações matemáticas de adição e subtração devem ser realizadas dentro de “$((a+b-c))”.

O comando printf imprime na tela a mensagem, substituindo caracteres de controles, sendo que o %d captura somente números inteiros, %f os números com casas decimais flutuantes e %s strings de caracteres. Veja mais parâmetros do printf clicando no link. O formato %X (%x para letras minúsculas) serve para número hexadecimal.

O sistema de numeração hexadecimal representa os números em base 16, ou seja, em ordem crescente os elementos são “0,1,2,3,4,5,6,7,8,9A,B,C,D,E,F”. É muito utilizado em informática, pois os computadores costumam utilizar o byte ou octeto (pois representa 28 valores possíveis) como unidade básica da memória.

Exemplo de script manipulando datas

Segue um script que utiliza os comandos vistos para criar diretórios com a data dos arquivos obtidas a partir do nome dos mesmos. Os nomes dos arquivos foram gravados a partir da informação de tempo de um GPS (ou seja, a hora está correta mas não está em UTC, e sim em GPS time) em hexadecimal. Cabe ao comando date converter para uma data UTC (conforme visto), gravando o resultado em uma string que será dividida em diferentes campos (hora, mês, etc) para formar os nomes dos respectivos diretórios para os quais os arquivos serão movidos.

No exemplo, os diretórios estão divididos de modo a receber os dados dos últimos 15 minutos. Assim, ao criar o nome de um diretório não devem surgir nomes contendo horas como “24” nem dias como “32”, daí que aparecem as exceções no último “elif” – destaque para o modo que foi calculado o “último dia do mês” utilizando o comando cal.

#!/bin/bash
# Script para converter um valor hexadecimal em time stamp

function coloca_zero(){
    a=$1
    b=`echo "$a" | wc -L | awk '{print $1}'`
    while [ $b != 2 ]; do
        b=$((b+1))
        a=0$a
    done
    echo $a
}

for file in *.gz; do
	hexa=`echo "${file%%.*}"`
	hexa_to_sec=`printf '%d\n' 0x$hexa`
	# Agrupar arquivos entre 00-14 | 15-29 | 30-44 | 45-59
	date_str=`date -u --date @$(($hexa_to_sec+315964800-16)) '+%Y:%m:%d:%T'`
	min=`echo $date_str | awk -F":" '{print $5}'`
	hour=`echo $date_str | awk -F":" '{print $4}'`
	day=`echo $date_str | awk -F":" '{print $3}'`
	month=`echo $date_str | awk -F":" '{print $2}'`
	year=`echo $date_str | awk -F":" '{print $1}'`
	if [ $min -lt 15 ]; then
		min_new=15
	elif [ $min -ge 15 -a $min -lt 30 ]; then
		min_new=30
	elif [ $min -ge 30 -a $min -lt 45 ]; then
		min_new=45
	elif [ $min -ge 45 ]; then
		min_new=00
		hour=$((10#$hour+1))
		hour=`coloca_zero "$hour"`
		if [ $hour -eq 24 ]; then
			hour=00
			day=$((10#$day+1))
			day=`coloca_zero "$day"`
			# Ultimo dia do mes
			last_day=`echo $(cal $month $year) | awk '{print $NF}'`
			last_day_err=$(($last_day+1))
			if [ $day -eq $last_day_err ]; then
				day=01
				month=$((10#$month+1))
				month=`coloca_zero "$month"`
				if [ $month -eq 13 ]; then
					month=12
					year=$(($year+1))
				fi
			fi
		fi
	fi
	name_dir=$year-$month-${day}_$hour$min_new
	#echo $name_dir
	mkdir -p $name_dir
	mv $file $name_dir
done

Os caracteres “10#” servem para forçar a leitura da variável como um decimal – no caso de ter um zero na frente do número (por exemplo “03”), o bash interpreta como hexadecimal. Uma data pode ser impressa sem o zero à esquerda usando um sinal de “menos” depois da porcentagem por exemplo ‘+%-d’ para imprimir o dia sem zero à esquerda caso tenha somente um dígito.

O script a seguir cria uma lista de n dias a partir de uma data inicial informada (considerando anos bissextos) – muito útil para servir de gabarito ao comparar uma lista de datas existente e descobrir se estão faltando dias e quais são eles:

data_inicial="01/01/2013"
n_dias=400
for i in $(seq 0 $n_dias); do
	date -d "$data_inicial +$i day" +%d/%m/%Y
done

Extra: comando gcal

O Gcal é um programa para calcular e imprimir calendários. Ele exibe folhas de calendário Juliano e gregoriano, por um mês, três meses ou um ano inteiro, assim como tem suporte para outros sistemas de calendário, por exemplo, os calendários chinês e japonês, o calendário hebraico e o calendário civil islâmico. Ele também exibe listas de feriados e datas fixas para muitos países ao redor do mundo, além de calcular vários dados astronômicos e os tempos do Sol e da Lua em qualquer lugar, com precisão suficiente para a maioria dos propósitos civis.

gcal --holiday-list --cc-holidays=br

O programa pode ser instalado através do comando “sudo apt-get install gcal”. O comando acima apresenta a lista de feriados (+) e algumas datas comemorativas (*) no Brasil para o ano atual, com a data, o dia da semana e o número de dias que já passaram ou ainda faltam para cada uma.

Leave a Reply

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.