วิธีแยกวิเคราะห์วันที่ ISO8601 ด้วยคำสั่ง linux date


15

ฉันพยายามใช้คำสั่ง date เพื่อสร้างการประทับเวลาของไฟล์ที่คำสั่ง date สามารถตีความได้ อย่างไรก็ตามคำสั่ง date ดูเหมือนจะไม่ชอบผลลัพธ์ของตัวเองและฉันไม่แน่ใจว่าจะแก้ไขได้อย่างไร กรณีในจุด:

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

วันที่ดูเหมือนจะตีความสตริงด้วยการชดเชย 15 ชั่วโมง มีวิธีแก้ปัญหาที่รู้จักสำหรับเรื่องนี้หรือไม่?

แก้ไข: นี่ไม่ใช่ปัญหาของการแสดงผล:

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
>>> 

มันยังคงปิดอยู่ 15 ชั่วโมงเมื่อแสดงเป็น unix timestamp

แก้ไข # 1

บางทีฉันควรตั้งคำถามนี้ให้แตกต่างออกไปเล็กน้อย ว่าฉันมีรายการของการประทับเวลาพื้นฐาน ISO8601 ของแบบฟอร์ม:

  • YYYYMMDDThhmm
  • YYYYMMDDThhmmss

วิธีที่ง่ายที่สุดในการแปลงเป็นเวลา Unix ที่สอดคล้องกันคืออะไร?

ตัวอย่างเช่น:

- 20140103T1422   = 1388787720
- 20140103T142233 = 1388787753

1
@drewbenn ฉันไม่สามารถมีอักขระพิเศษในการประทับเวลา เพียงแค่ตัวเลขและตัวอักษร ดังนั้นไม่ฉันไม่สามารถทำเช่นนั้นโชคไม่ดี
alex.forencich

@sim TZ ไม่ได้ตั้งค่า แต่ / etc / localtime เชื่อมโยง
alex.forencich

คุณกำลังฆ่าฉันนี่คือคำถามสุดท้ายของคุณหรือไม่ 8-)
slm

20140103T1518ไม่ถูกต้อง ISO 8601 มันพลาดส่วนของโซนเวลา
Ferrybig

คำตอบ:


9

คุณถามหา "วิธีแก้ปัญหาที่รู้จัก" นี่คือง่าย ๆ :

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

ใช้sedเพื่อแทนที่ "T" ด้วยช่องว่าง ผลลัพธ์คือรูปแบบที่dateเข้าใจได้

หากเราเพิ่มวินาทีลงในวันที่ ISO8601 ดังนั้นdateต้องมีการเปลี่ยนแปลงเพิ่มเติม:

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

ในข้างต้นsedแทนที่ "T" ด้วยช่องว่างและยังแยก HHMMSS เป็น HH: MM: SS


ใช้งานได้สำหรับฉันหากมีการลบ + อย่างไรก็ตามมันใช้ไม่ได้กับการประทับเวลาความแม่นยำที่สองเพียงความแม่นยำนาที
alex.forencich

@ alex.forencich คำตอบอัพเดทด้วยความแม่นยำวินาที แจ้งให้เราทราบหากรูปแบบวินาทีที่ฉันเลือกไม่ใช่รูปแบบที่คุณต้องการ
John1024

8

ข้อมูล coreutils เอกสารกล่าวว่ามาตรฐาน ISO 8601 "รูปแบบการขยาย" ได้รับการสนับสนุน

คุณจะต้องเพิ่มยัติภังค์เครื่องหมายโคลอนและ a +%zเพื่อให้ใช้งานได้

$ 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

เพื่อตอบคำถามที่สองของคุณ ...

เนื่องจากรูปแบบวันที่มีเฉพาะตัวเลขและสัญลักษณ์คุณสามารถแทนที่แต่ละสัญลักษณ์ด้วยตัวอักษรที่ไม่ซ้ำกันเช่นการใช้ 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

หรือคุณสามารถแยกมันโดยใช้Tและ-หรือ+เป็นตัวคั่นเช่นการใช้เปลือก${var%word}และ${var#word}การขยายตัว

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

หรือใช้bashการจับคู่นิพจน์ทั่วไป

$ 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

หรือ Perl, Python และอื่น ๆ เป็นต้น


การประทับเวลาไม่สามารถมีอักขระพิเศษใด ๆ อยู่ภายในได้ คุณรู้วิธีที่ดีในการเพิ่มสิ่งเหล่านั้นกลับเข้ามาโดยอัตโนมัติหรือไม่?
alex.forencich

6

coreutils ของ GNU รองรับวันที่ ISO 8601เป็นอินพุตตั้งแต่รุ่น 8.13 (เผยแพร่เมื่อ 2011-09-08) คุณต้องใช้เวอร์ชันที่เก่ากว่า

ภายใต้รุ่นที่เก่ากว่าคุณจะต้องแทนที่Tด้วยการเว้นวรรค มิฉะนั้นจะถูกตีความว่าเป็นโซนเวลาของกองทัพสหรัฐ

แม้จะอยู่ภายใต้เวอร์ชันล่าสุดจะมีการจดจำเฉพาะรูปแบบที่คั่นด้วยเครื่องหมายเท่านั้นไม่ใช่รูปแบบพื้นฐานที่มีเฉพาะตัวเลขและ a ที่Tอยู่ตรงกลาง

# 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

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.

มันไม่ได้เป็นข้อสรุป แต่จะไม่แสดงสตริงรูปแบบเวลาที่มีสิ่งTที่คุณกำลังพยายามอย่างชัดเจนสำหรับ [ISO 8601] ตามที่ระบุในคำตอบ @GillesการสนับสนุนISO 8601 ใน GNU CoreUtilsค่อนข้างใหม่

การจัดรูปแบบสตริงใหม่

คุณสามารถใช้ Perl เพื่อกำหนดค่าสตริงของคุณ

ตัวอย่าง:

$ 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

คุณสามารถทำให้การจัดการนี้ทั้งสองสายที่มีวินาทีและผู้ที่ไม่ได้

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 - คำสั่งทางเลือกที่จะจัดการกับรูปแบบเวลาทั้งสอง ฉันชอบและลบความคิดเห็นข้างต้นที่ไม่เกี่ยวข้องอีกต่อไป
slm

1

ตามหน้า man of date รูปแบบที่คุณส่งออกนั้นไม่เหมือนกับที่คุณdateคาดหวังไว้ นี่คือสิ่งที่หน้าคนพูดว่า:

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

ดังนั้นคุณสามารถทำเช่นนี้:

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

เพราะในตัวแปรที่ใช้ในการกำหนดสตริงผลลัพธ์+%m%d%H%M%Yจะเท่ากับสิ่งที่คาดหวังว่าเป็นอินพุต


จากนั้นคุณสามารถให้คำสั่งเพื่อแมปวันที่จัดรูปแบบ ISO8601 กับวันที่ที่ต้องการได้หรือไม่? การประทับเวลาที่จัดเก็บจริงจะต้องอยู่ในรูปแบบ ISO8601 เพื่อให้สามารถเรียงลำดับตามวันที่
alex.forencich
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.