ใครสามารถอธิบายความแตกต่างระหว่างSystem.DateTime.Now
และSystem.DateTime.Today
ใน C # .NET? ข้อดีข้อเสียของแต่ละข้อถ้าเป็นไปได้
ใครสามารถอธิบายความแตกต่างระหว่างSystem.DateTime.Now
และSystem.DateTime.Today
ใน C # .NET? ข้อดีข้อเสียของแต่ละข้อถ้าเป็นไปได้
คำตอบ:
DateTime.Now
ส่งคืนDateTime
ค่าที่ประกอบด้วยวันที่และเวลาท้องถิ่นของคอมพิวเตอร์ที่รหัสกำลังทำงานอยู่ ได้DateTimeKind.Local
กำหนดให้กับKind
ทรัพย์สินของตน เทียบเท่ากับการเรียกสิ่งต่อไปนี้:
DateTime.UtcNow.ToLocalTime()
DateTimeOffset.UtcNow.LocalDateTime
DateTimeOffset.Now.LocalDateTime
TimeZoneInfo.ConvertTime(DateTime.UtcNow, TimeZoneInfo.Local)
TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, TimeZoneInfo.Local)
DateTime.Today
ส่งคืนDateTime
ค่าที่มีส่วนประกอบของปีเดือนและวันเดียวกันกับนิพจน์ใด ๆ ข้างต้น แต่มีการตั้งค่าส่วนประกอบของเวลาเป็นศูนย์ นอกจากนี้ยังมีDateTimeKind.Local
ในKind
ทรัพย์สิน เทียบเท่ากับสิ่งต่อไปนี้:
DateTime.Now.Date
DateTime.UtcNow.ToLocalTime().Date
DateTimeOffset.UtcNow.LocalDateTime.Date
DateTimeOffset.Now.LocalDateTime.Date
TimeZoneInfo.ConvertTime(DateTime.UtcNow, TimeZoneInfo.Local).Date
TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, TimeZoneInfo.Local).Date
โปรดทราบว่าภายในนาฬิกาของระบบอยู่ในรูปของ UTC ดังนั้นเมื่อคุณเรียกDateTime.Now
ใช้ครั้งแรกให้รับเวลา UTC (ผ่านGetSystemTimeAsFileTime
ฟังก์ชันใน Win32 API) จากนั้นจะแปลงค่าเป็นเขตเวลาท้องถิ่น (จึงDateTime.Now.ToUniversalTime()
มีราคาแพงกว่าDateTime.UtcNow
)
นอกจากนี้โปรดทราบว่าDateTimeOffset.Now.DateTime
จะมีค่าที่คล้ายกันDateTime.Now
แต่จะมีDateTimeKind.Unspecified
มากกว่าDateTimeKind.Local
- ซึ่งอาจนำไปสู่ข้อผิดพลาดอื่น ๆ ขึ้นอยู่กับสิ่งที่คุณทำกับมัน
ดังนั้นคำตอบง่ายๆก็คือว่าเทียบเท่ากับDateTime.Today
แต่ IMHO - คุณไม่ควรใช้อย่างใดอย่างหนึ่งหรือเทียบเท่าข้างต้นDateTime.Now.Date
เมื่อคุณถามDateTime.Now
คุณกำลังขอค่าของนาฬิกาปฏิทินภายในของคอมพิวเตอร์ที่รหัสกำลังทำงานอยู่ แต่สิ่งที่คุณได้รับกลับไม่มีข้อมูลเกี่ยวกับนาฬิกาเรือนนั้นเลย! DateTime.Now.Kind == DateTimeKind.Local
ที่ดีที่สุดที่คุณจะได้รับคือ แต่มันเป็นของใคร? ข้อมูลนั้นจะหายไปทันทีที่คุณทำอะไรกับค่าเช่นเก็บไว้ในฐานข้อมูลแสดงบนหน้าจอหรือส่งโดยใช้บริการเว็บ
หากโซนเวลาท้องถิ่นของคุณต่อกฎใด ๆ เงินฝากออมทรัพย์ในเวลากลางวัน, DateTime.Now
คุณไม่ได้รับที่กลับมาข้อมูลจาก ในช่วงเวลาที่คลุมเครือเช่นในช่วงการเปลี่ยนแปลง "ถอยกลับ" คุณจะไม่รู้ว่าช่วงเวลาใดที่เป็นไปได้ที่สอดคล้องกับค่าที่คุณดึงDateTime.Now
มา ตัวอย่างเช่นสมมติว่าระบบของคุณตั้งค่าเป็นเขตเวลาMountain Time (US & Canada)
และคุณขอDateTime.Now
ในช่วงหัวค่ำของวันที่ 3 พฤศจิกายน 2013 ผลลัพธ์2013-11-03 01:00:00
หมายความว่าอย่างไร มีช่วงเวลาสองช่วงเวลาที่แสดงโดยวันที่และเวลาปฏิทินเดียวกันนี้ ถ้าฉันจะส่งค่านี้ไปให้คนอื่นพวกเขาคงไม่รู้ว่าฉันหมายถึงอันไหน โดยเฉพาะอย่างยิ่งถ้าพวกเขาอยู่ในเขตเวลาที่กฎแตกต่างกัน
สิ่งที่ดีที่สุดที่คุณสามารถทำได้คือใช้DateTimeOffset
แทน:
// This will always be unambiguous.
DateTimeOffset now = DateTimeOffset.Now;
ตอนนี้สำหรับสถานการณ์เดียวกันที่ฉันอธิบายไว้ข้างต้นฉันได้รับค่า2013-11-03 01:00:00 -0600
ก่อนการเปลี่ยนแปลงหรือ2013-11-03 01:00:00 -0700
หลังการเปลี่ยนแปลง ใครก็ตามที่ดูค่าเหล่านี้สามารถบอกได้ว่าฉันหมายถึงอะไร
ฉันเขียนบล็อกโพสต์เกี่ยวกับเรื่องนี้ โปรดอ่าน - กรณีกับ DateTime.Now
นอกจากนี้ยังมีสถานที่บางแห่งในโลกนี้ (เช่นบราซิล) ที่การเปลี่ยนแปลงแบบ "ก้าวไปข้างหน้า" เกิดขึ้นตรงกับเวลาเที่ยงคืน นาฬิกาเปิดเวลา 23.59 น. - 01:00 น. นั่นหมายความว่ามูลค่าที่คุณได้รับDateTime.Today
ในวันนั้นไม่มีอยู่จริง! แม้ว่าคุณจะใช้DateTimeOffset.Now.Date
คุณจะได้รับผลลัพธ์เดียวกันและคุณยังคงมีปัญหานี้ เป็นเพราะตามปกติแล้วไม่มีสิ่งที่เรียกว่าDate
วัตถุใน. Net ดังนั้นไม่ว่าคุณจะได้รับมูลค่าอย่างไรเมื่อคุณตัดเวลาออกไปคุณต้องจำไว้ว่ามันไม่ได้แสดงถึง "เที่ยงคืน" จริงๆแม้ว่านั่นจะเป็นคุณค่าที่คุณกำลังดำเนินการอยู่ก็ตาม
หากคุณต้องการการแก้ปัญหาที่ถูกต้องอย่างเต็มที่ในการแก้ไขปัญหานี้จริงๆวิธีที่ดีที่สุดคือการใช้NodaTime LocalDate
ระดับอย่างถูกต้องหมายถึงวันโดยไม่ต้องเวลา คุณสามารถรับวันที่ปัจจุบันสำหรับโซนเวลาใดก็ได้รวมถึงเขตเวลาของระบบท้องถิ่น:
using NodaTime;
...
Instant now = SystemClock.Instance.Now;
DateTimeZone zone1 = DateTimeZoneProviders.Tzdb.GetSystemDefault();
LocalDate todayInTheSystemZone = now.InZone(zone1).Date;
DateTimeZone zone2 = DateTimeZoneProviders.Tzdb["America/New_York"];
LocalDate todayInTheOtherZone = now.InZone(zone2).Date;
หากคุณไม่ต้องการใช้ Noda Time ตอนนี้มีอีกทางเลือกหนึ่ง ผมเคยมีส่วนทำให้การดำเนินการของวัตถุวันเท่านั้นที่จะ.Net CoreFX Labโครงการ คุณสามารถค้นหาSystem.Time
วัตถุแพ็กเกจได้ในฟีด MyGet เมื่อเพิ่มลงในโครงการของคุณแล้วคุณจะพบว่าคุณสามารถทำสิ่งใดสิ่งหนึ่งต่อไปนี้:
using System;
...
Date localDate = Date.Today;
Date utcDate = Date.UtcToday;
Date tzSpecificDate = Date.TodayInTimeZone(anyTimeZoneInfoObject);
DateTime.UtcNow
เป็นที่ยอมรับหากคุณสามารถระบุในใบสมัครหรือข้อมูลจำเพาะของคุณว่าค่าเป็น UTC (ฉันชอบเรียกฟิลด์หรือคุณสมบัติว่าMyDateUtc
แทนที่จะเป็นMyDate
- แต่นั่นเป็นเพียงแค่ไอซิ่งบนเค้ก) หากคุณไม่สามารถถ่ายทอดมันในข้อมูลจำเพาะหรือชื่อฟิลด์คุณDateTimeOffset.UtcNow
สามารถใช้เพื่อให้แน่ใจว่าศูนย์ออฟเซ็ตได้รับการถ่ายทอด ด้วยค่าวันที่และเวลา
DateTime.Now.Date
เช่นกัน
เวลา. .Now
รวม 09:23:12 หรืออะไรก็ได้; .Today
เป็นส่วนของวันที่เท่านั้น (เวลา 00:00:00 น. ของวันนั้น)
ดังนั้นใช้.Now
ถ้าคุณต้องการรวมเวลาและ.Today
ถ้าคุณต้องการวันที่!
.Today
โดยพื้นฐานแล้วจะเหมือนกับ .Now.Date
UtcNow
เว้นแต่คุณต้องการเขตเวลาท้องถิ่นของระบบจริงๆ (โดยเฉพาะบนเว็บแอปที่มักจะเป็นตัวเลือกที่ผิด)
คุณสมบัติส่งกลับวันและเวลาปัจจุบันตัวอย่างเช่นDateTime.Now
2011-07-01 10:09.45310
DateTime.Today
คุณสมบัติส่งกลับวันที่ปัจจุบันมี compnents 2011-07-01 00:00.00000
เวลาที่กำหนดเป็นศูนย์ตัวอย่างเช่น
DateTime.Today
คุณสมบัติจริงจะดำเนินการกลับมาDateTime.Now.Date
:
public static DateTime Today {
get {
DateTime now = DateTime.Now;
return now.Date;
}
}
DateTime.Todayหมายถึงวันที่ระบบปัจจุบันที่มีส่วนชุดเวลาที่จะ 00:00:00
และ
DateTime.Nowแสดงวันที่และเวลาของระบบปัจจุบัน
(v=VS.100)
.
ฉันคิดว่าจะเพิ่มลิงก์เหล่านี้ -
กลับมาที่คำถามเดิมการใช้ตัวสะท้อนแสงฉันได้อธิบายความแตกต่างของรหัสแล้ว
public static DateTime Today
{
get
{
return DateTime.Now.Date; // It returns the date part of Now
//Date Property
// returns same date as this instance, and the time value set to 12:00:00 midnight (00:00:00)
}
}
private const long TicksPerMillisecond = 10000L;
private const long TicksPerDay = 864000000000L;
private const int MillisPerDay = 86400000;
public DateTime Date
{
get
{
long internalTicks = this.InternalTicks; // Date this instance is converted to Ticks
return new DateTime((ulong) (internalTicks - internalTicks % 864000000000L) | this.InternalKind);
// Modulo of TicksPerDay is subtracted - which brings the time to Midnight time
}
}
public static DateTime Now
{
get
{
/* this is why I guess Jon Skeet is recommending to use UtcNow as you can see in one of the above comment*/
DateTime utcNow = DateTime.UtcNow;
/* After this i guess it is Timezone conversion */
bool isAmbiguousLocalDst = false;
long ticks1 = TimeZoneInfo.GetDateTimeNowUtcOffsetFromUtc(utcNow, out isAmbiguousLocalDst).Ticks;
long ticks2 = utcNow.Ticks + ticks1;
if (ticks2 > 3155378975999999999L)
return new DateTime(3155378975999999999L, DateTimeKind.Local);
if (ticks2 < 0L)
return new DateTime(0L, DateTimeKind.Local);
else
return new DateTime(ticks2, DateTimeKind.Local, isAmbiguousLocalDst);
}
}
DateTime dt = new DateTime();// gives 01/01/0001 12:00:00 AM
DateTime dt = DateTime.Now;// gives today date with current time
DateTime dt = DateTime.Today;// gives today date and 12:00:00 AM time
DateTime.Today
คือDateTime.Now
ตั้งเวลาเป็นศูนย์
สิ่งสำคัญคือต้องสังเกตว่ามีความแตกต่างระหว่างค่า DateTime ซึ่งแสดงถึงจำนวนเห็บที่ผ่านไปตั้งแต่เที่ยงคืนของวันที่ 1 มกราคม 0000 และการแสดงสตริงของค่า DateTime นั้นซึ่งแสดงค่าวันที่และเวลาใน a รูปแบบเฉพาะวัฒนธรรม: https://msdn.microsoft.com/en-us/library/system.datetime.now%28v=vs.110%29.aspx
DateTime.Now.Ticks
คือเวลาจริงที่จัดเก็บโดย. net (โดยพื้นฐานแล้วคือเวลา UTC) ส่วนที่เหลือเป็นเพียงการแสดง (ซึ่งสำคัญสำหรับวัตถุประสงค์ในการแสดงผล)
หากKind
คุณสมบัติDateTimeKind.Local
นั้นมีข้อมูลโซนเวลาของคอมพิวเตอร์ในระบบโดยปริยาย เมื่อส่งผ่านบริการเว็บ. net ค่า DateTime จะถูกทำให้เป็นอนุกรมตามค่าเริ่มต้นโดยมีข้อมูลโซนเวลารวมอยู่ด้วยเช่น 2008-10-31T15: 07: 38.6875000-05: 00 และคอมพิวเตอร์ในเขตเวลาอื่นยังสามารถทราบได้อย่างชัดเจนว่าเวลาคืออะไร ถูกอ้างถึง
ดังนั้นการใช้ DateTime.Now และ DateTime.Today ก็โอเคอย่างสมบูรณ์แบบ
โดยปกติคุณจะเริ่มประสบปัญหาเมื่อคุณเริ่มสับสนในการแทนค่าสตริงกับค่าจริงและพยายาม "แก้ไข" DateTime เมื่อมันไม่เสีย
DateTime.Now.ToShortDateString()
จะแสดงเฉพาะส่วนวันที่
DateTime.UtcNow
แทนDateTimeOffset.Now
?