DateTime.Now vs. DateTime.UtcNow


225

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


1
อาจจะสายเกินไป แต่ฉันต้องการที่จะชี้ไปที่บล็อกนี้: blog.angeloflogic.com/2013/10/…
Kai Wang

คำตอบ:


346

DateTimeUTCNowจะบอกวันที่และเวลาให้คุณในรูปแบบ Coordinated Universal Time ซึ่งเรียกว่า Greenwich Mean Time zone - โดยทั่วไปแล้วถ้าคุณอยู่ในลอนดอนประเทศอังกฤษ แต่ไม่ใช่ในช่วงฤดูร้อน DateTime ขณะนี้ให้วันที่และเวลาเหมือนที่ปรากฏแก่บางคนในสถานที่ปัจจุบันของคุณ

ฉันขอแนะนำให้ใช้DateTime.Nowเมื่อใดก็ตามที่คุณแสดงวันที่ให้กับมนุษย์ - วิธีที่พวกเขาพอใจกับคุณค่าที่พวกเขาเห็น - เป็นสิ่งที่พวกเขาสามารถเปรียบเทียบกับสิ่งที่พวกเขาเห็นบนนาฬิกาหรือนาฬิกาได้อย่างง่ายดาย ใช้DateTime.UtcNowเมื่อคุณต้องการจัดเก็บวันที่หรือใช้สำหรับการคำนวณในภายหลังด้วยวิธีนี้ (ในรูปแบบไคลเอนต์ - เซิร์ฟเวอร์) การคำนวณของคุณจะไม่สับสนโดยลูกค้าในเขตเวลาที่แตกต่างจากเซิร์ฟเวอร์ของคุณหรือจากกันและกัน


84
จุดที่ยอดเยี่ยม - เมื่อจัดเก็บวันที่ในฐานข้อมูลหรือไฟล์ให้จัดเก็บไว้ใน UTC อย่างแน่นอน!
Jeff Atwood

15
คุณต้องทราบว่าเมื่อคุณต้องการเก็บวันที่ใน UTC ในฐานข้อมูลคุณต้องตรวจสอบให้แน่ใจว่าฐานข้อมูลไม่ได้เพิ่มเขตเวลาของตัวเองไปยังวันที่ที่ไม่มีเขตเวลาที่ชัดเจน โปรดทราบว่า DateTime จะใช้เขตเวลาปัจจุบันเสมอเมื่อถูกถาม
Omer van Kloeten

@OmervanKloeten ให้คะแนนดีมาก ฉันสงสัยว่ามีวิธีแก้ปัญหา 'all round' ที่สง่างามสำหรับเรื่องนี้เพื่อจัดเก็บและรับวันที่อย่างถูกต้องทุกครั้งหรือไม่แม้ว่า IIS และเซิร์ฟเวอร์ SQL ของคุณจะอยู่ในเขตเวลาที่แตกต่างกัน
TheGeekZn

1
@ JoshYates1980 ใช่คุณเพียงแค่ทำ DateTime.UtcNow.AddYears (1)
CathalMF

3
ใช้NodaTime - มันจะบังคับให้คุณคิดเกี่ยวกับเวลาในวิธีที่มีประโยชน์มากขึ้นและหลีกเลี่ยงปัญหาดังกล่าว
aateeque

86

มันค่อนข้างง่ายจริงๆดังนั้นฉันคิดว่ามันขึ้นอยู่กับว่าผู้ชมของคุณอยู่ที่ไหนและพวกเขาอยู่ที่ไหน

หากคุณไม่ได้ใช้ Utc คุณต้องทราบเขตเวลาของบุคคลที่คุณแสดงวันที่และเวลา - มิฉะนั้นคุณจะบอกพวกเขาว่ามีบางสิ่งเกิดขึ้นในเวลา 15.00 น. ในระบบหรือเวลาเซิร์ฟเวอร์เมื่อเกิดขึ้นจริงในเวลา 17.00 น. พวกเขามีชีวิตอยู่

เราใช้ DateTime.UtcNowเพราะเรามีผู้ชมเว็บทั่วโลกและเพราะฉันไม่ต้องการให้ผู้ใช้ทุกคนกรอกแบบฟอร์มเพื่อระบุเขตเวลาที่พวกเขาอาศัยอยู่

นอกจากนี้เรายังแสดงเวลาที่สัมพันธ์กัน (2 ชั่วโมงที่ผ่านมา 1 วันที่ผ่านมา ฯลฯ ) จนกระทั่งโพสต์มีอายุพอที่เวลานั้น "เหมือนกัน" ไม่ว่าคุณจะอยู่ที่ไหนบนโลก


ฉันต้องการวินาทีที่เก็บ DateTime.UtcNow เป็นสิ่งจำเป็นเฉพาะเมื่อคำนวณด้วย 2 วันที่จะได้รับชั่วโมงที่ถูกต้อง เมื่อฉันต้องแสดงวันที่ลงทะเบียนแล้ว Datetime ตอนนี้ก็เพียงพอแล้ว
Elisabeth

36

ยังทราบความแตกต่างของประสิทธิภาพ DateTime.UtcNowอยู่ที่ไหนสักแห่งเร็วกว่าประมาณ30เท่าDateTime.Nowเนื่องจากภายในDateTime.Nowมีการปรับเปลี่ยนเขตเวลาจำนวนมาก (คุณสามารถตรวจสอบได้ด้วยตัวสะท้อนแสง)

ดังนั้นอย่าใช้DateTime.Nowสำหรับการวัดเวลาสัมพัทธ์


มันทำให้ฉันต้องเจ็บปวดกับการเดินทางเพียงแค่รู้ว่า UtcNow มีประสิทธิภาพที่ดีขึ้นและเพียงบันทึกวันที่ของคุณใน mysql และสมมติว่าเป็น utc และเปรียบเทียบการแสดงวันที่ขึ้นอยู่กับ UtcNow ลดความซับซ้อนของปัญหาเขตเวลาทั่วโลกนี้
Diin

29

หนึ่งในแนวคิดสำคัญที่ต้องเข้าใจใน NET เป็นว่าตอนนี้เป็นตอนนี้ทั่วทุกมุมโลกไม่ว่าสิ่งที่โซนเวลาที่คุณอยู่ในดังนั้นถ้าคุณโหลดตัวแปรที่มี. DateTime.NowหรือDateTime.UtcNow-. ที่ได้รับมอบหมายเป็นเหมือนของคุณ * DateTimeวัตถุรู้ว่าสิ่งที่เขตเวลาที่คุณอยู่ใน และคำนึงถึงสิ่งนั้นโดยไม่คำนึงถึงการมอบหมาย

ประโยชน์ของการใช้งานDateTime.UtcNowมีประโยชน์เมื่อคำนวณวันที่ข้ามขอบเขตเวลาออมแสง นั่นคือในสถานที่ที่มีส่วนร่วมในการปรับเวลาตามฤดูกาลบางครั้งมี 25 ชั่วโมงตั้งแต่เที่ยงวันถึงเที่ยงในวันรุ่งขึ้นและบางครั้งมี 23 ชั่วโมงระหว่างเที่ยงและเที่ยงในวันรุ่งขึ้น หากคุณต้องการกำหนดจำนวนชั่วโมงจากเวลา A และเวลา B อย่างถูกต้องคุณจะต้องแปลแต่ละครั้งเป็นเทียบเท่า UTC ก่อนที่จะคำนวณTimeSpanของพวกเขาก่อนที่จะคำนวณ

นี่คือโพสต์บล็อกที่ฉันเขียนที่อธิบายเพิ่มเติมTimeSpanและรวมถึงลิงก์ไปยังบทความ MS ที่กว้างขวางยิ่งขึ้นในหัวข้อ

* ความชัดเจน: การมอบหมายอย่างใดอย่างหนึ่งจะเก็บเวลาปัจจุบัน หากคุณต้องโหลดตัวแปรสองตัวตัวหนึ่งผ่านทางDateTime.Now()และอีกตัวหนึ่งผ่านDateTime.UtcNow()ความTimeSpanแตกต่างระหว่างสองตัวนั้นจะเป็นมิลลิวินาทีไม่ใช่ชั่วโมงสมมติว่าคุณอยู่ในเขตเวลานอกเวลาจาก GMT ดังที่ระบุไว้ด้านล่างการพิมพ์Stringค่าของพวกเขาจะแสดงสตริงที่แตกต่างกัน


1
เกี่ยวกับ "โหลดตัวแปรด้วย DateTime.Now หรือ DateTime.UtcNow - การกำหนดเหมือนกัน": สิ่งนี้อาจต้องมีการชี้แจง? ขณะที่ฉันนั่งอยู่ที่นี่ในเขตเวลา EDT (UTC -4) ฉันได้กำหนดตัวแปรสองตัวให้กับ DateTime.UtcNow และ DateTime.Now ตามลำดับจากนั้นพิมพ์ค่าของพวกเขาด้วย ToString () ค่าที่แสดงอยู่ห่างกัน 4 ชั่วโมงซึ่งไม่ใช่ "เหมือนกัน"
Jon Schneider

2
@ JonSchneider ฉันเชื่อว่าคุณถูกต้อง คำสั่ง: "การมอบหมายเหมือนกัน" ไม่เป็นความจริง ToString () อาจไม่ใช่วิธีที่ดีที่สุดในการทดสอบเนื่องจากอาจแสดงวันที่เท่ากันต่างกัน (เช่น Java) ฟังก์ชั่นการเปรียบเทียบเป็นการทดสอบที่ดีกว่าและแสดงว่ามันไม่เท่ากัน
Ted Bigham

ชี้แจงกับคำสั่ง "เหมือนกัน" ของฉัน: โหลดหนึ่งตัวแปรผ่าน DateTime.Now และอีกอันด้วย DateTime.UtcNow แล้วพิมพ์ความแตกต่างของ TimeSpan ความแตกต่างจะเป็นมิลลิวินาทีและไม่ใช่ชั่วโมงสมมติว่าคุณอยู่ห่างจาก GMT
Carl Camera

18

นี่เป็นคำถามที่ดี ฉันกำลังฟื้นฟูเพื่อให้รายละเอียดเพิ่มเติมเล็กน้อยว่า. Net ทำงานอย่างไรกับKindค่าที่แตกต่างกัน @Jan Zich ชี้ให้เห็นว่าจริง ๆ แล้วมันเป็นคุณสมบัติที่สำคัญอย่างยิ่งและมีการตั้งค่าที่แตกต่างกันไปขึ้นอยู่กับว่าคุณใช้NowหรือUtcNowหรือ

ภายในวันที่จะถูกจัดเก็บตามTicksที่ (ตรงข้ามกับคำตอบของ @Carl Camera) จะแตกต่างกันไปขึ้นอยู่กับว่าคุณใช้NowหรือUtcNowหรือ

DateTime.UtcNowมีพฤติกรรมเหมือนภาษาอื่น ๆ มันตั้งTicksค่าตาม GMT อีกทั้งยังตั้งค่าKindให้Utcที่จะ

DateTime.Nowalters * Ticksมูลค่าให้กับสิ่งที่มันจะเป็นถ้ามันเป็นเวลาของคุณในวันในเขตเวลา GMT อีกทั้งยังตั้งค่าKindให้Localที่จะ

หากคุณอยู่ช้ากว่า 6 ชั่วโมง (GMT-6) คุณจะได้รับเวลา GMT จาก 6 ชั่วโมงที่ผ่านมา .Net จะเพิกเฉยKindและปฏิบัติต่อในเวลานี้ราวกับว่ามันเป็น 6 ชั่วโมงที่ผ่านมาแม้ว่ามันควรจะเป็น "ตอนนี้" สิ่งนี้จะทำลายได้มากขึ้นถ้าคุณสร้างDateTimeอินสแตนซ์จากนั้นเปลี่ยนเขตเวลาของคุณและลองใช้

อินสแตนซ์ DateTime ที่มีค่า 'ชนิด' แตกต่างกันเข้ากันไม่ได้

ลองดูรหัสบางส่วน ...

    DateTime utc = DateTime.UtcNow;
    DateTime now = DateTime.Now;
    Debug.Log (utc + " " + utc.Kind);  // 05/20/2015 17:19:27 Utc
    Debug.Log (now + " " + now.Kind);  // 05/20/2015 10:19:27 Local

    Debug.Log (utc.Ticks);  // 635677391678617830
    Debug.Log (now.Ticks);  // 635677139678617840

    now = now.AddHours(1);
    TimeSpan diff = utc - now;
    Debug.Log (diff);  // 05:59:59.9999990

    Debug.Log (utc <  now);  // false
    Debug.Log (utc == now);  // false
    Debug.Log (utc >  now);  // true

    Debug.Log (utc.ToUniversalTime() <  now.ToUniversalTime());  // true
    Debug.Log (utc.ToUniversalTime() == now.ToUniversalTime());  // false
    Debug.Log (utc.ToUniversalTime() >  now.ToUniversalTime());  // false
    Debug.Log (utc.ToUniversalTime() -  now.ToUniversalTime());  // -01:00:00.0000010

อย่างที่คุณเห็นที่นี่ฟังก์ชั่นการเปรียบเทียบและคณิตศาสตร์ไม่ได้แปลงเป็นเวลาที่เข้ากันได้โดยอัตโนมัติ Timespanควรจะได้รับเกือบหนึ่งชั่วโมง แต่ก็เกือบ 6 "UTC <ตอนนี้" ควรจะได้รับจริง (ฉันยังเพิ่มชั่วโมงเพื่อให้แน่ใจว่า) แต่ก็ยังคงเป็นเท็จ

คุณยังสามารถดู 'การทำงานรอบด้าน' ซึ่งจะแปลงเป็นเวลาสากลทุกที่ Kindไม่เหมือนกัน

คำตอบของคำถามโดยตรงของฉันเห็นด้วยกับคำแนะนำของคำตอบที่ยอมรับเกี่ยวกับเวลาที่จะใช้แต่ละข้อ คุณควรพยายามทำงานกับDateTimeวัตถุที่มีKind=Utcยกเว้นระหว่าง i / o (การแสดงและการแยกวิเคราะห์) ซึ่งหมายความว่าคุณควรใช้งานเกือบตลอดเวลาDateTime.UtcNowยกเว้นกรณีที่คุณสร้างวัตถุเพื่อแสดงวัตถุและทิ้งมันทันที


7

DateTime ไม่มีความคิดว่าเขตเวลาคืออะไร มันจะถือว่าคุณอยู่ในเวลาท้องถิ่นของคุณ UtcNowหมายถึง "ลบเขตเวลาของฉันจากเวลา" เท่านั้น

หากคุณต้องการใช้วันที่ทราบเขตเวลาใช้DateTimeOffsetซึ่งแสดงวันที่ / เวลาด้วยเขตเวลา ฉันต้องเรียนรู้ว่าวิธีที่ยากลำบาก


9
เพื่อความแม่นยำอย่างสมบูรณ์ (และหลีกเลี่ยงผู้ใช้จากการใช้ตอนนี้ผ่าน UtcNow ด้วยเหตุผลด้านประสิทธิภาพ) เป็นวิธีอื่น: เพิ่มโซนเวลาใน UtcNow และในความเป็นจริงมีขนาดช้าลง
mafu

5

คำตอบที่ "ง่าย" สำหรับคำถามคือ:

DateTime ขณะนี้ส่งคืนค่าDateTime ที่แสดงเวลาปัจจุบันของระบบ (ในเขตเวลาใดก็ตามที่ระบบกำลังทำงานอยู่) DateTime.KindคุณสมบัติจะDateTimeKind.Local

DateTime.UtcNowส่งคืนค่าDateTime ซึ่งเป็นตัวแทนของเวลาพิกัดสากลปัจจุบัน (aka UTC) ซึ่งจะเหมือนกันโดยไม่คำนึงถึงเขตเวลาของระบบ DateTime.KindคุณสมบัติจะDateTimeKind.Utc


4

นอกเหนือจากจุดที่ทำข้างต้นเล็กน้อย: โครงสร้าง DateTime ยังมีเขตข้อมูลที่รู้จักเล็กน้อยที่เรียกว่าชนิด (อย่างน้อยฉันไม่ทราบเกี่ยวกับมันเป็นเวลานาน) มันเป็นเพียงแค่การตั้งค่าสถานะที่ระบุว่าเวลาเป็นท้องถิ่นหรือ UTC; ไม่ได้ระบุออฟเซ็ตจริงจาก UTC สำหรับเวลาท้องถิ่น นอกจากความจริงที่ว่ามันแสดงให้เห็นกับสิ่งที่ตั้งใจ stuct ถูกสร้างก็ยังมีอิทธิพลต่อวิธีการที่วิธีการToUniversalTime ()และToLocalTime ()การทำงาน


3

1

DateTime.UtcNow เป็นมาตราส่วนเวลาแบบต่อเนื่องที่มีค่าเดียวในขณะที่ DateTime.Now ไม่ต่อเนื่องหรือมีค่าเดียว เหตุผลหลักคือเวลาออมแสงซึ่งไม่ได้ใช้กับ UTC ดังนั้น UTC จะไม่ข้ามไปข้างหน้าหรือย้อนกลับหนึ่งชั่วโมงในขณะที่เวลาท้องถิ่น (DateTime.Now) ทำ และเมื่อมันกระโดดไปข้างหลังค่าเวลาเดียวกันจะเกิดขึ้นสองครั้ง


1

DateTime.UtcNow เป็นมาตราส่วนเวลาสากลที่ไม่ใช้เวลาออมแสง UTC ไม่เคยเปลี่ยนแปลงเนื่องจาก DST

แต่ DateTime ตอนนี้ไม่ต่อเนื่องหรือมีมูลค่าเดียวเพราะจะเปลี่ยนแปลงตาม DST ซึ่งหมายถึง DateTime ขณะนี้ค่าเวลาเดียวกันอาจเกิดขึ้นสองครั้งที่ทำให้ลูกค้าอยู่ในสถานะสับสน


0

เมื่อคุณต้องการเวลาท้องถิ่นสำหรับเครื่องที่แอปพลิเคชันของคุณทำงาน (เช่น CEST สำหรับยุโรป) ให้ใช้ทันที หากคุณต้องการเวลาสากล - UtcNow มันเป็นเรื่องของการตั้งค่าของคุณ - อาจสร้างเว็บไซต์ท้องถิ่น / แอปพลิเคชันแบบสแตนด์อโลนที่คุณต้องการใช้เวลาที่ผู้ใช้มี - ดังนั้นได้รับผลกระทบจากการตั้งค่าเขตเวลาของเขา / เธอ - DateTime ตอนนี้

เพียงจำไว้ว่าสำหรับเว็บไซต์การตั้งค่าเขตเวลาของเซิร์ฟเวอร์ ดังนั้นหากคุณกำลังแสดงเวลาสำหรับผู้ใช้ให้เลือกเขตเวลาที่ต้องการและเปลี่ยนเวลา (เพียงบันทึกเวลา Utc ไปยังฐานข้อมูลแล้วปรับเปลี่ยน) หรือระบุ UTC หากคุณลืมที่จะทำเช่นนั้นผู้ใช้สามารถเห็นสิ่งที่ชอบ: โพสต์ 3 minuses ที่ผ่านมาแล้วเวลาในอนาคตใกล้ :)


0

ข้อแตกต่างใหญ่ :) คือ DateTime ขณะนี้ไม่ได้รับการสนับสนุนใน SharePoint Workflow คุณต้องใช้ DateTime.UtcNow

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