Linux tarih komutuyla ISO8601 tarihlerini ayrıştırma


15

Date komutunun yorumlayabileceği bir dosya zaman damgası oluşturmak için date komutunu kullanmaya çalışıyorum. Ancak, date komutu kendi çıktısını beğenmiyor gibi görünüyor ve bu soruna geçici bir çözüm bulmak için emin değilim. Konuşma konusu olan mesele:

sh-4.2$ date
Fri Jan  3 14:22:19 PST 2014
sh-4.2$ date +%Y%m%dT%H%M
20140103T1422
sh-4.2$ date -d "20140103T1422"
Thu Jan  2 23:22:00 PST 2014

tarih, dizeyi 15 saat uzaklıkla yorumluyor gibi görünüyor. Bunun için bilinen herhangi bir geçici çözüm var mı?

Düzenleme: Bu bir görüntüleme sorunu değildir:

sh-4.2$ date +%s
1388791096
sh-4.2$ date +%Y%m%dT%H%M
20140103T1518
sh-4.2$ date -d 20140103T1518 +%s
1388737080
sh-4.2$ python
Python 3.3.3 (default, Nov 26 2013, 13:33:18) 
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 1388737080 - 1388791096
-54016
>>> 54016/3600
15.004444444444445
>>> 

Unix zaman damgası olarak görüntülendiğinde hala 15 saat kapalıdır.

DÜZENLEME # 1

Belki bu soruyu biraz farklı bir şekilde sormalıyım. Diyelim ki formun ISO8601 temel zaman damgalarının bir listesi var:

  • YYYYMMDDThhmm
  • YYYYMMDDThhmmss

Bunları karşılık gelen Unix zaman damgalarına dönüştürmenin en basit yolu nedir?

Örneğin:

- 20140103T1422   = 1388787720
- 20140103T142233 = 1388787753

1
@drewbenn Zaman damgasında özel karakterlerim olamaz. Sadece rakamlar ve harfler. Yani hayır, ne yazık ki yapamam.
alex.forencich

@sim TZ ayarlanmamış, ancak / etc / localtime bağlı.
alex.forencich

Beni öldürüyorsun, bu senin son sorunun mu? 8-)
slm

20140103T1518geçerli değil ISO 8601, saat dilimi bölümünü özlüyor
Ferrybig

Yanıtlar:


9

"Bilinen geçici çözümler" istersiniz. İşte basit olanı:

$ date -d "$(echo 20140103T1422 | sed 's/T/ /')"
Fri Jan  3 14:22:00 PST 2014

Bu, sed"T" yerine bir boşluk koymak için kullanılır . Sonuç, dateanlayan bir biçimdir .

ISO8601 tarihine saniye eklersek, daha datefazla değişiklik gerektirir:

$ date -d "$(echo 20140103T142211 | sed -r 's/(.*)T(..)(..)(..)/\1 \2:\3:\4/')"
Fri Jan  3 14:22:11 PST 2014

Yukarıda sed"T" yerine bir boşluk konur ve ayrıca HHMMSS'yi HH: MM: SS'ye ayırır.


+ Silinirse benim için çalışır. Bununla birlikte, ikinci hassas zaman damgaları için çalışmaz, sadece dakika hassasiyeti.
alex.forencich

@ alex.forencich Yanıt saniye hassasiyetle güncellendi. Seçtiğim saniye formatının ihtiyacınız olan format olmadığını bildirin.
John1024

8

Coreutils bilgi dokümanlar ISO 8601 "genişletilmiş biçimi" desteklendiğini söylüyor.

+%zÇalışması için kısa çizgi, iki nokta üst üste ve a eklemeniz gerekir .

$ date +"%Y-%m-%dT%H:%M:%S%z"
2014-01-03T16:08:23-0800
$ date -d 2014-01-03T16:08:23-0800
Fri Jan  3 16:08:23 PST 2014

Sorunun ikinci bölümünü cevaplamak için ...

Tarih biçimi yalnızca sayı ve sembol içerdiğinden, her sembolü benzersiz bir harfle değiştirebilirsiniz, örneğin tr

$ ts="$(date +"%Y-%m-%dT%H:%M:%S%z" | tr -- '-:+' 'hcp')"; echo "$ts"
2014h01h03T16c18c04h0800
$ date -d "$(echo "$ts" | tr -- 'hcp' '-:+')"
Fri Jan  3 16:18:04 PST 2014

Veya, Tve -veya +ayırıcılarını kullanarak, örneğin kabuk ${var%word}ve ${var#word}genişletme kullanarak ayrıştırabilirsiniz

$ ts="$(date +"%Y%m%dT%H%M%S%z")"; echo "$ts"
20140103T162228-0800
$ date=${ts%T*}; time=${ts#*T}
etc.    

veya bashnormal ifade eşleşmesini kullanarak

$ ts="$(date +"%Y%m%dT%H%M%S%z")"; echo "$ts"
20140103T165611-0800
$ [[ "$ts" =~ (.*)(..)(..)T(..)(..)(..)(.....) ]]
$ match=("${BASH_REMATCH[@]}")
$ Y=${match[1]}; m=${match[2]}; d=${match[3]}; H=${match[4]}; M=${match[5]}; S=${match[6]}; z=${match[7]}
$ date -d "$Y-$m-$d"T"$H:$M:$S$z"
Fri Jan  3 16:56:11 PST 2014

veya Perl, Python vb.


Zaman damgasının içinde özel karakterler olamaz. Bunları otomatik olarak eklemenin iyi bir yolunu biliyor musunuz?
alex.forencich

6

GNU coreutils, 8.13 sürümünden (2011-09-08'de yayımlandı) bu yana girdi olarak ISO 8601 tarihlerini yalnızca desteklemiştir . Eski bir sürüm kullanıyor olmalısınız.

Eski sürümlerde, yerine Tbir boşluk koymanız gerekir . Aksi takdirde ABD askeri saat dilimi olarak yorumlanır .

Son sürümlerde bile, yalnızca tamamen noktalama işaretli form tanınır, yalnızca basamaklı ve Tortada olan temel format değil .

# Given a possibly abbreviated ISO date $iso_date...
date_part=${iso_date%%T*}
if [ "$date_part" != "$iso_date" ]; then
  time_part=${abbreviated_iso_date#*T}
  case ${iso_date#*T} in
    [!0-9]*) :;;
    [0-9]|[0-9][0-9]) time_part=${time_part}:00;;
    *)
      hour=${time_part%${time_part#??}}
      minute=${time_part%${time_part#????}}; minute=${minute#??}
      time_part=${hour}:${minute}:${time_part#????};;
  esac
else
  time_part=
fi
date -d "$date_part $time_part"

2

Bu notu man sayfasındaki için fark ettim date.

DATE STRING
      The --date=STRING is a mostly free format human readable date string
      such as "Sun, 29 Feb 2004 16:21:42 -0800"  or  "2004-02-29
      16:21:42"  or  even  "next Thursday".  A date string may contain 
      items indicating calendar date, time of day, time zone, day of
      week, relative time, relative date, and numbers.  An empty string 
      indicates the beginning of the day.  The date  string  format
      is more complex than is easily documented here but is fully described 
      in the info documentation.

Kesin değildir ancak T[ISO 8601] için açıklamaya çalıştığınız zamanı içeren bir zaman biçimi dizesi göstermez . As @Gilles cevap belirtilen destek GNU coreutils içerisinde ISO 8601 nispeten yenidir.

Dizeyi yeniden biçimlendirme

Dizenizi yeniden formüle etmek için Perl kullanabilirsiniz.

Misal:

$ date -d "$(perl -pe 's/(.*)T(\d{2})(\d{2})(\d{2})/$1 $2:$3:$4/' \
    <<<"20140103T142233")"
Fri Jan  3 14:22:33 EST 2014

Bu tanıtıcıyı hem saniye içeren hem de içermeyen dizeleri yapabilirsiniz.

20140103T1422:

$ date -d "$(perl -pe 's/^(.*)T(\d{2})(\d{2})(\d{2})$/$1 $2:$3:$4/ || \
     s/^(.*)T(\d{2})(\d{2})$/$1 $2:$3:00/' <<<"20140103T1422")"
Fri Jan  3 14:22:00 EST 2014

20140103T142233:

$ date -d "$(perl -pe 's/^(.*)T(\d{2})(\d{2})(\d{2})$/$1 $2:$3:$4/ || \
     s/^(.*)T(\d{2})(\d{2})$/$1 $2:$3:00/' <<<"20140103T142233")"
Fri Jan  3 14:22:33 EST 2014

@ alex.forencich - her iki saat biçimini de ele alacak alternatif bir komut. Bana bir iyilik yap ve yukarıda artık alakalı olmayan yorumları sil.
slm

1

Tarihin man sayfasına göre, çıkardığınız biçim, dategirdi olarak beklediğinizle aynı değil . Man sayfasının söylediği şey:

date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]]

Böylece bunu şöyle yapabilirsiniz:

# date +%m%d%H%M%Y
010402052014
# date 010402052014
Sat Jan  4 02:05:00 EAT 2014

Çünkü çıktı dizesini tanımlamak için kullanılan değişkenlerde +%m%d%H%M%Ygirdi olarak beklediği değere eşit olur.


O zaman bir ISO8601 format tarihini hangi tarihin gerektirdiği ile eşleştirmek için bir komut sağlayabilir misiniz? Saklanan gerçek zaman damgalarının tarihe göre sıralanabilmesi için ISO8601 biçiminde olması gerekir.
alex.forencich
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.