I am using Noda Time (Date and Time Api) for my date conversions from UTC to a provided timezone.
Below is a method that returns a localized DateTime object based on the specified noda time zone id.
"utcDateTime" is the DateTime to convert and "timeZoneId" is the id of the time zone
public static DateTime ConvertDateTimeFromUtc(DateTime utcDateTime, string timeZoneId)
{
utcDateTime = DateTime.SpecifyKind(utcDateTime, DateTimeKind.Utc);
var timeZone = DateTimeZoneProviders.Tzdb[timeZoneId];
var convertedDateTime = Instant.FromDateTimeUtc(utcDateTime)
.InZone(timeZone)
.ToDateTimeUnspecified();
return convertedDateTime;
}
I get a date which is in utc from a collection and trying to convert it to the provided time zone but i get this error
Ticks must be between DateTime.MinValue.Ticks and DateTime.MaxValue.Ticks.
DateUtility.ConvertDateTimeFromUtc(collection.Select(c => c.date).DefaultIfEmpty(DateTime.MinValue).First(), time_zone)
Related
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);
}
I'm working with data from several sources, and I need to put together an accurate DateTime.
I have:
A) a string representing a time of day, e.g.: "4:00 pm"
B) a DateTime object intended to represent a pure date, by having been created as midnight, zulu time (offset of 00:00) for a particular date.
C) a string representing a timezone locale, e.g.: "America/Los_Angeles"
How do I get a precise DateTime object, with correct number of ticks, representing the time (A) experienced in that locale (C), on that date (B)??
Here you have an example using NodaTime, which is more reliable of any of the framework classes when dealing with calendars, time zones, dates and times:
var timeString = "4:00 pm";
var pureDate = new DateTime(2017, 5, 22, 0, 0, 0, DateTimeKind.Utc);
var timezoneString = "America/Los_Angeles";
var localTime = ParseTimeString(timeString);
var localDate = LocalDate.FromDateTime(pureDate);
var localDateTime = localDate.At(localTime);
var zone = DateTimeZoneProviders.Tzdb[timezoneString];
var zonedDateTime = localDateTime.InZoneStrictly(zone);
Inside zonedDateTime you will find your full date:
"2017-05-22T16:00:00 America/Los_Angeles (-07)"
You may than use zonedDateTime.ToDateTimeUtc() to get a System.DateTime instance in UTC.
ParseTimeString parses your time string using your format specifier:
public static LocalTime ParseTimeString(string timeString)
{
var pattern = LocalTimePattern.CreateWithInvariantCulture("h:mm tt");
return pattern.Parse(timeString).Value;
}
Considerations if you use DateTime, DateTimeOffset and TimeZoneInfo
If you do not want to use NodaTime be aware of the possible pitfalls of the built-in classes:
TimeZoneInfo in Windows uses a different specifier that is not compatible with IANA/TZDB. Your America/Los_Angeles time zone string will not work if you do not convert it before use (see https://stackoverflow.com/tags/timezone/info)
DateTimeOffset (which is more reliable then DateTime) still loses information when created. The time zone data cannot be persisted and you will have just a date with an offset from UTC.
You'll need to manually parse your custom time string (maybe using regexes).
Here's how I ended up working it out w/o NodaTime:
public static DateTime Combine(DateTime date, string time, string timeZone)
{
TimeZoneInfo tzInfo = TimeZoneInfo.FindSystemTimeZoneById(TimezoneDictionary[timeZone]);
var timeOfDay = DateTime.ParseExact(time, "h:mm tt", null).TimeOfDay;
var combined = date.Add(timeOfDay).Subtract(tzInfo.BaseUtcOffset);
if (tzInfo.IsDaylightSavingTime(combined))
combined = combined.Subtract(TimeSpan.FromHours(1));
return combined;
}
I also need this dictionary to convert IANA timezones to Microsoft:
private static Dictionary<string, string> TimezoneDictionary = new Dictionary<string, string>
{
{ "America/Los_Angeles", "Pacific Standard Time" },
{ "America/Denver", "Mountain Standard Time" },
{ "America/Chicago", "Central Standard Time" },
{ "America/New_York", "Eastern Standard Time" },
//many more of course, just clipping this list for brevity.
};
I have a DateTime constructed explicitly.
var myDateTime = new DateTime(2015,1,1,0,0,0);
I have a timezone obtained explicitly.
var myTimeZone = DateTimeZoneProviders.Tzdb["America/Los_Angeles"];
myDate is known to be represented in myTimeZone
How should I use this information to generate a ZonedDateTime or an Instant using NodaTime?
First, convert your DateTime to a LocalDateTime.
LocalDateTime ldt = LocalDateTime.FromDateTime(myDateTime);
Then you can assign it to a zone:
ZonedDateTime zdt = ldt.InZoneLeniently(myTimeZone);
And map it back to an instant:
Instant instant = zdt.ToInstant();
I have a DateTime dt, which has a date and time of some local instant and a String tz specifying the timezone name for that datetime. How do I get a DateTimeOffset struct fully representing the DateTime?
I can get the timezone info with TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById(csf.TimezoneName);
but I'm now unsure how to get the DateTimeOffset I want from these two elements
You can convert a local time in a particular zone to a DateTimeOffset like this:
DateTime dt = new DateTime(2013, 1, 1, 0, 0, 0);
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
DateTimeOffset dto = new DateTimeOffset(dt, tzi.GetUtcOffset(dt));
Just be aware that if the input time is ambiguous or invalid due to daylight saving time, it will use the zone's standard offset.
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 ...