DateTime + TZ -> NodaTime conversion - c#

When I look about how to convert time to NodaTime, I find many posts but not a single straight answer about what I need.
I have:
- A DateTime object (DateTime myDateTime)
- An Olson timezone (var TZ = "America/Los_Angeles")
I want:
- A ZonedDateTime object (ZonedDateTime myZonedDateTime)
Ideally, I'm looking for some helper like:
var myZonedDateTime = ZonedDateTime.From(myDateTime, TZ);
but all the samples I see go through turning the date into a string and then parsing the string, which seems quite odd.
There is a ZonedDateTime.FromDateTimeOffset() method, but the offset and the TimeZone are different things since the TZ can handle daylight savings.

It sounds like you just want:
var local = LocalDateTime.FromDateTime(myDateTime);
var zone = DateTimeZoneProviders.Tzdb[id];
var zoned = local.InZoneLeniently(zone);
Except:
You may well want to write your own rules instead of using InZoneLeniently
You may want to use DateTimeZoneProviders.Tzdb.GetZoneOrNull(id) if you're not sure whether the zone ID will be recognized by Noda Time.

Related

Converting from CEST /CET date string to UTC date string when CEST timezone not installed on the machine

I need to parse some dates that are in CEST/CET, coming as strings from an external provider, and convert them to UTC.
My current culture on my computer is en-GB and I have the BST timezone installed on my machine, but I do not have CEST. Therefore I cannot use TimeZoneInfo to convert between time zones as I cannot instantiate the one for CEST.
How do I do this in C#? I have looked at similar questions here on StackOverflow and googled this but I cannot find a solution that works.
My code currently works with this, but I think it's a hack, still:
// dateToParse: "2018-09-04T19:17:37.022363"
var theDate = DateTime.ParseExact(dateToParse,
#"yyyy-MM-ddTHH\:mm\:ss\.ffffff",
new CultureInfo("sq-AL"), // this culture info is in CEST. Tried using CultureInfo.InvariantCulture as well - nothing changed
DateTimeStyles.AssumeLocal); // tried putting here DateTimeStyles.None
// Our local time is in BST.
// CEST and BST are always one hour apart so parsing date during daylight saving times will (probably) still work.
// I think. Except for that 1h window when the switch happens...
theDate = theDate.AddHours(-1); // I was hoping to not need this!
var utcDate = theDate.ToUniversalTime();
return utcDate;
So essentially I am looking for something that understands that the date is in CEST, or CET depending on the time of the year, and not in my current BST time, and knows how to turn that into UTC, factoring in things like daylight saving times.
I don't mind using a library - I have very very briefly looked at NodaTime but didn't find an obvious solution there (there very well might be but I didn't put in the time to reliably look for it).
Any help greatly appreciated.
After help from the comments and searching a bit more, this code seems to work well:
var theDate = DateTime.ParseExact(dateToParse,
#"yyyy-MM-ddTHH\:mm\:ss\.ffffff",
CultureInfo.InvariantCulture,
DateTimeStyles.None);
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time");
var utcDate = TimeZoneInfo.ConvertTimeToUtc(theDate, timeZoneInfo);
return utcDate;

Convert timestamp from any timezone to UTC, and optionally without DST

We have timestamps from CSV files that look like this:
06-02-2018 15:04:21
We do not control the delivery of them, nor the timezone.
What we do know so far is that we have seen so far is this:
Standard Romance Time
Standard Romance Time, but without DST compensation.
UTC
From this, we gather that we need an engine that can take any timestamp (written in patterns that DateTime.ParseExact understands), belong to any timezone, optionally ignore DST, and then convert it to UTC (the format we internally use).
I was hoping this could do it:
public DateTime ConvertToUtc(string fromTimestamp, DataReaderConfiguration dataReaderConfiguration)
{
DateTime readTime = DateTime.ParseExact(fromTimestamp, dataReaderConfiguration.TimestampFormat,
CultureInfo.InvariantCulture, DateTimeStyles.None);
DateTime utcTime = TimeZoneInfo.ConvertTimeToUtc(readTime,
TimeZoneInfo.FindSystemTimeZoneById(dataReaderConfiguration.TimeZone));
return utcTime;
}
but C# does not have timezones defined without DST (except for UTC).
So we need to expand on the method to allow for a timezone conversion without DST.
You can create this function yourself, by leveraging the TimeZoneInfo.BaseUtcOffset property and a DateTimeOffset.
public static DateTime ConvertTimeToUtc(DateTime dt, TimeZoneInfo tz, bool useDST)
{
if (useDST)
{
// the normal way (converts using the time in effect - standard or daylight)
return TimeZoneInfo.ConvertTimeToUtc(dt, tz);
}
// the way to convert with just the standard time (even when DST is in effect)
var dto = new DateTimeOffset(dt, tz.BaseUtcOffset);
return dto.UtcDateTime;
}
Then just pass whatever property from your DataReaderConfiguration object that indicates whether you want to use DST (or negate it if necessary).
Also note that this gives the standard time based on the current set of rules. If you are dealing with historical dates where the time zone's standard time has changed, things get a bit more complex. You'd have to figure out which adjustment rules were in place at the time, etc. You might even find edge cases where the Windows time zone data is insufficient.

How to find out if a given DateTime on the day of the DST change? [duplicate]

I have a date as string. There is no time info.
For eg. "20131031" ie) 31 oktober 2013.
I want to verify whether it is the date on which DST happens or not ?
w.r.t. WesternEurope.
ie) Does c# have an API, to say it is a DST date or not ?
I want simply a boolean as return, for the last sunday of October and last sunday of March.
which are the dates on which clocks are adjusted.
Per MSDN Documentation
Important
Whenever possible, use the TimeZoneInfo class instead of the TimeZone class.
You should consider TimeZone deprecated.
Instead, you can check DST for the local time zone like this:
DateTime dt = new DateTime(2013,10,31);
TimeZoneInfo tzi = TimeZoneInfo.Local;
bool isDST = tzi.IsDaylightSavingTime(dt);
For a specific time zone, do this instead:
DateTime dt = new DateTime(2013,10,31);
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time");
bool isDST = tzi.IsDaylightSavingTime(dt);
If you want to know when the daylight periods start and stop, you'll have to work through the transition rules from tzi.GetAdjustmentRules(). That can get a bit complex though. You would probably be better off using Noda Time for that.
You can use the TimeZone.IsDaylightSavingTime method, it takes a DateTime:
public virtual bool IsDaylightSavingTime(
DateTime time
)
So for example:
var tz = TimeZone.CurrentTimeZone;
var is_dst = tz.IsDaylightSavingTime(DateTime.Now);
See MSDN for more information.
Yes, there is an API: TimeZone.GetDaylightChanges
http://msdn.microsoft.com/en-us/library/system.timezone.getdaylightchanges.aspx
You provide a year and it will return a DaylightTime object, which contains the start and end dates for daylight saving. You can then compare your date against those two to determine if its a DLS date or not.
Whilst this answer has been accepted, please see Matt Johnson's answer below for details why it's not the best answer and why the TimeZoneInfo class should be used instead. https://stackoverflow.com/a/19523173/7122

Convert some local time to UTC in C#

I am trying do to something like this:
On a client side I have datepicker for selecting date, drop down for selecting an hour, and drop down with time zones for selecting user time zone.
I am sending this info to server. On a server side, I want to accomplish this:
Take date and time values, and check what is the value of time zone.
If it is for example "UTC+1" (or any other +- value of UTC time), convert that into UTC, before saving.
What I am not sure how to do it is: What value should I send from client as time zone information so server can detect it is a for example UTC+1.
I saw examples like this:
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
On how to find out what is the time zone by its id, but I cannot do something like this:
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("UTC+1");
Because, I get an exception, of course:
Additional information: The time zone ID 'UTC+1' was not found on the
local computer.
Does someone know what is Id for all UTC+-someNumber, or there is a way to detect timezone from UTC string in some different way?
Did someone had experience whit this kind of a conversion?
As far as I remember the only way to work with the timezones is by the full name that is available in your OS.
You can find a similar question here.
A list from MSDN is here.
So there seems to be no easy way to convert strings like "UTC+1", unless you create a mapping to the ones that are supported by framework.
You could use TimeZoneInfo.CreateCustomTimeZone():
DateTime utcTime = DateTime.UtcNow;
TimeZoneInfo targetTimeZone = TimeZoneInfo.CreateCustomTimeZone("MyId", TimeSpan.FromHours(1), "Somewhere", "Somewhere");
DateTime targetTime = TimeZoneInfo.ConvertTime(utcTime, targetTimeZone);
or you can use DateTimeOffset, or DateTime.AddHours(1):
var datetimeOffset = new DateTimeOffset(yourDateTime, TimeSpan.FromHours(1));
var otherDatetime = yourDateTime.AddHours(1);

Converting UK times (both BST and GMT) represented as strings to UTC (in C#)

I have to use some dates and times from a legacy database. They are represented as strings. Dates are dd/MM/yy. Times are HH:mm.
I'd like to convert these to UTC as soon as I pull them from the database. I'm working on US systems, so need a common time.
The problem I'm facing is how to convert them to UTC DateTime values. I can do the parsing, etc. The real problem I have concerns the timezone.
I'm trying to use the following approach:
DateTime ukTime = // Parse the strings in a DateTime value.
TimeZoneInfo timeZoneInformation = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
DateTimeOffset utcTime = new DateTimeOffset(ukTime, timeZoneInformation.BaseUtcOffset);
However, this gives incorrect values if the date is in the British Summer Time period.
I can use "GMT Daylight Time" on those dates, but that requires me to know when the switchover is. I'm sure there must be a less laborious way.
As I'm not using a machine with UK time settings I can't rely on local time.
Basically, I need something like:
// Works for both GMT (UTC+0) and BST (UTC+1) regardless of the regional settings of the system it runs on.
DateTime ParseUkTimeAsUtcTime(string date, string time)
{
...
}
I've scoured the posts, but couldn't find anything that addressed this directly. Surely this is also an issue with EST, EDT, etc?
Try using the GetUtcOffset() method on your TimeZoneInfo instance, which takes "adjustment rules" into consideration.
Using this should work basically the same as your original example, but you'll use that method instead of the BaseUtcOffset property.
DateTime ukTime = // Parse the strings in a DateTime value.
TimeZoneInfo timeZoneInformation = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
DateTimeOffset utcTime = new DateTimeOffset(ukTime, timeZoneInformation.GetUtcOffset(ukTime));
How about:
DateTime.Parse(dateTimeString).ToUniversalTime();
Assuming that the database server stores its datetimes in the same timezone as your application server.

Categories

Resources