TimeZone conversion displaying EDT instead of EST - c#

I am using this piece of code to convert "Eastern Time Zone" to "EST". Now it is showing "EDT". You dont see that abbr that often in places and would like to stick to "EST". How do I do this with NodaTime?
public static string GetTimeZoneAbbr(string timeZone)
{
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timeZone);
if (timeZoneInfo != null)
{
var dateTime = DateTime.UtcNow;
var instant = Instant.FromDateTimeUtc(dateTime);
var tzdbSource = TzdbDateTimeZoneSource.Default;
var tzid = tzdbSource.MapTimeZoneId(timeZoneInfo);
var dateTimeZone = DateTimeZoneProviders.Tzdb[tzid];
var zoneInterval = dateTimeZone.GetZoneInterval(instant);
return zoneInterval.Name;
}
return string.Empty;
}

UPDATE
The answer below described how to parse and use the CLDR data. This is fine, but I've made it much easier by encompassing this all in a library. See this StackOverflow answer, read my blog post, and take a look at the TimeZoneNames library. Using this library is much easier than parsing the CLDR data yourself.
// You can pass either type of time zone identifier:
var tz = "America/New_York"; // IANA
var tz = "Eastern Standard Time"; // Windows
// You can get names or abbreviations for any language or locale
var names = TZNames.GetNamesForTimeZone(tz, "en-US");
var abbreviations = TZNames.GetAbbreviationsForTimeZone(tz, "en-US");
names.Generic == "Eastern Time"
names.Standard == "Eastern Standard Time"
names.Daylight == "Eastern Daylight Time"
abbreviations.Generic == "ET"
abbreviations.Standard == "EST"
abbreviations.Daylight == "EDT"
ORIGINAL ANSWER
I've written a bit in the question comments about why it's perfectly valid to show the abbreviated form, but allow me to also answer the question as it was asked.
Reiterating your question another way, you wish to start with a Microsoft Windows time zone id, and end up with a human-readable string that represents the entire time zone, and not just the time zone segment that is in effect.
You could just give them the TimeZoneInfo.DisplayName, but that isn't always going to be appropriate. For the US, you might get a display name back of "(UTC-05:00) Eastern Time (US & Canada), and you could strip off the leading offset and parenthesis to just give back "Eastern Time (US & Canada)". But that's not going to work for all time zones, since many just have display names that list cities, such as "(UTC-04:00) Georgetown, La Paz, Manaus, San Juan".
A better approach would be to use the data from the Unicode CLDR Project. Noda Time has a portion of this data, but not everything you need for this particular problem. So I can't give you a code example that uses Noda Time. However, you can use the following steps against the raw CLDR data to achieve your goal:
Find the IANA time zone ID corresponding to the Windows time zone, such as you've already done in the code above, or using the CLDR Windows time zone mappings directly.
Lookup the IANA time zone in the CLDR MetaZones file.
Lookup the MetaZone in one of the CLDR translation data files, or charts such as this one. Use the "generic-long" or "generic-short" pattern, and the language of your choice, such as "en" for English.
So, in your case, starting with the Windows TimeZoneInfo.Id of "Eastern Standard Time":
IANA Zone = "America/New_York"
CLDR MetaZone = "America_Eastern"
generic-long [en] = "Eastern Time"
generic-short [en] = "ET"
Note that not every Windows time zone is mappable to an IANA zone, not every meta zone has a short name, and some zones that have never followed daylight saving time will only have a standard name instead of a generic name.
Here is some C# code that shows how to traverse the CLDR's XML data to get the generic long names for the TimeZoneInfo objects. It assumes you have access to the CLDR data at the path specified. Download the latest core.zip and extract, then point the basePath at that folder.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;
static Dictionary<TimeZoneInfo, string> GetCldrGenericLongNames(string basePath, string language)
{
// Set some file paths
string winZonePath = basePath + #"\common\supplemental\windowsZones.xml";
string metaZonePath = basePath + #"\common\supplemental\metaZones.xml";
string langDataPath = basePath + #"\common\main\" + language + ".xml";
// Make sure the files exist
if (!File.Exists(winZonePath) || !File.Exists(metaZonePath) || !File.Exists(langDataPath))
{
throw new FileNotFoundException("Could not find CLDR files with language '" + language + "'.");
}
// Load the data files
var xmlWinZones = XDocument.Load(winZonePath);
var xmlMetaZones = XDocument.Load(metaZonePath);
var xmlLangData = XDocument.Load(langDataPath);
// Prepare the results dictionary
var results = new Dictionary<TimeZoneInfo, string>();
// Loop for each Windows time zone
foreach (var timeZoneInfo in TimeZoneInfo.GetSystemTimeZones())
{
// Get the IANA zone from the Windows zone
string pathToMapZone = "/supplementalData/windowsZones/mapTimezones/mapZone" +
"[#territory='001' and #other='" + timeZoneInfo.Id + "']";
var mapZoneNode = xmlWinZones.XPathSelectElement(pathToMapZone);
if (mapZoneNode == null) continue;
string primaryIanaZone = mapZoneNode.Attribute("type").Value;
// Get the MetaZone from the IANA zone
string pathToMetaZone = "/supplementalData/metaZones/metazoneInfo/timezone[#type='" + primaryIanaZone + "']/usesMetazone";
var metaZoneNode = xmlMetaZones.XPathSelectElements(pathToMetaZone).LastOrDefault();
if (metaZoneNode == null) continue;
string metaZone = metaZoneNode.Attribute("mzone").Value;
// Get the generic name for the MetaZone
string pathToNames = "/ldml/dates/timeZoneNames/metazone[#type='" + metaZone + "']/long";
var nameNodes = xmlLangData.XPathSelectElement(pathToNames);
var genericNameNode = nameNodes.Element("generic");
var standardNameNode = nameNodes.Element("standard");
string name = genericNameNode != null
? genericNameNode.Value
: standardNameNode != null
? standardNameNode.Value
: null;
// If we have valid results, add to the dictionary
if (name != null)
{
results.Add(timeZoneInfo, name);
}
}
return results;
}
Calling this will get you a dictionary which you can then use for lookups. Example:
// load the data once an cache it in a static variable
const string basePath = #"C:\path\to\extracted\cldr\core";
private static readonly Dictionary<TimeZoneInfo, string> timeZoneNames =
GetCldrGenericLongNames(basePath, "en");
// then later access it like this
string tzname = timeZoneNames[yourTimeZoneInfoObject];

Related

How to change a past date from local Eastern time to Central European Time while accounting for daylight savings? [duplicate]

I find it hard to understand how UTC works.
I have to do the following but I'm still confused if I'd get the right result.
Objectives:
Ensure all saved dates in Database are in UTC format
Update DefaultTimezone is in Manila time
Ensure all returned dates are in Manila Time
So the code is:
public ConvertDate(DateTime? dateTime)
{
if (dateTime != null)
{
Value = (DateTime)dateTime;
TimeZone = GetFromConfig.DefaultTimeZone();
}
}
public ConvertDate(DateTime? dateTime, int GMTTimeZone)
{
if (dateTime != null)
{
Value = (DateTime)dateTime;
TimeZone = GMTTimeZone;
}
}
public int TimeZone
{
get { return m_TimeZone; }
set { m_TimeZone = value; }
}
DateTime m_Value;
public DateTime Value
{
get { return m_Value; }
set
{
m_Value = value;
DateTime converted = m_Value.ToUniversalTime().ToLocalTime();
}
}
Sample usage:
DateTime SampleInputFromUser = new DateTime(2012, 1, 22);
ConvertDate newConversion = new ConvertDate(SampleInputFromUser, 21);
DateTime answer = newConversion.Value;
Now I get confused for 'TimeZone'. I don't know how to use it to get the objectives.
Hope you understand my question and have the idea to get the objectives done.
Edit
According to #raveturned answer, I get this following code:
***Added in ConvertDate method
TimeZoneInfo timeInfo = TimeZoneInfo.FindSystemTimeZoneById(GetFromConfig.ManilaTimeZoneKey());
ManilaTime = TimeZoneInfo.ConvertTime(dateTime.Value, TimeZoneInfo.Local, timeInfo).ToUniversalTime();
**New Property
DateTime _ManilaTime;
public DateTime ManilaTime
{
get { return _ManilaTime; }
set { _ManilaTime = value; }
}
The .NET framework already has classes and methods available to convert DateTimes between different time zones. Have a look at the ConvertTime methods of the TimeZoneInfo class.
Edit: When you get the time to put into the database, assuming it was created with correct time zone information you can easily convert to UTC:
DateTime utcTime = inputDateTime.ToUniversalTime();
Get timeInfo as done in the question edit:
TimeZoneInfo timeInfo = TimeZoneInfo.FindSystemTimeZoneById(GetFromConfig.ManilaTimeZoneKey());
When you send the database time to user, convert it to the correct timezone using timeInfo.
DateTime userTime = TimeZoneInfo.ConvertTimeFromUtc(dbDateTime, timeInfo);
Personally I'd try and keep this logic separate from the propery get/set methods.
var date = System.TimeZoneInfo.ConvertTimeFromUtc(
DateTime.UtcNow,
TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"));
TimeZoneInfo infotime = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time (Mexico)");
DateTime thisDate = TimeZoneInfo.ConvertTimeFromUtc(datetimeFromBD, infotime);
To help others:
static void ChangeTimezone()
{
// Timezone string here:
foreach (TimeZoneInfo z in TimeZoneInfo.GetSystemTimeZones())
Console.WriteLine(z.Id);
// Use one of those timezone strings
DateTime localDt = DateTime.Today;
DateTime utcTime = localDt.ToUniversalTime();
TimeZoneInfo timeInfo = TimeZoneInfo.FindSystemTimeZoneById("US Eastern Standard Time");
DateTime estDt = TimeZoneInfo.ConvertTimeFromUtc(utcTime, timeInfo);
return;
}
For anyone facing problem in getting TimeZoneInfo in cross-platform (different time zone ids between Windows and Linux), .NET 6 addresses this issue:
Starting with this release, the TimeZoneInfo.FindSystemTimeZoneById method will automatically convert its input to the opposite format if the requested time zone is not found on the system. That means that you can now use either IANA or Windows time zone IDs on any operating system that has time zone data installed*. It uses the same CLDR mappings, but gets them through .NET’s ICU globalization support, so you don’t have to use a separate library.
A brief example:
// Both of these will now work on any supported OS where ICU and time zone data are available.
TimeZoneInfo tzi1 = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time");
TimeZoneInfo tzi2 = TimeZoneInfo.FindSystemTimeZoneById("Australia/Sydney");
Find more info here
And as mentioned in other answers: to get DateTime in the desired timezone from UTC, use TimeZoneInfo.ConvertTimeFromUtc(DateTime, TimeZoneInfo) Method

Problem with converting time according to timezone in C#

I am trying to convert a DateTime into UTC from a source timezone. Date, time and timezone are taken as inputs from a user (presented as dropdown menu options).
Following is a portion of the code utilized for conversion:
string inputDateString = "2019-11-12T09:00:00.000"; //Taken as input from user
string inputTimeZoneString = "(UTC-03:00) Brasilia"; // Taken as input from user
DateTime dtStartdatetime = DateTime.Parse(inputDateString);
string sourceTimeZone = string.Empty;
foreach (TimeZoneInfo a in TimeZoneInfo.GetSystemTimeZones())
{
if (a.DisplayName == objCalendar.timezone)
{
sourceTimeZone = a.Id;
}
string strTimeZone = a.DisplayName.Substring(a.DisplayName.IndexOf(')') + 1);
string strTimeZone1 = objCalendar.timezone.Substring(objCalendar.timezone.IndexOf(')') + 1);
if (strTimeZone.Trim() == strTimeZone1.Trim())
{
sourceTimeZone = a.Id;
}
}
DateTime utc_time_start = TimeZoneInfo.ConvertTimeToUtc(dtStartdatetime, TimeZoneInfo.FindSystemTimeZoneById(sourceTimeZone));
Console.WriteLine(utc_time_start.ToString("yyyyMMddTHHmmssZ"));
The problem is that this piece of code gives 20191112T120000Z as output when run on Dev system (based in IST timezone) whereas same code results in 20191112T110000Z as output when run on server (based in EST). Is this behavior due to difference in timezone of the systems on which it is being run? What is could be a possible solution for this situation? A particular time from a particular timezone should result in same UTC time irrespective of the machine where the code executes.
The time zone that your server is running in does not impact this code.
The difference is due to the end of DST for Brazil in 2019.
Windows released an update in July 2019 to cover this scenario. Specifically, this change is addressed by KB4507704 and Windows 10 Build 17763.652. Your dev environment has this update, the server does not. You should ensure your server is receiving Windows Updates. If it's missing this (5 months after release), it's probably missing more critical security updates as well.
Additionally, I strongly discourage matching time zone by display name for a few reasons:
The display names are localized by the primary language of the operating system, so they will be different, for example, on a server set for English than on a server set for Portuguese. (The globalization and localization settings in .NET are not used for this.)
The display names are potentially volatile. That is, if there is a reason to change the display name in a future update, the string will change from what you previously had used.
Instead, pass the Id of the time zone as an input to TimeZoneInfo.FindSystemTimeZoneById, and skip the matching bit in the middle entirely.
You are not leaving your loop after you found a source time zone.
In your second part you search for a partial string of the time zone. Most probably this part finds a second time zone on your server. This can happen if the OS or .net versions differ.
Try:
string inputDateString = "2019-11-12T09:00:00.000"; //Taken as input from user
string inputTimeZoneString = "(UTC-03:00) Brasilia"; // Taken as input from user
var dtStartdatetime = DateTime.Parse(inputDateString);
string sourceTimeZone = string.Empty;
foreach (TimeZoneInfo a in TimeZoneInfo.GetSystemTimeZones())
{
if (a.DisplayName == inputTimeZoneString)
{
sourceTimeZone = a.Id;
break;
}
string strTimeZone = a.DisplayName.Substring(a.DisplayName.IndexOf(')') + 1);
string strTimeZone1 = inputTimeZoneString.Substring(inputTimeZoneString.IndexOf(')') + 1);
if (strTimeZone.Trim() == strTimeZone1.Trim())
{
sourceTimeZone = a.Id;
break;
}
}
DateTime utc_time_start = TimeZoneInfo.ConvertTimeToUtc(dtStartdatetime, TimeZoneInfo.FindSystemTimeZoneById(sourceTimeZone));
Console.WriteLine(utc_time_start.ToString("yyyyMMddTHHmmssZ"));

Nodatime create a ZonedDateTime given a time and timezone

Can anyone give me the most straightforward way to create a ZonedDateTime, given "4:30pm" and "America/Chicago".
I want this object to represent that time for the current date in that timezone.
Thanks!
I tried this... but it seems to actually give me an instant in the local timezone which gets offset when creating the zonedDateTime.
string time = "4:30pm";
string timezone = "America/Chicago";
DateTime dateTime;
if (DateTime.TryParse(time, out dateTime))
{
var instant = new Instant(dateTime.Ticks);
DateTimeZone tz = DateTimeZoneProviders.Tzdb[timezone];
var zonedDateTime = instant.InZone(tz);
using NodaTime;
using NodaTime.Text;
// your inputs
string time = "4:30pm";
string timezone = "America/Chicago";
// parse the time string using Noda Time's pattern API
LocalTimePattern pattern = LocalTimePattern.CreateWithCurrentCulture("h:mmtt");
ParseResult<LocalTime> parseResult = pattern.Parse(time);
if (!parseResult.Success) {
// handle parse failure
}
LocalTime localTime = parseResult.Value;
// get the current date in the target time zone
DateTimeZone tz = DateTimeZoneProviders.Tzdb[timezone];
IClock clock = SystemClock.Instance;
Instant now = clock.Now;
LocalDate today = now.InZone(tz).Date;
// combine the date and time
LocalDateTime ldt = today.At(localTime);
// bind it to the time zone
ZonedDateTime result = ldt.InZoneLeniently(tz);
A few notes:
I intentionally separated many items into separate variables so you could see the progression from one type to the next. You may condense them as desired for fewer lines of code. I also used the explicit type names. Feel free to use var.
You may want to put this in a function. When you do, you should pass in the clock variable as a parameter. This will let you replace the system clock for a FakeClock in your unit tests.
Be sure to understand how InZoneLeniently behaves, and note how it's changing in the upcoming 2.0 release. See "Lenient resolver changes" in the 2.x migration guide.

Want to display date and time based on timezone id Nodatime [duplicate]

This question already has answers here:
How Convert UTC Date & time to local time using different timezone Nodatime
(2 answers)
Closed 8 years ago.
I heard that if I use nodatime library then I can get date & time based on timezone id.
first I change my pc date and time. set to old date and time in my pc and then run the below code which disappoint me.
using NodaTime;
var zoneId = "Asia/Kolkata";
DateTimeZone _zone = DateTimeZoneProviders.Tzdb[zoneId];
ZonedDateTime _now = SystemClock.Instance.Now.InZone(_zone);
var xx = _now.LocalDateTime;
Below code display wrong date & time because I set my pc date & time to few days back.
Is there any way that if date & time is wrong but still code display right date & time without depending on user pc date & time setting using Noda Time library. Looking for suggestion.
UPDATE
i follow this way but not sure am i on right tract to achieve my goal.
public static DateTime GetFastestNISTDate()
{
var result = DateTime.MinValue;
DateTime utcDateTime= DateTime.MinValue;
// Initialize the list of NIST time servers
// http://tf.nist.gov/tf-cgi/servers.cgi
string[] servers = new string[] {
"nist1-ny.ustiming.org",
"nist1-nj.ustiming.org",
"nist1-pa.ustiming.org",
"time-a.nist.gov",
"time-b.nist.gov",
"nist1.aol-va.symmetricom.com",
"nist1.columbiacountyga.gov",
"nist1-chi.ustiming.org",
"nist.expertsmi.com",
"nist.netservicesgroup.com"
};
// Try 5 servers in random order to spread the load
Random rnd = new Random();
foreach (string server in servers.OrderBy(s => rnd.NextDouble()).Take(5))
{
try
{
// Connect to the server (at port 13) and get the response
string serverResponse = string.Empty;
using (var reader = new StreamReader(new System.Net.Sockets.TcpClient(server, 13).GetStream()))
{
serverResponse = reader.ReadToEnd();
}
// If a response was received
if (!string.IsNullOrEmpty(serverResponse))
{
// Split the response string ("55596 11-02-14 13:54:11 00 0 0 478.1 UTC(NIST) *")
string[] tokens = serverResponse.Split(' ');
// Check the number of tokens
if (tokens.Length >= 6)
{
// Check the health status
string health = tokens[5];
if (health == "0")
{
// Get date and time parts from the server response
string[] dateParts = tokens[1].Split('-');
string[] timeParts = tokens[2].Split(':');
// Create a DateTime instance
DateTime utcDateTime = new DateTime(
Convert.ToInt32(dateParts[0]) + 2000,
Convert.ToInt32(dateParts[1]), Convert.ToInt32(dateParts[2]),
Convert.ToInt32(timeParts[0]), Convert.ToInt32(timeParts[1]),
Convert.ToInt32(timeParts[2]));
// Convert received (UTC) DateTime value to the local timezone
//result = utcDateTime.ToLocalTime();
return utcDateTime;
// Response successfully received; exit the loop
}
}
}
}
catch
{
// Ignore exception and try the next server
}
}
return result;
}
var wc = GetFastestNISTDate();
var pattern = InstantPattern.CreateWithInvariantCulture("dd/MM/yyyy HH:mm:ss");
var parseResult = pattern.Parse(wc.ToString("dd/MM/yyyy HH:mm:ss", CultureInfo.InvariantCulture));
if (!parseResult.Success)
throw new InvalidDataException("...whatever...");
var instant = parseResult.Value;
var timeZone = DateTimeZoneProviders.Tzdb["Europe/London"];
var zonedDateTime = instant.InZone(timeZone);
var bclDateTime = zonedDateTime.ToDateTimeUnspecified();
If you can't trust the computer's clock, then you must get the time from another source, such as from a network server via NTP connection. Noda Time does not have this functionality.
You may be interested in this answer which describes how to query an NTP server in C#. Note that at the very end of the code in that answer it calls ToLocalTime. Instead, you would use Noda Time's Instant.FromDateTimeUtc method.

Converting between time zones with Noda Time

I'm currently trying to ensure that our legacy back-end can support resolving date times based on the user's current time zone (or, more specifically offset). Our servers are in eastern standard time, and most of our date times originate there. However, for users that are in other time zones, a conversion to their time zone (or, in this case, offset) is needed when retrieving those date times. Also, date times coming from the user will have to be converted to eastern standard time before persistence on the server. Given that the front end we are developing is web-based, I am able to retrieve the user's offset in minutes and pass that value into my service layer within the header. I looked at Noda Time and think it's a great API. It did force me to think about time in a more refined matter, but I am still not 100% sure that I've properly used it correctly. Here are the methods that I wrote for the conversions described above. I've tested them and they seem to work. Given the scenario above, does this look like a proper use of the library? Am I thinking about date times properly?
public static DateTime ConvertToUtcFromEasternTimeZone(DateTime easternDateTime)
{
NodaTime.DateTimeZone easternTimeZone = NodaTime.DateTimeZoneProviders.Tzdb.GetZoneOrNull("America/New_York");
ZoneLocalMappingResolver customResolver = Resolvers.CreateMappingResolver(Resolvers.ReturnLater, Resolvers.ReturnStartOfIntervalAfter);
var easternLocalDateTime = LocalDateTime.FromDateTime(easternDateTime);
var easternZonedDateTime = easternTimeZone.ResolveLocal(easternLocalDateTime, customResolver);
return easternZonedDateTime.ToDateTimeUtc();
}
public static DateTime ConvertToEasternTimeZoneFromUtc(DateTime utcDateTime)
{
NodaTime.DateTimeZone easternTimeZone = NodaTime.DateTimeZoneProviders.Tzdb.GetZoneOrNull("America/New_York");
NodaTime.DateTimeZone utcTimeZone = NodaTime.DateTimeZoneProviders.Tzdb.GetZoneOrNull("UTC");
ZoneLocalMappingResolver customResolver = Resolvers.CreateMappingResolver(Resolvers.ReturnLater, Resolvers.ReturnStartOfIntervalAfter);
var utcLocal = LocalDateTime.FromDateTime(utcDateTime);
var utcZonedDateTime = utcTimeZone.ResolveLocal(utcLocal, customResolver);
var easternZonedDateTime = utcZonedDateTime.ToInstant().InZone(easternTimeZone);
return easternZonedDateTime.ToDateTimeUnspecified();
}
public static DateTime ConvertToUtc(DateTime dateTime, int offsetInMinutes)
{
LocalDateTime localDateTime = LocalDateTime.FromDateTime(dateTime);
var convertedDateTime = localDateTime.PlusMinutes(offsetInMinutes).ToDateTimeUnspecified();
return convertedDateTime;
}
public static DateTime ConvertFromUtc(DateTime dateTime, int offsetInMinutes)
{
LocalDateTime localDateTime = LocalDateTime.FromDateTime(dateTime);
var convertedDateTime = localDateTime.PlusMinutes(-offsetInMinutes).ToDateTimeUnspecified();
return convertedDateTime;
}
The idea here is that time zone matters when I'm resolving between UTC time and the time zone in the database. When I'm resolving between the client time and UTC time then offset matters.
In the future, we can persist UTC time, and this will be easier. Currently, this solution is a stop gap.
The idea is that we are going to go from...
client -> UTC +/- offset -> UTC -> Eastern Time -> database
database -> Eastern Time -> UTC -> UTC +/- offset -> client
to eventually...
client -> UTC +/- offset -> UTC -> database
database -> UTC -> UTC +/- offset -> client
Your first method looks okay, although we don't know what customResolver is.
Your second method is a bit off. I'd suggest:
public static DateTime ConvertToEasternTimeZoneFromUtc(DateTime utcDateTime)
{
var easternTimeZone = DateTimeZoneProviders.Tzdb["America/New_York"];
return Instant.FromDateTimeUtc(utcDateTime)
.InZone(easternTimeZone)
.ToDateTimeUnspecified();
}
Note that you don't need to look up the Eastern time zone in every method call - just have:
private static readonly DateTimeZone EasternTimeZone =
DateTimeZoneProviders.Tzdb["America/New_York"];
... then use that everywhere.
Your third and fourth methods aren't what I'd think of as idiomatic - for the third method you should use:
public static DateTime ConvertToUtc(DateTime dateTime, int offsetInMinutes)
{
var offset = Offset.FromMinutes(offsetInMinutes);
var localDateTime = LocalDateTime.FromDateTime(dateTime);
return new OffsetDateTime(localDateTime, offset).ToInstant()
.ToDateTimeUtc();
}
The fourth method seems a bit trickier, as we don't provide everything we should in terms of conversions with OffsetDateTime. The code you've used is probably okay, but it would certainly be cleaner if you could use OffsetDateTime.
EDIT: I've now added a method to Instant to make the fourth method cleaner. It will be part of 1.2.0, and you can use:
public static DateTime ConvertFromUtc(DateTime dateTime, int offsetInMinutes)
{
var offset = Offset.FromMinutes(offsetInMinutes);
var instant = Instant.FromDateTimeUtc(dateTime);
return instant.WithOffset(offset)
.LocalDateTime
.ToDateTimeUnspecified();
}
I would like to add that the first method could be rewritten without customResolver.
using System;
using NodaTime;
namespace qwerty
{
class Program
{
static void Main(string[] args)
{
var convertedInUTC = ConvertToUtcFromCustomTimeZone("America/Chihuahua", DateTime.Now);
Console.WriteLine(convertedInUTC);
}
private static DateTime ConvertToUtcFromCustomTimeZone(string timezone, DateTime datetime)
{
DateTimeZone zone = DateTimeZoneProviders.Tzdb[timezone];
var localtime = LocalDateTime.FromDateTime(datetime);
var zonedtime = localtime.InZoneLeniently(zone);
return zonedtime.ToInstant().InZone(zone).ToDateTimeUtc();
}
}
}

Categories

Resources