I have a datetimeoffset value as 11/22/2016 05:20 AM with an offset of -06:00. I want to get the result as 11/21/2016 11:20 PM after reducing the offset from the time value. I tried
date.UtcDateTime
but it gives me the result as 11/22/206 11:20 PM . What is the way to get the preferred result from datetimeoffset value
The following example shows that when a DateTimeOffset is created, the year, month, day, hour, minute, etc. are interpreted as a local time in the time zone specified by the offset (in udaya726's case, -6 hours). The default output, "11/22/2016 05:20:00 -06:00", should be read as "November 22, 2016, 5:20 AM in the time zone 6 hours behind Greenwich."
using System;
public class StOv4
{
public static void Main()
{
// Time in question: 11/22/2016 05:20 AM with an offset of -06:00
TimeSpan questionOffset = new TimeSpan(-6, 0, 0);
DateTimeOffset questionTime = new DateTimeOffset(2016, 11, 22, 5, 20, 0, 0,
questionOffset);
Console.WriteLine("Time with {0} offset: {1}", questionOffset, questionTime);
// "u" format specifier indicates string is to represent UTC time.
Console.WriteLine("UTC time: {0}", questionTime.ToString("u"));
}
}
Console output:
Time with -06:00:00 offset: 11/22/2016 05:20:00 -06:00
UTC time: 2016-11-22 11:20:00Z
Related
During a Daylight Saving Time transition, the clock is moved forward, and so a specific hour will not exist in that specific day for that specific time zone.
Is there an easy way in .NET to find out if an hour exists or not for a time zone?
The only way I found was by trying to convert an hour to UTC, and check for an exception:
public bool IsValidTime(DateTime date, TimeZoneInfo tzi)
{
try
{
date = DateTime.SpecifyKind(date, DateTimeKind.Unspecified);
TimeZoneInfo.ConvertTimeToUtc(date, tzi);
return true;
}
catch
{
return false;
}
}
And so running something like this will return false:
var date = new DateTime(2020, 3, 8);
var tzi = TimeZoneInfo.FindSystemTimeZoneById("Cuba Standard Time");
var isValid = IsValidTime(date, tzi);
Is there any built in way of doing this, that is less messy?
You can use IsInvalidTime method of TimeZoneInfo.
From Microsoft : https://learn.microsoft.com/en-us/dotnet/api/system.timezoneinfo.isinvalidtime?view=netframework-4.6.2
Example: In the Pacific Time zone, daylight saving time begins at 2:00 A.M. on April 2, 2006. The following code passes the time at one-minute intervals from 1:59 A.M. on April 2, 2006, to 3:01 A.M. on April 2, 2006, to the IsInvalidTime method of a TimeZoneInfo object that represents the Pacific Time zone. The console output indicates that all times from 2:00 A.M. on April 2, 2006, to 2:59 A.M. on April 2, 2006, are invalid.
// Specify DateTimeKind in Date constructor
DateTime baseTime = new DateTime(2007, 3, 11, 1, 59, 0, DateTimeKind.Unspecified);
DateTime newTime;
// Get Pacific Standard Time zone
TimeZoneInfo pstZone = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
// List possible invalid times for a 63-minute interval, from 1:59 AM to 3:01 AM
for (int ctr = 0; ctr < 63; ctr++)
{
// Because of assignment, newTime.Kind is also DateTimeKind.Unspecified
newTime = baseTime.AddMinutes(ctr);
Console.WriteLine("{0} is invalid: {1}", newTime, pstZone.IsInvalidTime(newTime));
}
I'm playing with some C# code to try to gain an understanding of how subtracting DateTime objects in C# works with respect to Daylight Saving Time.
Per Google and other sources, the Daylight Saving Time "spring ahead" event in the Eastern Standard Time zone in 2017 was at 2:00am on March 12. So, the first few hours of the day on that date were:
12:00am - 1:00am
1:00am - 2:00am
(There was no 2:00am - 3:00am hour due to the "spring ahead")
3:00am - 4:00am
So, if I were to calculate the time differential between 1:00am and 4:00am in that time zone on that date, I'd expect the result to be 2 hours.
However, the code I put together to try to simulate this problem is returning a 3 hour TimeSpan.
Code:
TimeZoneInfo easternStandardTime = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
DateTime oneAm = TimeZoneInfo.ConvertTime(new DateTime(2017, 03, 12, 01, 00, 00), easternStandardTime);
DateTime fourAm = TimeZoneInfo.ConvertTime(new DateTime(2017, 03, 12, 04, 00, 00), easternStandardTime);
TimeSpan difference = (fourAm - oneAm);
Console.WriteLine(oneAm);
Console.WriteLine(fourAm);
Console.WriteLine(TimeZoneInfo.Local.IsDaylightSavingTime(oneAm));
Console.WriteLine(TimeZoneInfo.Local.IsDaylightSavingTime(fourAm));
Console.WriteLine(difference);
On my PC, this generates:
2017-03-12 01:00:00.000 -5
2017-03-12 04:00:00.000 -4
False
True
03:00:00
All of that output is as expected -- except that final value of 3 hours, which as I noted above, I would expect to be 2 hours instead.
Obviously, my code isn't correctly simulating the situation that I have in mind. What is the flaw?
Observe:
// These are just plain unspecified DateTimes
DateTime dtOneAm = new DateTime(2017, 03, 12, 01, 00, 00);
DateTime dtFourAm = new DateTime(2017, 03, 12, 04, 00, 00);
// The difference is not going to do anything other than 4-1=3
TimeSpan difference1 = dtFourAm - dtOneAm;
// ... but we have a time zone to consider!
TimeZoneInfo eastern = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
// Use that time zone to get DateTimeOffset values.
// The GetUtcOffset method has what we need.
DateTimeOffset dtoOneAmEastern = new DateTimeOffset(dtOneAm, eastern.GetUtcOffset(dtOneAm));
DateTimeOffset dtoFourAmEastern = new DateTimeOffset(dtFourAm, eastern.GetUtcOffset(dtFourAm));
// Subtracting these will take the offset into account!
// It essentially does this: [4-(-4)]-[1-(-5)] = 8-6 = 2
TimeSpan difference2 = dtoFourAmEastern - dtoOneAmEastern;
// Let's see the results
Console.WriteLine("dtOneAm: {0:o} (Kind: {1})", dtOneAm, dtOneAm.Kind);
Console.WriteLine("dtFourAm: {0:o} (Kind: {1})", dtFourAm, dtOneAm.Kind);
Console.WriteLine("difference1: {0}", difference1);
Console.WriteLine("dtoOneAmEastern: {0:o})", dtoOneAmEastern);
Console.WriteLine("dtoFourAmEastern: {0:o})", dtoFourAmEastern);
Console.WriteLine("difference2: {0}", difference2);
Results:
dtOneAm: 2017-03-12T01:00:00.0000000 (Kind: Unspecified)
dtFourAm: 2017-03-12T04:00:00.0000000 (Kind: Unspecified)
difference1: 03:00:00
dtoOneAmEastern: 2017-03-12T01:00:00.0000000-05:00)
dtoFourAmEastern: 2017-03-12T04:00:00.0000000-04:00)
difference2: 02:00:00
Note that DateTime carries a DateTimeKind in its Kind property, which is Unspecified by default. It doesn't belong to any particular time zone. DateTimeOffset doesn't have a kind, it has an Offset, which tells you how far that local time is offset from UTC. Neither of these give you the time zone. That is what TimeZoneInfo object is doing. See "time zone != offset" in the timezone tag wiki.
The part I think you are perhaps frustrated with, is that for several historical reasons, the DateTime object does not ever understand time zones when doing math, even when you might have DateTimeKind.Local. It could have been implemented to observe the transitions of the local time zone, but it was not done that way.
You also might be interested in Noda Time, which gives a very different API for date and time in .NET, in a much more sensible and purposeful way.
using NodaTime;
...
// Start with just the local values.
// They are local to *somewhere*, who knows where? We didn't say.
LocalDateTime ldtOneAm = new LocalDateTime(2017, 3, 12, 1, 0, 0);
LocalDateTime ldtFourAm = new LocalDateTime(2017, 3, 12, 4, 0, 0);
// The following won't compile, because LocalDateTime does not reference
// a linear time scale!
// Duration difference = ldtFourAm - ldtOneAm;
// We can get the 3 hour period, but what does that really tell us?
Period period = Period.Between(ldtOneAm, ldtFourAm, PeriodUnits.Hours);
// But now lets introduce a time zone
DateTimeZone eastern = DateTimeZoneProviders.Tzdb["America/New_York"];
// And apply the zone to our local values.
// We'll choose to be lenient about DST gaps & overlaps.
ZonedDateTime zdtOneAmEastern = ldtOneAm.InZoneLeniently(eastern);
ZonedDateTime zdtFourAmEastern = ldtFourAm.InZoneLeniently(eastern);
// Now we can get the difference as an exact elapsed amount of time
Duration difference = zdtFourAmEastern - zdtOneAmEastern;
// Dump the output
Console.WriteLine("ldtOneAm: {0}", ldtOneAm);
Console.WriteLine("ldtFourAm: {0}", ldtFourAm);
Console.WriteLine("period: {0}", period);
Console.WriteLine("zdtOneAmEastern: {0}", zdtOneAmEastern);
Console.WriteLine("zdtFourAmEastern: {0}", zdtFourAmEastern);
Console.WriteLine("difference: {0}", difference);
ldtOneAm: 3/12/2017 1:00:00 AM
ldtFourAm: 3/12/2017 4:00:00 AM
period: PT3H
zdtOneAmEastern: 2017-03-12T01:00:00 America/New_York (-05)
zdtFourAmEastern: 2017-03-12T04:00:00 America/New_York (-04)
difference: 0:02:00:00
We can see a period of three hours, but it doesn't really mean the same as the elapsed time. It just means the two local values are three hours apart in their position on a clock. NodaTime understands the difference between these concepts, while .Net's built-in types do not.
Some follow-up reading for you:
What's wrong with DateTime anyway?
More Fun with DateTime
The case against DateTime.Now
Five Common Daylight Saving Time Antipatterns of .NET Developers
Oh, and one other thing. Your code has this...
DateTime oneAm = TimeZoneInfo.ConvertTime(new DateTime(2017, 03, 12, 01, 00, 00), easternStandardTime);
Since the DateTime you create has unspecified kind, you are asking to convert from your computer's local time zone to Eastern time. If you happen to be not in Eastern time, your oneAm variable might not be 1 AM at all!
Ok, so I made some minor changes to your code. Not sure if this is what you are trying to achieve or not but this will give you what you want...
static void Main() {
TimeZoneInfo easternStandardTime = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
TimeZone timeZone = TimeZone.CurrentTimeZone;
DateTime oneAm = TimeZoneInfo.ConvertTime(new DateTime(2017, 03, 12, 01, 00, 00), easternStandardTime);
DateTime fourAm = TimeZoneInfo.ConvertTime(new DateTime(2017, 03, 12, 04, 00, 00), easternStandardTime);
DaylightTime time = timeZone.GetDaylightChanges(fourAm.Year);
TimeSpan difference = ((fourAm - time.Delta) - oneAm);
Console.WriteLine(oneAm);
Console.WriteLine(fourAm);
Console.WriteLine(TimeZoneInfo.Local.IsDaylightSavingTime(oneAm));
Console.WriteLine(TimeZoneInfo.Local.IsDaylightSavingTime(fourAm));
Console.WriteLine(difference);
Console.ReadLine();
}
So this is addressed in the MSDN documentation.
Basicaly, when subtracting one date from another you should be using DateTimeOffset.Subtract() and not arithmetic subtraction as you have here.
TimeSpan difference = fourAm.Subtract(oneAm);
Yields the expected 2 hour time difference.
My server is sending me the following value 13928550480000 which I know represents the date 02/19/2014. But I am not able to figure out how to get to the date from the long value.
I tried various ways of converting long to date using c# date time class but not able to get to the correct date i.e. 02/19/2014
long dateL = 13928550480000;
DateTime dt = new DateTime(dateL);
var dtstr = dt.ToString("MM/dd/yyyy");
var onlyDate = dt.Date;
DateTime start = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
DateTime date = start.AddMilliseconds(dateL).ToLocalTime();
var dtstr1 = date.ToString("MM/dd/yyyy");
It looks like your source number represents number of 0.10 ms increments since 1-1-1970 (either that or a typo):
long dateL = 13928550480000;
DateTime start = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
DateTime date = start.AddMilliseconds(dateL/10).ToLocalTime();
// ***
// ^------
var dtstr1 = date.ToString("MM/dd/yyyy"); // 02/19/2014
I suspect the time zone difference is irrelevant to your problem.
Did you write too many zeros at the end of your big number? That is, does it really end in 0000 and not just 000?
If it really is 0000, then it appears to be measuring time in 100-microsecond increments (10,000 time increments per second). But it is probably also giving you time in GMT and you are expecting to derive local time from it. The time 1392855048 seconds from Jan. 1, 1970 would be 10 minutes 48 seconds past midnight on Feb. 20, 2014. Depending on your time zone, that could be sometime on Feb. 19 local time.
I'm saving date time in CST timezone,how to change the CST date time to local time.
Ex:
In DB,
Date time is 2013-01-21 06:50:00 and its timezone is CST.This Date Time should be converted into local current time.
Save them as UTC time and then convert them to local time when loading to the UI.
A sample code would be like
using System;
public class Example
{
public static void Main()
{
DateTime date1 = new DateTime(2010, 3, 14, 2, 30, 0, DateTimeKind.Local);
Console.WriteLine("Invalid time: {0}",
TimeZoneInfo.Local.IsInvalidTime(date1));
DateTime utcDate1 = date1.ToUniversalTime();
DateTime date2 = utcDate1.ToLocalTime();
Console.WriteLine("{0} --> {1}", date1, date2);
}
}
// The example displays the following output:
// Invalid time: True
// 3/14/2010 2:30:00 AM --> 3/14/2010 3:30:00 AM
Hope this helps
I'm trying to convert a C# DateTime variable to Unix time, ie, the number of seconds since Jan 1st, 1970. It looks like a DateTime is actually implemented as the number of 'ticks' since Jan 1st, 0001.
My current thought is to subtract Jan 1st, 1970 from my DateTime like this:
TimeSpan span= DateTime.Now.Subtract(new DateTime(1970,1,1,0,0,0));
return span.TotalSeconds;
Is there a better way?
That's basically it. These are the methods I use to convert to and from Unix epoch time:
public static DateTime ConvertFromUnixTimestamp(double timestamp)
{
DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
return origin.AddSeconds(timestamp);
}
public static double ConvertToUnixTimestamp(DateTime date)
{
DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
TimeSpan diff = date.ToUniversalTime() - origin;
return Math.Floor(diff.TotalSeconds);
}
Update: As of .Net Core 2.1 and .Net Standard 2.1 a DateTime equal to the Unix Epoch can be obtained from the static DateTime.UnixEpoch.
If the rest of your system is OK with DateTimeOffset instead of DateTime, there's a really convenient feature:
long unixSeconds = DateTimeOffset.Now.ToUnixTimeSeconds();
The only thing I see is that it's supposed to be since Midnight Jan 1, 1970 UTC
TimeSpan span= DateTime.Now.Subtract(new DateTime(1970,1,1,0,0,0, DateTimeKind.Utc));
return span.TotalSeconds;
You probably want to use DateTime.UtcNow to avoid timezone issue
TimeSpan span= DateTime.UtcNow.Subtract(new DateTime(1970,1,1,0,0,0));
I use year 2000 instead of Epoch Time in my calculus. Working with smaller numbers is easy to store and transport and is JSON friendly.
Year 2000 was at second 946684800 of epoch time.
Year 2000 was at second 63082281600 from 1-st of Jan 0001.
DateTime.UtcNow Ticks starts from 1-st of Jan 0001
Seconds from year 2000:
DateTime.UtcNow.Ticks/10000000-63082281600
Seconds from Unix Time:
DateTime.UtcNow.Ticks/10000000-946684800
For example year 2020 is:
var year2020 = (new DateTime()).AddYears(2019).Ticks; // Because DateTime starts already at year 1
637134336000000000 Ticks since 1-st of Jan 0001
63713433600 Seconds since 1-st of Jan 0001
1577836800 Seconds since Epoch Time
631152000 Seconds since year 2000
References:
Epoch Time converter: https://www.epochconverter.com
Year 1 converter: https://www.epochconverter.com/seconds-days-since-y0
That approach will be good if the date-time in question is in UTC, or represents local time in an area that has never observed daylight saving time. The DateTime difference routines do not take into account Daylight Saving Time, and consequently will regard midnight June 1 as being a multiple of 24 hours after midnight January 1. I'm unaware of anything in Windows that reports historical daylight-saving rules for the current locale, so I don't think there's any good way to correctly handle any time prior to the most recent daylight-saving rule change.
UTC:
long timeSince1970 = DateTimeOffset.Now.ToUnixTimeSeconds();
Local time:
long timeSince1970 = DateTime.Now.Ticks / 10000000 - 62135596800;
You can create a startTime and endTime of DateTime, then do endTime.Subtract(startTime). Then output your span.Seconds.
I think that should work.