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
Related
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
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);
}
This code has been working for a long time now but has broken now when I try to pass DateTime.Now as the outageEndDate parameter:
public Outage(DateTime outageStartDate, DateTime outageEndDate, Dictionary<string, string> weeklyHours, string province, string localProvince)
{
this.outageStartDate = outageStartDate;
this.outageEndDate = outageEndDate;
this.weeklyHours = weeklyHours;
this.province = province;
localTime = TimeZoneInfo.FindSystemTimeZoneById(timeZones[localProvince]);
if (outageStartDate < outageEndDate)
{
TimeZoneInfo remoteTime = TimeZoneInfo.FindSystemTimeZoneById(timeZones[province]);
outageStartDate = TimeZoneInfo.ConvertTime(outageStartDate, localTime, remoteTime);
outageEndDate = TimeZoneInfo.ConvertTime(outageEndDate, localTime, remoteTime);
The error message I am getting on the last line is that the Kind property is not set correctly on the DateTime parameter (outageEndDate). I've Googled and checked SO for examples but I don't really understand the error message.
Any advice is appreciated.
Regards.
EDIT - The exact error message is:
The conversion could not be completed because the supplied DateTime did not have the Kind
property set correctly. For example, when the Kind property is DateTimeKind.Local, the source
time zone must be TimeZoneInfo.Local. Parameter name: sourceTimeZone
EDIT: outageEndDate.Kind = Utc
Thanks for clarifying your question.
If the DateTime instance Kind is Local, then TimeZoneInfo.ConvertTime will expect the second parameter to be the local timezone of your computer.
If DateTime instance Kind is Utc, then TimeZoneInfo.ConvertTime will expect the second parameter to be the Utc timezone.
You need to convert outageEndDate to the right timezone first, just in case the localProvice timezone doesn't match the timezone on your computer.
outageEndDate = TimeZoneInfo.ConvertTime(outageEndDate, localTime);
here is an example of something that you could try
It depends on what you mean by "a GMT + 1 timezone". Do you mean permanently UTC+1, or do you mean UTC+1 or UTC+2 depending on DST?
If you're using .NET 3.5, use TimeZoneInfo to get an appropriate time zone, then use:
// Store this statically somewhere
TimeZoneInfo maltaTimeZone = TimeZoneInfo.FindSystemTimeZoneById("...");
DateTime utc = DateTime.UtcNow;
DateTime malta = TimeZoneInfo.ConvertTimeFromUtc(utc, maltaTimeZone );
You'll need to work out the system ID for the Malta time zone, but you can do that easily by running this code locally:
Console.WriteLine(TimeZoneInfo.Local.Id);
If you're not using .NET 3.5, you'll need to work out the daylight savings yourself. To be honest, the easiest way to do that is going to be a simple lookup table. Work out the DST changes for the next few years, then write a simple method to return the offset at a particular UTC time with that list hardcoded. You might just want a sorted List<DateTime> with the known changes in, and alternate between 1 and 2 hours until your date is after the last change:
// Be very careful when building this list, and make sure they're UTC times!
private static readonly IEnumerable<DateTime> DstChanges = ...;
static DateTime ConvertToLocalTime(DateTime utc)
{
int hours = 1; // Or 2, depending on the first entry in your list
foreach (DateTime dstChange in DstChanges)
{
if (utc < dstChange)
{
return DateTime.SpecifyKind(utc.AddHours(hours), DateTimeKind.Local);
}
hours = 3 - hours; // Alternate between 1 and 2
}
throw new ArgumentOutOfRangeException("I don't have enough DST data!");
}
In db I save DateTime in UTC like this:
CreatedDate = DateTime.UtcNow;
and also for every user I save timezone in this format "+0200", "-0300", "-0430"
now I want to filter results by date
SQL: SELECT * FROM tableName WHERE CreatedDate >= GETDATE()
how add value from timezone column to the selected dateTime?
you can do something similar to this
DateTime utcDateTime = DateTime.UtcNow;
TimeSpan offSet = TimeSpan.Parse("+01:00:00");
DateTime checkDate = utcDateTime + offSet;
and then pass checkDate as parameter to the query
Depending on the language you are using, you can get this from the client application, e.g. for javascript.
var offset = new Date().getTimezoneOffset();
Getting the client's timezone in JavaScript
This way you don't need to store it in the DB.
To add the time back in for your example, use parsing and DATEADD http://msdn.microsoft.com/en-gb/library/ms186819.aspx
Something like this:
storedDate.AddHours(double.Parse(timezoneOffset)/100).ToString();
Untested!
EDIT
Or use something like this: (Again, untested)
TimeZoneInfo[] tz = TimeZoneInfo.GetSystemTimeZones().ToArray();
string t1 = tz.First(t => t.BaseUtcOffset == TimeSpan.FromHours(Math.Round((double.Parse(stored) / 100), 1))).Id;
DateTime time= TimeZoneInfo.ConvertTimeBySystemTimeZoneId(storedDate, t1);
I have a date that shows up as 10/18/2011 3:12:33 PM
How do I get only the time portion of this datetime?
I am using C#.
I tried:
string timeval = PgTime.ToShortTimeString();
but that did not work as Intellisense only showed ToString();
Assuming that
DateTime PgTime;
You can:
String timeOnly = PgTime.ToString("t");
Other format options can be viewed on MSDN.
Also, if you'd like to combine it in a larger string, you can do either:
// Instruct String.Format to parse it as time format using `{0:t}`
String.Format("The time is: {0:t}", PgTime);
// pass it an already-formatted string
String.Format("The time is: {0}", PgTime.ToString("t"));
If PgTime is a TimeSpan, you have a few other options:
TimeSpan PgTime;
String formattedTime = PgTime.ToString("c"); // 00:00:00 [TimeSpan.ToString()]
String formattedTime = PgTime.ToString("g"); // 0:00:00
String formattedTime = PgTime.ToString("G"); // 0:00:00:00.0000000
If you want a formatted string, just use .ToString(format), specifying only time portions. If you want the actual time, use .TimeOfDay, which will be a TimeSpan from midnight.
DateTime PgTime = new DateTime();
var hr = PgTime.Hour;
var min = PgTime.Minute;
var sec = PgTime.Second;
//or
DateTime.Now.ToString("HH:mm:ss tt") gives it to you as a string.
Don't now nothing about a class named PgTime. Do now about DateTime, though.
Try
DateTime instance = DateTime.Now ; // current date/time
string time = instance.ToString("t") ; // short time formatted according to the rules for the current culture/locale
Might want to read up on Standard Date and Time Format Strings and Custom Date and Time Format Strings
In C# 10 you can use TimeOnly.
TimeOnly date = TimeOnly.FromDateTime(PgTime);