I am sending from webbrowser this string "2019-01-25T00:00:00+01:00"
I undestand this as: this is local time and in utc should be "2019-01-24T23:00:00"
but on the server :
myDate.Kind is local
myDate "2019-01-24T23:00:00"
myDate.ToLocalTime() is the same "2019-01-24T23:00:00"
myDate.ToUniversalTime() is the same "2019-01-24T23:00:00"
what I need is if I sent this string "2019-01-25T00:00:00+01:00" I need to know on the server that there is 1h difference between local and utc
and parsing this string is done automatically by dot net core api (DateTime is method parameter)
The DateTime Type does not have any concept of time zones: if you need this, use DateTimeOffset instead.
I suspect your server is in the UTC timezone, Since ToLocalTime and ToUniversalTime give the same result.
You can try AdjustToUniversal option, e.g.
string source = "2019-01-25T00:00:00+01:00";
DateTime myDate = DateTime.ParseExact(
source,
"yyyy-MM-dd'T'HH:mm:sszzz",
CultureInfo.InvariantCulture,
DateTimeStyles.AdjustToUniversal);
Console.Write(string.Join(Environment.NewLine,
$"Value = {myDate:HH:mm:ss}",
$"Kind = {myDate.Kind}"));
Outcome:
Value = 23:00:00
Kind = Utc
Edit: If you can't change server's code and thus you have to provide a string (source) such that DateTime.Parse(source)
will return a correct date you can try to convert existing time-zone (+01:00) into Zulu:
string source = "2019-01-25T00:00:00+01:00";
// 2019-01-24T23:00:00Z
source = DateTime
.ParseExact(source,
"yyyy-MM-dd'T'HH:mm:sszzz",
CultureInfo.InvariantCulture,
DateTimeStyles.AdjustToUniversal)
.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'");
Then on the server you'll have
// source is treated as UTC-time;
// However, by default (when no options provided) myDate will have Kind = Local
DateTime myDate = DateTime.Parse(source);
Console.Write(string.Join(Environment.NewLine,
$"Value = {myDate:HH:mm:ss}",
$"Kind = {myDate.Kind}"));
Outcome:
Value = 02:00:00 // May vary; adjusted to server's time zone (In my case MSK: +03:00)
Kind = Local // DateTime.Parse returns Local when no options specified
Related
I have code that converts long numbers to dates.
DateTimeOffset value =
DateTimeOffset.FromUnixTimeSeconds(1597325462);
DateTime showTime = value.DateTime;
string easternZoneId = "America/New_York";
TimeZoneInfo easternZone =
TimeZoneInfo.FindSystemTimeZoneById(easternZoneId);
DateTime targetTime =
TimeZoneInfo.ConvertTime(showTime, easternZone);
Console.WriteLine("DateTime is {0}", targetTime);
On my Mac, the output is "DateTime is 8/13/2020 6:31:02 AM"
On my server the output is "DateTime is 8/13/2020 9:31:02 AM"
Identical code on both.
The Linux box value is accurate. How can I get the same result on my Mac?
The overload of TimeZone.ConvertTime you're using takes a DateTime value and a destination TimeZoneInfo. There's no mention of the source time zone, so it is infered from the .Kind property of the DateTime being passed in.
In your case, that is DateTimeKind.Unspecified, because the .DateTime property of a DateTimeOffset always returns unspecified, regardless of what the offset is.
In the ConvertTime call, if the kind is DateTimeKind.Unspecified, it is assumed to be local time (as if it were DateTimeKind.Local). (Scroll down to the Remarks section in the docs here.) Thus, you are converting as if the Unix timestamp were local-time based, rather than the actuality that it is UTC based. You get different results between your workstation and server because they have different system-local time zones - not because they are running different operating systems.
There are a number of different ways to rewrite this to address the problem. I will give you a few to choose from, in order of my preference:
You could leave everything as a DateTimeOffset throughout the conversion process:
DateTimeOffset value = DateTimeOffset.FromUnixTimeSeconds(1597325462);
string easternZoneId = "America/New_York";
TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId);
DateTimeOffset targetTime = TimeZoneInfo.ConvertTime(value, easternZone);
You could use the .UtcDateTime property instead of the .DateTime property:
DateTimeOffset value = DateTimeOffset.FromUnixTimeSeconds(1597325462);
DateTime showTime = value.UtcDateTime;
string easternZoneId = "America/New_York";
TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId);
DateTime targetTime = TimeZoneInfo.ConvertTime(showTime, easternZone);
You could use ConvertTimeFromUtc instead of ConvertTime:
DateTimeOffset value = DateTimeOffset.FromUnixTimeSeconds(1597325462);
DateTime showTime = value.DateTime;
string easternZoneId = "America/New_York";
TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId);
DateTime targetTime = TimeZoneInfo.ConvertTimeFromUtc(showTime, easternZone);
You could specify UTC as the source time zone in the ConvertTime call:
DateTimeOffset value = DateTimeOffset.FromUnixTimeSeconds(1597325462);
DateTime showTime = value.DateTime;
string easternZoneId = "America/New_York";
TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId);
DateTime targetTime = TimeZoneInfo.ConvertTime(showTime, TimeZoneInfo.Utc, easternZone);
There are a few other options, such as explicitly setting the kind, but I think the above gives you enough to go on.
If in doubt, pick the first option. DateTimeOffset is much easier to rationalize than DateTime in most cases.
The issue seems to be that there is not such a timezone I'd in the ICU library that both OS look into.
Check the example in the Microsoft docs:
https://learn.microsoft.com/en-us/dotnet/api/system.timezoneinfo.converttimebysystemtimezoneid?view=netcore-3.1
DateTime currentTime = DateTime.Now;
Console.WriteLine("New York: {0}",
TimeZoneInfo.ConvertTimeBySystemTimeZoneId(currentTime, TimeZoneInfo.Local.Id, "Eastern Standard Time"));
So it looks like the id you should look for is ""Eastern Standard Time"
If you can't find it then run the following code to check the available timezones on your pc
foreach (TimeZoneInfo z in TimeZoneInfo.GetSystemTimeZones())
Console.WriteLine(z.Id);
The destinationTimeZoneId parameter must correspond exactly to the time zone's identifier in length, but not in case, for a successful match to occur; that is, the comparison of destinationTimeZoneId with time zone identifiers is case-insensitive.
So check the timezones and copy the correct string to use based on what exists on the machine.
I save time to UTC in database.
And I want convert time to local time zone when get time data from database.
Here is function.
public static List<string> convertListDateTime(List<string> timelist, TimeZoneInfo local)
{
for (int i = 0; i < timelist.Count; i++)
{
DateTime dt = DateTime.Parse(timelist[i]);
dt = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(dt, local.Id);
timelist[i] = dt.ToString("yyyy-MM-dd HH:mm:ss");
}
return timelist;
}
timelist is string list that has data from database.
But timelist is not change. It is the same as the database data.
How can I do?
This is the first problem:
DateTime dt = DateTime.Parse(timelist[i]);
You haven't said that the value is in UTC, so it's assumed to be in local time. A conversion from that to local time is a no-op. You can fix that when parsing by saying that the input is in UTC and you want the output to be in UTC too:
DateTime dt = DateTime.ParseExact(
timelist[i],
"yyyy-MM-dd HH:mm:ss",
CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
But secondly, you should try to avoid all this string conversion anyway: if you store the values in the database as DateTime values instead of strings, that makes things a lot easier.
I would try to use the values as DateTime values as far as possible too - only convert to strings when you absolutely have to, and ideally not as part of an operation which is also performing time zone changes.
Finally, rather than using ConvertTimeBySystemTimeZoneId, if you've already got a TimeZoneInfo you can use that directly:
DateTime convertedValue = TimeZoneInfo.ConvertTimeFromUtc(utcValue, zoneInfo);
I need to send a start date and end date to an API in UTC format, I have tried the following:
DateTime startDate = Convert.ToDateTime(start + "T00:00:00Z").ToUniversalTime();
DateTime endDate = Convert.ToDateTime(end + "T23:59:59Z").ToUniversalTime();
But it appears they are not converting to UTC, what would be the proper way to take startDate and endDate and convert them over to UTC?
start is a string and is 2018-08-31 and end date is also a string and is 2018-08-31 I added the times in the code above to cover the full date.
Assuming you want endDate to represent the last possible moment on the given date in UTC:
DateTime startDate = DateTime.ParseExact(start, "yyyy-MM-dd", CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
DateTime endDate = DateTime.ParseExact(end, "yyyy-MM-dd", CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal)
.AddDays(1).AddTicks(-1);
A few other things:
ToUniversalTime converts to UTC from the computer's local time zone (unless .Kind == DateTimeKind.Utc). You should generally avoid it unless the computer's local time zone is relevant to your situation.
In the above code, you need both AssumeUniversal to indicate that the input date is meant to be interpreted as UTC, and AdjustToUniversal to indicate that you want the output value to be kept in terms of UTC and not the computer's local time zone.
UTC is not a "format". Your combined date and time strings would be in ISO 8601 extended format (also RFC 3339 compliant).
Generally, try not to use Convert.ToDateTime. It is equivalent to DateTime.Parse with CultureInfo.CurrentCulture and no DateTimeStyles. That may work for some scenarios, but it is usually better to be more specific.
.AddDays(1).AddTicks(-1) is there to get you to the last representable tick on that date. That allows for inclusive comparison between start and end, however it comes with the disadvantage of not being able to subtract the two values and get a whole 24 hours. Thus, it is usually better to simply track 00:00 of one day to 00:00 of the next day, then use exclusive comparison on the end date. (Only the start date should be compared inclusively.)
In other words, instead of:
2018-08-31T00:00:00.0000000Z <= someValueToTest <= 2018-08-31T23:59:59.9999999Z
Do this:
2018-08-31T00:00:00.0000000Z <= someValueToTest < 2018-09-01T00:00:00.0000000Z
First install below package from NuGet package manager and referenced it in your project:
Install-Package Newtonsoft.Json
Now you can easily use JsonConvert.SerializeObject(object value) method for serialize any objects to Json.
For converting DateTime to UTC use TimeZoneInfo.ConvertTimeToUtc(DateTime dateTime) method.
In your case:
DateTime date = DateTime.Parse("2018-08-31");
DateTime dateTimeToUtc = TimeZoneInfo.ConvertTimeToUtc(date);
string dateInJson = JsonConvert.SerializeObject(dateTimeToUtc);
the variable dateInJson will have value like 2018-08-30T19:30:00Z.
Remove the Z
string start = "2018-08-31";
string end = "2018-08-31";
DateTime startDate = Convert.ToDateTime(start + "T00:00:00");
DateTime endDate = Convert.ToDateTime(end + "T23:59:59");
Console.WriteLine(startDate); // 8/31/2018 12:00:00 (Local)
Console.WriteLine(startDate.ToUniversalTime()); // 8/31/2018 5:00:00 (UTC)
Console.WriteLine(endDate); // 8/31/2018 11:59:59 (Local)
Console.WriteLine(endDate.ToUniversalTime()); // 9/1/2018 4:59:59 (UTC)
In case you are sending dynamic linq like me, you'd need datetime in a text form.
If you are dealing with UTC then:
//specify utc just to avoid any problem
DateTime dateTime = yourDateTime.SetKindUtc();
var filterToSendToApi = $"CreatedTime>={dateTime.ToStringUtc()}"
helpers:
public static string ToStringUtc(this DateTime time)
{
return $"DateTime({time.Ticks}, DateTimeKind.Utc)";
}
public static DateTime SetKindUtc(this DateTime dateTime)
{
if (dateTime.Kind == DateTimeKind.Utc)
{
return dateTime;
}
return DateTime.SpecifyKind(dateTime, DateTimeKind.Utc);
}
My data in SQL database looks like this:
PubDateUTC PubDateUTCOffset
----------------------- --------------------
2011-08-04 10:02:50.000 +8:00:00
2012-04-23 02:32:25.287 +8:00:00
2010-09-26 04:23:00.000 +8:00:00
What I want is to get a DateTime based on PubDateUTC and PubDateUTCOffset, for example:
2011-08-04 10:02:50.000, +8:00:00 should result in 2011-08-04 18:02:50:000
I have tried with TimeZoneInfo class, but I don't know hot to create a instance of TimeZoneInfo with a string like "+8:00:00", which would be the CreateTimeZoneInfo method below
var tz = CreateTimeZoneInfo(post.PubDateUTCOffset);
return TimeZoneInfo.ConvertTimeFromUtc(post.PubDateUTC, tz);
Is there anyway to do this?
Note: I cannot change the data in SQL database.
You could try something like:
var date = post.PubDateUTC.Add(
TimeSpan.Parse(post.PubDateUTCOffset.Replace("+", ""))
);
The .Replace("+", "") is because TimeSpan will handle -01:00:00 but will choke on +01:00:00
I think you need to use DateTimeOffset class. This thread may be helpful.
http://msdn.microsoft.com/en-us/library/bb546101.aspx
This works, remove any leading "+" from the offset ( "-" are ok)
var d = new DateTimeOffset(DateTime.Parse("2011-08-04 10:02:50.000"),
TimeSpan.Parse("08:00:00"));
d.DateTime - the time in db = 10:02:50
d.LocalDateTime - the time according to your servers timezone
d.UtcDateTime - the time at GMT = 02:02:50
I'm not sure you want 18:02:50 since it is the time at GMT+16 (+16:00:00), unless of course that is how it's encoded in the db, then just ignore this post :)
You should change your post class to have one property:
public DateTimeOffset Published { get; set; }
Then when you read from the database (assuming you have datetime and varchar types in your database):
DateTime utc = DateTime.SpecifyKind(
(DateTime) reader["PubDateUTC"], DateTimeKind.Utc);
TimeSpan offset = TimeSpan.Parse(
((string) reader["PubDateUTCOffset"]).Replace("+", ""))
post.Published = new DateTimeOffset(utc).ToOffset(offset);
Then when you need to consume it, you have all of the options of a full DateTimeOffset:
DateTime local = post.Published.DateTime; // with your offset applied
DateTime utc = post.Published.UtcDateTime; // the original utc value
string s = post.Published.ToString("o"); // 2011-08-04T18:02:50.0000000+08:00
If I run:
// 7:10 am at a location which has a +2 offset from UTC
string timeString = "2011-06-15T07:10:25.894+02:00";
DateTime time = DateTime.Parse(timeString);
It gives me time = 6/14/2011 10:10:25 PM. This is the local time where I am at (Pacific time i.e. UTC -7).
Is there an elegant way of getting the local time at the origin i.e. 6/15/2011 07:10:25 AM?
You can use TimeZoneInfo:
DateTime localTime = DateTime.Now;
TimeZoneInfo targetTimeZone =
TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
DateTime targetTime = TimeZoneInfo.ConvertTime(localTime, targetTimeZone);
Actually, the ConvertTimeBySystemTimeZoneId method would be even more succinct:
DateTime targetTime =
TimeZoneInfo.ConvertTimeBySystemTimeZoneId(localTime, "Eastern Standard Time");
You can get information for time zones available using TimeZoneInfo.GetSystemTimeZones().
The DateTimeOffset structure seems to be built to specifically handle timezones. It includes most of the functionality of the DateTime type.
string timeString = "2011-06-15T07:10:25.894+02:00";
DateTimeOffset time = DateTimeOffset.Parse(timeString);
As this article illustrates, you should DateTimeOffset instead of DateTime whenever you need to unambiguously identify a single point in time.
Lock into using TimeZoneInfo - http://msdn.microsoft.com/en-us/library/system.timezoneinfo.aspx to do conversions. FindSystemTimeZoneById and ConvertTimeFromUtc should be enough. You may need to convert your local DateTime to UTC first with DateTime.ToUniversalTime.
You can format the way DateTime is Parse.
For example, if I want the DateTime to be format in french Canadian format :
IFormatProvider culture = new CultureInfo("fr-CA", true);
DateTime dt = DateTime.ParseExact(dateString, "dd-MM-yyyy", culture);
You can do it the same way for a en-US culture and add the time format to specify the format you want ...