Reputation: 331
I would like to convert specific date time value to UTC with NodaTime by giving country code.
For example country is Turkey, country code is TR and specific date time is "Feb 5, 2016 7:45 PM" it would be "Feb 5, 2016 5:45 PM" is it possible?
Also my windows location is not Turkey.
Thank you in advance?
Upvotes: 5
Views: 2925
Reputation: 2449
I was trying to add a comment to Jon's answer above.
Here's the F# equivalent to the code above using NodaTime 3.0.9 nuget package - notice that I am using yyyy instead of YYYY:
let text = "Feb 5, 2016 7:45 PM"
let zone = NodaTime.DateTimeZoneProviders.Tzdb.["Europe/Istanbul"]
let pattern = NodaTime.Text.LocalDateTimePattern.CreateWithInvariantCulture("MMM d, uuuu h:mm tt");
let local = pattern.Parse(text).Value;
let zoned = local.InZoneStrictly(zone);
let utc = zoned.WithZone(NodaTime.DateTimeZone.Utc);
System.Console.WriteLine(utc); // 2016-02-05T17:45:00 UTC (+00)
When I used YYYY I get the message NodaTime.Text.InvalidPatternException: The character Y is not a format specifier, and should be quoted to act as a literal.
You can also make the code above less 'letty' as follows
let local = ("Feb 5, 2016 7:45 PM" |> ("MMM d, uuuu h:mm tt" |> NodaTime.Text.LocalDateTimePattern.CreateWithInvariantCulture).Parse).Value;
let utc = NodaTime.DateTimeZone.Utc
|> (NodaTime.DateTimeZoneProviders.Tzdb.["Europe/Istanbul"] |> local.InZoneStrictly).WithZone
|> System.Console.WriteLine
Upvotes: 0
Reputation: 1500215
Well, you can't do it just with a country code - you need a time zone. In some countries there are multiple time zones.
Once you have a time zone as a DateTimeZone
(either via a BCL TimeZoneInfo
or from the TZDB time zone provider) you would:
LocalDateTime
from the value you've got, e.g. using LocalDateTimePattern
to parse textLocalDateTime.InZoneLeniently
(or similar - more about that in a moment) to get the ZonedDateTime
WithZone(DateTimeZone.Utc)
to convert it to a UTC-based ZonedDateTime
The part about InZoneLeniently
, InZoneStrictly
or InZone(DateTimeZone, ZoneLocalMappingResolver)
is because a local date and time might occur twice or not at all, around DST transitions. See the user guide for more details on that.
Sample code:
using System;
using NodaTime;
using NodaTime.Text;
class Test
{
static void Main()
{
var text = "Feb 5, 2016 7:45 PM";
var zone = DateTimeZoneProviders.Tzdb["Europe/Istanbul"];
var pattern = LocalDateTimePattern.CreateWithInvariantCulture("MMM d, uuuu h:mm tt");
var local = pattern.Parse(text).Value;
var zoned = local.InZoneStrictly(zone);
var utc = zoned.WithZone(DateTimeZone.Utc);
Console.WriteLine(utc); // 2016-02-05T17:45:00 UTC (+00)
}
}
Now, for finding the time zone from a country code, the TZDB (IANA) database comes with information about time zone locations, which is exposed in Noda Time. For example, if you have an ISO-3166 2-letter country code, you could use:
using NodaTime;
using NodaTime.TimeZones;
using System.Linq;
...
var code = "TR"; // Turkey
var zoneId = TzdbDateTimeZoneSource.Default.ZoneLocations
.Single(loc => loc.CountryCode == code)
.ZoneId;
var zone = DateTimeZoneProviders.Tzdb[zoneId];
The Single
call will fail if there's more than one zone with the given country code (or none).
If you're going to frequently look up the zones, you might want to build a dictionary:
var zonesByCountryCode = TzdbDateTimeZoneSource.Default
.ZoneLocations
.GroupBy(loc => loc.CountryCode)
.Where(g => g.Count() == 1) // Single-zone countries only
.ToDictionary(g => g.Key, g => g.First());
Upvotes: 4