รับวันที่เมื่อวานในทุบตีบน Linux, DST- ปลอดภัย


158

ฉันมีเชลล์สคริปต์ที่ทำงานบน Linux และใช้สายนี้เพื่อรับวันที่ในYYYY-MM-DDรูปแบบของเมื่อวาน:

date -d "1 day ago" '+%Y-%m-%d'

มันทำงานมากที่สุดของเวลา แต่เมื่อสคริปต์วิ่งตอนเช้าเมื่อวานนี้ที่2013-03-11 0:35 CDTมันกลับมาแทน"2013-03-09""2013-03-10"

น่าจะเป็นการปรับเวลาตามฤดูกาล (ซึ่งเริ่มเมื่อวานนี้) ฉันคาดเดาวิธีการที่"1 day ago"จะดำเนินการก็หักออก 24 ชั่วโมงและ 24 ชั่วโมงก่อนที่จะ2013-03-11 0:35 CDTเป็นซึ่งนำไปสู่ผลมาจากการ2013-03-09 23:35 CST"2013-03-09"

ดังนั้นวิธีการที่ดีเวลาที่ปลอดภัยที่จะได้รับวันที่เมื่อวานในทุบตีบน Linux คืออะไร?


คุณมักจะเรียกใช้สิ่งนี้ในเวลาเดียวกัน
ทิงค์

@tink มันทำงานทุกวันเวลา 00:35
Ike Walker

คำตอบ:


267

ฉันคิดว่าสิ่งนี้จะทำงานได้โดยไม่คำนึงถึงความถี่และเวลาที่คุณเรียกใช้ ...

date -d "yesterday 13:00" '+%Y-%m-%d'

1
คุณจะกำหนดสิ่งนี้ให้กับตัวแปรเพื่อใช้ในภายหลังได้อย่างไร
null

6
@null - เช่นเดียวกับที่คุณกำหนดเอาต์พุตของคำสั่งเชลล์อื่น ๆ ตัวแปร = $ (วันที่ -d "เมื่อวานนี้ 13:00" '+% Y-% m-% d') ...
tink

สำหรับ GNU-date:date -d yesterday 13:00 -I
gogstad

สิ่งนี้ขึ้นอยู่กับความจริงที่ว่าการสลับไปมาระหว่างฤดูร้อนและฤดูหนาวมักจะทำในช่วงกลางคืนถ้าฉันเข้าใจถูกต้องหรือไม่
Nicolas Raoul

2
@NicolasRaoul: ไม่รับประกัน แต่มันเป็นการประชุมที่มีผู้ติดตามอย่างกว้างขวางในการกำหนดเวลานี้ในตอนเช้า ในทางตรงกันข้ามมี IIRC ไม่มีสถานที่ที่สวิตช์จะเกิดขึ้นใกล้กับเที่ยงท้องถิ่น ดังนั้น "1300J ไม่เคยมีในขอบเขตเวลา" คือการที่เหมาะสมสมมติฐาน
Piskvor ออกจากอาคาร

56

วันที่ภายใต้ Mac OSX นั้นแตกต่างกันเล็กน้อย

สำหรับเมื่อวาน

date -v-1d +%F

สำหรับสัปดาห์ที่แล้ว

date -v-1w +%F

8
หากสนใจที่จะใช้สไตล์ GNU ใน OSX คุณสามารถใช้gdateงานได้ในcoreutilsแพ็คเกจของโฮมบรูว์
user456584

11
คุณหมายความว่าdateแตกต่าง
2559

12

สิ่งนี้ควรใช้งานได้ แต่อาจมากเกินไป:

date -d @$(( $(date +"%s") - 86400)) +"%Y-%m-%d"

สิ่งนี้เป็นสิ่งจำเป็นถ้าคุณต้องการที่จะจัดการกับ Mac OS X dateซึ่งไม่สนับสนุนyesterdayไวยากรณ์ ...
Mikko Rantalainen

7

หากคุณแน่ใจว่าสคริปต์ทำงานในชั่วโมงแรกของวันคุณสามารถทำได้

  date -d "12 hours ago" '+%Y-%m-%d'

BTW หากสคริปต์ทำงานทุกวันเวลา 00:35 (ผ่าน crontab?) คุณควรถามตัวเองว่าจะเกิดอะไรขึ้นหากการเปลี่ยนแปลง DST ลดลงในชั่วโมงนั้น สคริปต์ไม่สามารถรันหรือรันสองครั้งในบางกรณี การใช้งานที่ทันสมัยของcronมีค่อนข้างฉลาดในเรื่องนี้แม้ว่า


5

คุณสามารถใช้ได้

date -d "30 days ago" +"%d/%m/%Y"

เพื่อรับวันที่จาก 30 วันที่ผ่านมาเช่นเดียวกันคุณสามารถแทนที่ 30 ด้วย x จำนวนวัน


คุณควรเปลี่ยนรูปแบบของคุณเพื่อ%Y%m%dให้ตรงกับคำถาม ฉัน upvoted ต่อไปเพราะมันทำงานอย่างถูกต้อง
isapir

4

นี่เป็นวิธีแก้ปัญหาที่จะทำงานกับ Solaris และ AIX เช่นกัน

การจัดการเขตเวลาเป็นไปได้สำหรับการเปลี่ยนนาฬิกาบางชั่วโมง เนื่องจากเวลาออมแสง 24 ชั่วโมงที่ผ่านมาสามารถเป็นวันนี้หรือวันก่อนเมื่อวาน

คุณแน่ใจว่าเมื่อวานนี้คือ 20 หรือ 30 ชั่วโมงที่ผ่านมา อันไหน? ดีล่าสุดที่ไม่ใช่วันนี้

echo -e "$(TZ=GMT+30 date +%Y-%m-%d)\n$(TZ=GMT+20 date +%Y-%m-%d)" | grep -v $(date +%Y-%m-%d) | tail -1

พารามิเตอร์ -e ที่ใช้ในคำสั่ง echo จำเป็นต้องใช้กับ bash แต่จะไม่ทำงานกับ ksh ใน ksh คุณสามารถใช้คำสั่งเดียวกันโดยไม่มีแฟล็ก -e

เมื่อสคริปต์ของคุณจะถูกใช้ในสภาพแวดล้อมที่แตกต่างกันคุณสามารถเริ่มต้นสคริปต์ด้วย #! / bin / ksh หรือ #! / bin / bash คุณสามารถแทนที่ \ n ด้วยบรรทัดใหม่:

echo "$(TZ=GMT+30 date +%Y-%m-%d)
$(TZ=GMT+20 date +%Y-%m-%d)" | grep -v $(date +%Y-%m-%d) | tail -1

0

เพียงใช้dateและเชื่อถือวินาที:

ในขณะที่คุณชี้ให้เห็นอย่างถูกต้องรายละเอียดจำนวนมากเกี่ยวกับการคำนวณพื้นฐานจะถูกซ่อนหากคุณใช้การคำนวณเวลาภาษาอังกฤษ เช่น-d yesterdayและ-d 1 day agoจะมีพฤติกรรมที่แตกต่าง

แต่คุณสามารถเชื่อถือได้ขึ้นอยู่กับวินาที (บันทึกไว้อย่างแม่นยำ) ตั้งแต่ unix epoch UTC และ bash arithmetic เพื่อรับช่วงเวลาที่คุณต้องการ:

date -d @$(( $(date +"%s") - 24*3600)) +"%Y-%m-%d"

นี้ก็ชี้ให้เห็นในอีกคำตอบ แบบฟอร์มนี้สามารถพกพาข้ามแพลตฟอร์มที่มีการdateตั้งค่าสถานะบรรทัดคำสั่งต่างกันเป็นภาษาที่ไม่ขึ้นกับภาษา (เช่น "เมื่อวาน" เทียบกับ "hier" ในภาษาฝรั่งเศส) และตรงไปตรงมา (ในระยะยาว) จะง่ายต่อการจดจำ รู้แล้ว คุณอาจถามตัวเองต่อไปว่า: "เป็นอย่างนั้น-d 2 hours agoหรือ-d 2 hour agoอีกครั้ง?" หรือ "มันเป็น-d yesterdayหรือ-d 1 day agoที่ฉันต้องการ?") @บิตหากินเฉพาะที่นี่เป็น

อาวุธทุบตีและไม่มีอะไรอื่น:

ทุบตีบนทุบตีเท่านั้นคุณยังสามารถรับเวลาของเมื่อวานผ่าน printf builtin:

 %(datefmt)T
     causes printf to output the date-time string resulting from using
     datefmt as a format string for strftime(3).  The  corresponding  argu
     ment  is an integer representing the number of seconds since the
     epoch.  Two special argument values may be used: -1 represents the
     current time, and -2 represents the time the shell was invoked.
     If no argument is specified, conversion behaves as if -1 had
     been  given.
     This is an exception to the usual printf behavior.

ดังนั้น,

# inner printf gets you the current unix time in seconds
# outer printf spits it out according to the format
printf "%(%Y-%m-%d)T\n" $(( $(printf "%(%s)T" -1) - 24*3600 ))

หรือเทียบเท่ากับตัวแปร temp (ตัวเลือก subshell ด้านนอก แต่ทำให้สภาพแวดล้อมของ vars สะอาด)

(
  now=$(printf "%(%s)T" -1);
  printf "%(%Y-%m-%d)T\n" $((now - 24*3600));
)

หมายเหตุ: แม้จะมี manpage ที่ระบุว่าไม่มีการโต้แย้งกับตัว%()Tจัดรูปแบบจะถือว่าเป็นค่าเริ่มต้น-1แต่ฉันดูเหมือนจะได้รับ 0 แทน (ขอบคุณ bash manual version 4.3.48)


0
date -d "yesterday" '+%Y-%m-%d'

หากต้องการใช้สิ่งนี้ในภายหลัง:

date=$(date -d "yesterday" '+%Y-%m-%d')

2
ในขณะที่รหัสนี้อาจแก้ไขปัญหาของ OP ได้ดีกว่าที่จะรวมคำอธิบายเกี่ยวกับวิธีที่รหัสของคุณแก้ไขปัญหาของ OP ด้วยวิธีนี้ผู้เข้าชมในอนาคตสามารถเรียนรู้จากโพสต์ของคุณ & ใช้กับโค้ดของตนเอง ดังนั้นไม่ใช่บริการการเข้ารหัส แต่เป็นแหล่งความรู้ คำตอบที่มีคุณภาพสูงเสริมความคิดนี้ให้สมบูรณ์และมีแนวโน้มที่จะถูกยกเลิก คุณสมบัติเหล่านี้รวมถึงข้อกำหนดที่โพสต์ทั้งหมดมีอยู่ในตัวเองเป็นจุดแข็งของ SO ในฐานะแพลตฟอร์มที่ทำให้เราแตกต่างจากฟอรัม คุณสามารถแก้ไขเพื่อเพิ่มข้อมูลเพิ่มเติม & / หรือเสริมคำอธิบายของคุณด้วยเอกสารต้นฉบับ
SherylHohman

0

คุณสามารถใช้ได้:

date -d "yesterday 13:55" '+%Y-%m-%d'

หรือเวลาใดก็ตามที่คุณต้องการดึงข้อมูลจะถูกเรียกคืนโดยการทุบตี

สำหรับเดือน:

date -d "30 days ago" '+%Y-%m-%d'

0

ตามคำถามนี้ถูกติดแท็ก "DST ปลอดภัย"

และการใช้ fork to datecommand implie delay มีวิธีที่ง่ายและมีประสิทธิภาพมากขึ้นโดยใช้bashในตัว:

printf -v tznow '%(%z %s)T' -1
TZ=${tznow% *} printf -v yesterday '%(%Y-%m-%d)T' $(( ${tznow#* } - 86400 ))
echo $yesterday

สิ่งนี้เร็วกว่ามากในระบบที่เป็นมิตรมากกว่าที่จะต้องแยกจากdateกัน

จาก V> = 5.0มีตัวแปรใหม่$EPOCHSECONDS

printf -v tz '%(%z)T' -1
TZ=$tz printf -v yesterday '%(%Y-%m-%d)T' $(( EPOCHSECONDS - 86400 ))
echo $yesterday
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.